浏览代码

Merge pull request #107 from mpsonntag/release0123

Merge of upstream 'release' into G-Node/gogs 'master'

LGTM
Achilleas Koutsou 4 年之前
父节点
当前提交
1619dc104e
共有 100 个文件被更改,包括 2767 次插入1956 次删除
  1. 0 7
      .codebeatignore
  2. 0 7
      .codebeatsettings
  3. 2 3
      .dockerignore
  4. 1 1
      .editorconfig
  5. 0 1
      .gitattributes
  6. 5 2
      .github/ISSUE_TEMPLATE/bug_report.md
  7. 52 0
      .github/workflows/codeql.yml
  8. 54 0
      .github/workflows/go.yml
  9. 9 6
      .github/workflows/lsif.yml
  10. 13 0
      .github/workflows/shell.yml
  11. 0 1
      .gitignore
  12. 0 20
      .travis.yml
  13. 66 2
      CHANGELOG.md
  14. 5 5
      Dockerfile
  15. 0 37
      Dockerfile.aarch64
  16. 0 46
      Dockerfile.aarch64hub
  17. 0 57
      Dockerfile.rpihub
  18. 9 16
      Makefile
  19. 1 1
      README_ZH.md
  20. 11 0
      SECURITY.md
  21. 8 1
      codecov.yml
  22. 27 6
      conf/app.ini
  23. 21 9
      conf/locale/locale_bg-BG.ini
  24. 50 38
      conf/locale/locale_cs-CZ.ini
  25. 160 148
      conf/locale/locale_de-DE.ini
  26. 20 8
      conf/locale/locale_en-GB.ini
  27. 21 9
      conf/locale/locale_en-US.ini
  28. 20 8
      conf/locale/locale_es-ES.ini
  29. 20 8
      conf/locale/locale_fa-IR.ini
  30. 23 11
      conf/locale/locale_fi-FI.ini
  31. 20 8
      conf/locale/locale_fr-FR.ini
  32. 20 8
      conf/locale/locale_gl-ES.ini
  33. 20 8
      conf/locale/locale_hu-HU.ini
  34. 20 8
      conf/locale/locale_id-ID.ini
  35. 20 8
      conf/locale/locale_it-IT.ini
  36. 62 50
      conf/locale/locale_ja-JP.ini
  37. 51 39
      conf/locale/locale_ko-KR.ini
  38. 20 8
      conf/locale/locale_lv-LV.ini
  39. 20 8
      conf/locale/locale_nl-NL.ini
  40. 49 37
      conf/locale/locale_pl-PL.ini
  41. 20 8
      conf/locale/locale_pt-BR.ini
  42. 50 38
      conf/locale/locale_pt-PT.ini
  43. 41 29
      conf/locale/locale_ru-RU.ini
  44. 20 8
      conf/locale/locale_sk-SK.ini
  45. 20 8
      conf/locale/locale_sr-SP.ini
  46. 20 8
      conf/locale/locale_sv-SE.ini
  47. 69 57
      conf/locale/locale_tr-TR.ini
  48. 20 8
      conf/locale/locale_uk-UA.ini
  49. 20 8
      conf/locale/locale_vi-VN.ini
  50. 168 155
      conf/locale/locale_zh-CN.ini
  51. 20 8
      conf/locale/locale_zh-HK.ini
  52. 21 9
      conf/locale/locale_zh-TW.ini
  53. 44 0
      docker/Dockerfile.aarch64
  54. 44 0
      docker/Dockerfile.rpi
  55. 40 2
      docker/README.md
  56. 0 3
      docker/aarch64/build.sh
  57. 二进制
      docker/aarch64/qemu-aarch64-static
  58. 二进制
      docker/aarch64/resin-xbuild
  59. 0 66
      docker/aarch64/resin-xbuild.go
  60. 0 3
      docker/armhf/build.sh
  61. 二进制
      docker/armhf/qemu-arm-static
  62. 二进制
      docker/armhf/resin-xbuild
  63. 0 66
      docker/armhf/resin-xbuild.go
  64. 0 32
      docker/build-go.sh
  65. 0 31
      docker/build.sh
  66. 0 2
      docker/finalize.sh
  67. 0 16
      docker/no-pic.patch
  68. 140 0
      docker/runtime/backup-init.sh
  69. 33 0
      docker/runtime/backup-job.sh
  70. 27 0
      docker/runtime/backup-rotator.sh
  71. 0 1
      docker/s6/gogs/run
  72. 2 13
      docker/s6/gogs/setup
  73. 8 3
      docker/start.sh
  74. 21 0
      docs/admin/lfs.md
  75. 2 2
      docs/dev/local_development.md
  76. 28 0
      docs/user/lfs.md
  77. 10 12
      go.mod
  78. 14 67
      go.sum
  79. 2 2
      gogs.go
  80. 34 0
      internal/app/api.go
  81. 95 0
      internal/app/api_test.go
  82. 33 0
      internal/app/metrics.go
  83. 31 31
      internal/assets/conf/conf_gen.go
  84. 24 25
      internal/assets/public/public_gen.go
  85. 17 17
      internal/assets/templates/templates_gen.go
  86. 13 16
      internal/auth/auth.go
  87. 5 5
      internal/auth/ldap/ldap.go
  88. 35 0
      internal/authutil/basic.go
  89. 72 0
      internal/authutil/basic_test.go
  90. 7 9
      internal/avatar/avatar_test.go
  91. 8 2
      internal/cmd/admin.go
  92. 40 14
      internal/cmd/backup.go
  93. 2 2
      internal/cmd/cmd.go
  94. 8 8
      internal/cmd/hook.go
  95. 6 6
      internal/cmd/import.go
  96. 12 8
      internal/cmd/restore.go
  97. 23 21
      internal/cmd/serv.go
  98. 485 479
      internal/cmd/web.go
  99. 13 4
      internal/conf/conf.go
  100. 0 4
      internal/conf/conf_test.go

+ 0 - 7
.codebeatignore

@@ -1,7 +0,0 @@
-conf/**
-docker/**
-modules/bindata/**
-packager/**
-public/**
-scripts/**
-templates/**

+ 0 - 7
.codebeatsettings

@@ -1,7 +0,0 @@
-{
-	"GOLANG": {
-		"TOTAL_LOC": [500, 999, 1999, 9999],
-		"TOO_MANY_FUNCTIONS": [50, 99, 199, 999],
-		"TOO_MANY_IVARS": [20, 50, 70, 99]
-	}
-}

+ 2 - 3
.dockerignore

@@ -1,5 +1,5 @@
-packager
-packager/**
+.packager
+.packager/**
 scripts
 scripts/**
 .github/
@@ -8,7 +8,6 @@ config.codekit
 .dockerignore
 *.yml
 *.md
-.bra.toml
 .editorconfig
 .gitignore
 Dockerfile*

+ 1 - 1
.editorconfig

@@ -16,7 +16,7 @@ indent_size = 4
 indent_style = tab
 indent_size = 2
 
-[*.{less,yml}]
+[*.{less, yml}]
 indent_style = space
 indent_size = 2
 

+ 0 - 1
.gitattributes

@@ -3,7 +3,6 @@ conf/license/* linguist-vendored
 public/assets/* linguist-vendored
 public/plugins/* linguist-vendored
 public/css/themes/* linguist-vendored
-public/css/github.min.css linguist-vendored
 public/css/semantic-2.4.2.min.css linguist-vendored
 public/js/libs/* linguist-vendored
 public/js/jquery-3.4.1.min.js linguist-vendored

+ 5 - 2
.github/ISSUE_TEMPLATE/bug_report.md

@@ -22,8 +22,11 @@ The issue will be closed without any explanation if it does not satisfy any of f
 **Describe the bug**
 <!-- A clear and concise description of what the bug is -->
 
-**Gogs version or commit**
-<!-- The version number or the commit SHA of the Gogs instance you use -->
+**Gogs version and commit**
+<!-- 
+  The version number or the commit SHA of the Gogs instance you use.
+  You can find these information in the admin dashboard ("/admin").
+-->
 
 **Git version**
 

+ 52 - 0
.github/workflows/codeql.yml

@@ -0,0 +1,52 @@
+name: "Code scanning - action"
+
+on:
+  push:
+    branches: [master]
+  schedule:
+    - cron: '0 19 * * 0'
+
+jobs:
+  CodeQL-Build:
+
+    # CodeQL runs on ubuntu-latest and windows-latest
+    runs-on: ubuntu-latest
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout@v2
+      with:
+        # We must fetch at least the immediate parents so that if this is
+        # a pull request then we can checkout the head.
+        fetch-depth: 2
+
+    # If this run was triggered by a pull request event, then checkout
+    # the head of the pull request instead of the merge commit.
+    - run: git checkout HEAD^2
+      if: ${{ github.event_name == 'pull_request' }}
+      
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init@v1
+      # Override language selection by uncommenting this and choosing your languages
+      # with:
+      #   languages: go, javascript, csharp, python, cpp, java
+
+    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+    # If this step fails, then you should remove it and run the build manually (see below)
+    - name: Autobuild
+      uses: github/codeql-action/autobuild@v1
+
+    # ℹ️ Command-line programs to run using the OS shell.
+    # 📚 https://git.io/JvXDl
+
+    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+    #    and modify them (or add more) to build your code if your project
+    #    uses a compiled language
+
+    #- run: |
+    #   make bootstrap
+    #   make release
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze@v1

+ 54 - 0
.github/workflows/go.yml

@@ -0,0 +1,54 @@
+name: Go
+on:
+  push:
+    branches:
+      - master
+      - main
+      - 'release/**'
+    paths:
+      - '**.go'
+  pull_request:
+    paths:
+      - '**.go'
+env:
+  GOPROXY: "https://proxy.golang.org"
+
+jobs:
+  lint:
+    name: Lint
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v2
+      - name: Run golangci-lint
+        uses: actions-contrib/golangci-lint@v1
+        with:
+          args: 'run --timeout=30m'
+
+  test:
+    name: Test
+    strategy:
+      matrix:
+        go-version: [1.14.x, 1.15.x]
+        platform: [ubuntu-latest, macos-latest, windows-latest]
+    runs-on: ${{ matrix.platform }}
+    steps:
+      - name: Install Go
+        uses: actions/setup-go@v1
+        with:
+          go-version: ${{ matrix.go-version }}
+      - name: Checkout code
+        uses: actions/checkout@v2
+      - name: Run unit tests
+        run: go test -v -race -coverprofile=coverage -covermode=atomic ./...
+      - name: Upload coverage report to Codecov
+        uses: codecov/codecov-action@v1.0.6
+        with:
+          file: ./coverage
+          flags: unittests
+      - name: Cache downloaded modules
+        uses: actions/cache@v1
+        with:
+          path: ~/go/pkg/mod
+          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
+          restore-keys: |
+            ${{ runner.os }}-go-

+ 9 - 6
.github/workflows/lsif.yml

@@ -1,17 +1,20 @@
 name: LSIF
 on: [push]
 jobs:
-  build:
+  lsif-go:
+    if: github.repository == 'gogs/gogs'
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v1
       - name: Generate LSIF data
         uses: sourcegraph/lsif-go-action@master
+      - name: Upload LSIF data to sourcegraph.com
+        continue-on-error: true
+        uses: docker://sourcegraph/src-cli:latest
         with:
-          verbose: 'true'
-      - name: Upload LSIF data
-        uses: sourcegraph/lsif-upload-action@master
+          args: lsif upload -github-token=${{ secrets.GITHUB_TOKEN }}
+      - name: Upload LSIF data to sourcegraph.unknwon.cn
         continue-on-error: true
+        uses: docker://sourcegraph/src-cli:latest
         with:
-          endpoint: https://sourcegraph.com
-          github_token: ${{ secrets.GITHUB_TOKEN }}
+          args: -endpoint=https://sourcegraph.unknwon.cn lsif upload -github-token=${{ secrets.GITHUB_TOKEN }}

+ 13 - 0
.github/workflows/shell.yml

@@ -0,0 +1,13 @@
+name: Shell
+on:
+  push:
+    branches: [master]
+  pull_request:
+jobs:
+  shellcheck:
+    name: Shellcheck
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@master
+      - name: Run ShellCheck
+        uses: ludeeus/action-shellcheck@master

+ 0 - 1
.gitignore

@@ -4,7 +4,6 @@
 log/
 custom/
 data/
-.vendor/
 .idea/
 *.iml
 public/img/avatar/

+ 0 - 20
.travis.yml

@@ -1,20 +0,0 @@
-os: linux
-language: go
-go:
-  - 1.13.x
-  - 1.14.x
-go_import_path: gogs.io/gogs
-
-env:
-  - GO111MODULE=on
-
-before_install:
-  - sudo apt-get update -qq
-  - sudo apt-get install -y libpam-dev
-
-script:
-  - go build -v -tags "pam"
-  - go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
-
-after_success:
-  - bash <(curl -s https://codecov.io/bash)

+ 66 - 2
CHANGELOG.md

@@ -2,19 +2,69 @@
 
 All notable changes to Gogs are documented in this file.
 
-## 0.12.0+dev (`master`)
+## 0.13.0+dev (`main`)
 
 ### Added
 
+- An unlisted option is added when create or migrate a repository. Unlisted repositories are public but not being listed for users without direct access in the UI. [#5733](https://github.com/gogs/gogs/issues/5733)
+- Add new configuration option `[git.timeout] DIFF` for customizing operation timeout of `git diff`. [#6315](https://github.com/gogs/gogs/issues/6315)
+
+### Changed
+
+- The default branch has been changed to `main`. [#6285](https://github.com/gogs/gogs/pull/6285)
+- MSSQL as database backend is deprecated, installation page no longer shows it as an option. Existing installations and manually craft configuration file continue to work. [#6295](https://github.com/gogs/gogs/pull/6295)
+- Use [Task](https://github.com/go-task/task) as the default build tool for development. [#6297](https://github.com/gogs/gogs/pull/6297)
+
+### Fixed
+
+- Add `X-Frame-Options` header to prevent Clickjacking. [#6409](https://github.com/gogs/gogs/issues/6409) 
+- [Security] Potential SSRF attack by CRLF injection via repository migration. [#6413](https://github.com/gogs/gogs/issues/6413)
+
+
+### Removed
+
+- ⚠️ Migrations before 0.12 are removed, installations not on 0.12 should upgrade to it to run the migrations and then upgrade to 0.13.
+- Configuration section `[mailer]` is no longer used.
+- Configuration section `[service]` is no longer used.
+- Configuration option `APP_NAME` is no longer used.
+- Configuration option `[security] REVERSE_PROXY_AUTHENTICATION_USER` is no longer used.
+- Configuration option `[database] PASSWD` is no longer used.
+- Configuration option `[auth] ACTIVE_CODE_LIVE_MINUTES` is no longer used.
+- Configuration option `[auth] RESET_PASSWD_CODE_LIVE_MINUTES` is no longer used.
+- Configuration option `[auth] ENABLE_CAPTCHA` is no longer used.
+- Configuration option `[auth] ENABLE_NOTIFY_MAIL` is no longer used.
+- Configuration option `[auth] REGISTER_EMAIL_CONFIRM` is no longer used.
+- Configuration option `[session] GC_INTERVAL_TIME` is no longer used.
+- Configuration option `[session] SESSION_LIFE_TIME` is no longer used.
+- Configuration option `[server] ROOT_URL` is no longer used.
+- Configuration option `[server] LANDING_PAGE` is no longer used.
+- Configuration option `[database] DB_TYPE` is no longer used.
+- Configuration option `[database] PASSWD` is no longer used.
+
+## 0.12.1
+
+### Fixed
+
+- The `updated_at` field is now correctly updated when updates an issue. [#6209](https://github.com/gogs/gogs/issues/6209)
+- Fixed a regression which created `login_source.cfg` column to have `VARCHAR(255)` instead of `TEXT` in MySQL. [#6280](https://github.com/gogs/gogs/issues/6280)
+
+## 0.12.0
+
+### Added
+
+- Support for Git LFS, you can read documentation for both [user](https://github.com/gogs/gogs/blob/master/docs/user/lfs.md) and [admin](https://github.com/gogs/gogs/blob/master/docs/admin/lfs.md). [#1322](https://github.com/gogs/gogs/issues/1322)
 - Allow admin to remove observers from the repository. [#5803](https://github.com/gogs/gogs/pull/5803)
 - Use `Last-Modified` HTTP header for raw files. [#5811](https://github.com/gogs/gogs/issues/5811)
 - Support syntax highlighting for SAS code files (i.e. `.r`, `.sas`, `.tex`, `.yaml`). [#5856](https://github.com/gogs/gogs/pull/5856)
 - Able to fill in pull request title with a template. [#5901](https://github.com/gogs/gogs/pull/5901)
 - Able to override static files under `public/` directory, please refer to [documentation](https://gogs.io/docs/features/custom_template) for usage. [#5920](https://github.com/gogs/gogs/pull/5920)
+- New API endpoint `GET /admin/teams/:teamid/members` to list members of a team. [#5877](https://github.com/gogs/gogs/issues/5877)
+- Support backup with retention policy for Docker deployments. [#6140](https://github.com/gogs/gogs/pull/6140)
 
 ### Changed
 
-- The required Go version to compile source code changed to 1.13.
+- The organization profile page has changed to display at most 12 members. [#5506](https://github.com/gogs/gogs/issues/5506)
+- The required Go version to compile source code changed to 1.14.
 - All assets are now embedded into binary and served from memory by default. Set `[server] LOAD_ASSETS_FROM_DISK = true` to load them from disk. [#5920](https://github.com/gogs/gogs/pull/5920)
 - Application and Go versions are removed from page footer and only show in the admin dashboard.
 - Build tag for running as Windows Service has been changed from `miniwinsvc` to `minwinsvc`.
@@ -32,18 +82,31 @@ All notable changes to Gogs are documented in this file.
 - Configuration option `[auth] ENABLE_NOTIFY_MAIL` is deprecated and will end support in 0.13.0, please start using `[user] ENABLE_EMAIL_NOTIFICATION`.
 - Configuration option `[session] GC_INTERVAL_TIME` is deprecated and will end support in 0.13.0, please start using `[session] GC_INTERVAL`.
 - Configuration option `[session] SESSION_LIFE_TIME` is deprecated and will end support in 0.13.0, please start using `[session] MAX_LIFE_TIME`.
+- The name `-` is reserved and cannot be used for users or organizations.
 
 ### Fixed
 
 - [Security] Potential open redirection with i18n.
 - [Security] Potential ability to delete files outside a repository.
+- [Security] Potential ability to set primary email on others' behalf from their verified emails.
+- [Security] Potential XSS attack via `.ipynb`. [#5170](https://github.com/gogs/gogs/issues/5170)
+- [Security] Potential SSRF attack via webhooks. [#5366](https://github.com/gogs/gogs/issues/5366)
+- [Security] Potential CSRF attack in admin panel. [#5367](https://github.com/gogs/gogs/issues/5367)
+- [Security] Potential stored XSS attack in some browsers. [#5397](https://github.com/gogs/gogs/issues/5397)
 - [Security] Potential RCE on mirror repositories. [#5767](https://github.com/gogs/gogs/issues/5767)
 - [Security] Potential XSS attack with raw markdown API. [#5907](https://github.com/gogs/gogs/pull/5907)
+- File both modified and renamed within a commit treated as separate files. [#5056](https://github.com/gogs/gogs/issues/5056)
+- Unable to restore the database backup to MySQL 8.0 with syntax error. [#5602](https://github.com/gogs/gogs/issues/5602)
 - Open/close milestone redirects to a 404 page. [#5677](https://github.com/gogs/gogs/issues/5677)
 - Disallow multiple tokens with same name. [#5587](https://github.com/gogs/gogs/issues/5587) [#5820](https://github.com/gogs/gogs/pull/5820)
 - Enable Federated Avatar Lookup could cause server to crash. [#5848](https://github.com/gogs/gogs/issues/5848)
 - Private repositories are hidden in the organization's view. [#5869](https://github.com/gogs/gogs/issues/5869)
+- Users have access to base repository cannot view commits in forks. [#5878](https://github.com/gogs/gogs/issues/5878)
 - Server error when changing email address in user settings page. [#5899](https://github.com/gogs/gogs/issues/5899)
+- Fall back to use RFC 3339 as time layout when misconfigured. [#6098](https://github.com/gogs/gogs/issues/6098)
+- Unable to update team with server error. [#6185](https://github.com/gogs/gogs/issues/6185)
+- Webhooks are not fired after push when `[service] REQUIRE_SIGNIN_VIEW = true`.
+- Files with identical content are randomly displayed one of them.
 
 ### Removed
 
@@ -54,6 +117,7 @@ All notable changes to Gogs are documented in this file.
 - Configuration option `[session] ENABLE_SET_COOKIE`
 - Configuration option `[release.attachment] PATH`
 - Configuration option `[webhook] QUEUE_LENGTH`
+- Build tag `sqlite`, which means CGO is now required.
 
 ---
 

+ 5 - 5
Dockerfile

@@ -1,4 +1,4 @@
-FROM golang:alpine3.10 AS binarybuilder
+FROM golang:alpine3.11 AS binarybuilder
 RUN apk --no-cache --no-progress add --virtual \
   build-deps \
   build-base \
@@ -7,10 +7,10 @@ RUN apk --no-cache --no-progress add --virtual \
 
 WORKDIR /go/src/github.com/G-Node/gogs
 COPY . .
-RUN make build-no-gen TAGS="sqlite cert pam"
+RUN make build-no-gen TAGS="cert pam"
 
-FROM alpine:3.10
-ADD https://github.com/tianon/gosu/releases/download/1.10/gosu-amd64 /usr/sbin/gosu
+FROM alpine:3.11
+ADD https://github.com/tianon/gosu/releases/download/1.11/gosu-amd64 /usr/sbin/gosu
 RUN chmod +x /usr/sbin/gosu \
   && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
   && apk --no-cache --no-progress add \
@@ -49,7 +49,7 @@ COPY --from=binarybuilder /go/src/github.com/G-Node/gogs/gogs .
 RUN ./docker/finalize.sh
 
 # Configure Docker Container
-VOLUME ["/data"]
+VOLUME ["/data", "/backup"]
 EXPOSE 22 3000
 ENTRYPOINT ["/app/gogs/docker/start.sh"]
 CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

+ 0 - 37
Dockerfile.aarch64

@@ -1,37 +0,0 @@
-FROM arm64v8/alpine:latest
-
-# Install system utils & Gogs runtime dependencies
-ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-arm64 /usr/sbin/gosu
-RUN chmod +x /usr/sbin/gosu \
-  && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
-  && apk --no-cache --no-progress add \
-    bash \
-    ca-certificates \
-    curl \
-    git \
-    linux-pam \
-    openssh \
-    s6 \
-    shadow \
-    socat \
-    tzdata \
-    rsync
-
-ENV GOGS_CUSTOM /data/gogs
-
-# Configure LibC Name Service
-COPY docker/nsswitch.conf /etc/nsswitch.conf
-COPY docker /app/gogs/docker
-
-WORKDIR /app/gogs/build
-COPY . .
-
-RUN    ./docker/build-go.sh \
-    && ./docker/build.sh \
-    && ./docker/finalize.sh
-
-# Configure Docker Container
-VOLUME ["/data"]
-EXPOSE 22 3000
-ENTRYPOINT ["/app/gogs/docker/start.sh"]
-CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

+ 0 - 46
Dockerfile.aarch64hub

@@ -1,46 +0,0 @@
-FROM arm64v8/alpine:latest
-
-ENV GOGS_CUSTOM /data/gogs
-ENV QEMU_EXECVE 1
-
-# For cross compile on dockerhub
-################################
-
-COPY ./docker/aarch64/qemu-aarch64-static /usr/bin/
-COPY ./docker/aarch64/resin-xbuild /usr/bin/
-
-RUN [ "/usr/bin/qemu-aarch64-static", "/bin/sh", "-c", "ln -s resin-xbuild /usr/bin/cross-build-start; ln -s resin-xbuild /usr/bin/cross-build-end; ln /bin/sh /bin/sh.real" ]
-
-RUN [ "cross-build-start" ]
-
-# Prepare the container
-#######################
-
-# Install system utils & Gogs runtime dependencies
-ADD https://github.com/tianon/gosu/releases/download/1.10/gosu-arm64 /usr/sbin/gosu
-RUN chmod +x /usr/sbin/gosu \
- && apk --no-cache --no-progress add ca-certificates bash git linux-pam s6 curl openssh shadow socat tzdata go=1.10.1-r0
-
-
-
-COPY docker /app/gogs/docker
-WORKDIR /app/gogs/build
-COPY . .
-
-RUN    ./docker/build.sh \
-    && ./docker/finalize.sh
-
-# Configure LibC Name Service
-COPY docker/nsswitch.conf /etc/nsswitch.conf
-
-# For cross compile on dockerhub
-################################
-
-RUN [ "cross-build-end" ]
-
-# Configure Docker Container
-############################
-VOLUME ["/data"]
-EXPOSE 22 3000
-ENTRYPOINT ["/app/gogs/docker/start.sh"]
-CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

+ 0 - 57
Dockerfile.rpihub

@@ -1,57 +0,0 @@
-FROM arm32v7/alpine:latest
-
-ENV GOGS_CUSTOM /data/gogs
-ENV QEMU_EXECVE 1
-
-# For cross compile on dockerhub
-################################
-
-COPY ./docker/armhf/qemu-arm-static /usr/bin/
-COPY ./docker/armhf/resin-xbuild /usr/bin/
-
-RUN [ "/usr/bin/qemu-arm-static", "/bin/sh", "-c", "ln -s resin-xbuild /usr/bin/cross-build-start; ln -s resin-xbuild /usr/bin/cross-build-end; ln /bin/sh /bin/sh.real" ]
-
-RUN [ "cross-build-start" ]
-
-# Prepare the container
-#######################
-
-# Install system utils & Gogs runtime dependencies
-ADD https://github.com/tianon/gosu/releases/download/1.9/gosu-armhf /usr/sbin/gosu
-RUN chmod +x /usr/sbin/gosu \
-  && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
-  && apk --no-cache --no-progress add \
-    bash \
-    ca-certificates \
-    curl \
-    git \
-    linux-pam \
-    openssh \
-    s6 \
-    shadow \
-    socat \
-    tzdata \
-    rsync
-
-# Configure LibC Name Service
-COPY docker/nsswitch.conf /etc/nsswitch.conf
-COPY docker /app/gogs/docker
-
-WORKDIR /app/gogs/build
-COPY . .
-
-RUN    ./docker/build-go.sh \
-    && ./docker/build.sh \
-    && ./docker/finalize.sh
-
-# For cross compile on dockerhub
-################################
-
-RUN [ "cross-build-end" ]
-
-# Configure Docker Container
-############################
-VOLUME ["/data"]
-EXPOSE 22 3000
-ENTRYPOINT ["/app/gogs/docker/start.sh"]
-CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

+ 9 - 16
Makefile

@@ -6,9 +6,7 @@ TEMPLATES_FILES := $(shell find templates | sed 's/ /\\ /g')
 PUBLIC_FILES := $(shell find public | sed 's/ /\\ /g')
 LESS_FILES := $(wildcard public/less/*.less)
 ASSETS_GENERATED := internal/assets/conf/conf_gen.go internal/assets/templates/templates_gen.go internal/assets/public/public_gen.go
-GENERATED := $(ASSETS_GENERATED) public/css/gogs.css
-
-OS := $(shell uname)
+GENERATED := $(ASSETS_GENERATED) public/css/gogs.min.css
 
 TAGS = ""
 BUILD_FLAGS = "-v"
@@ -16,9 +14,8 @@ BUILD_FLAGS = "-v"
 RELEASE_ROOT = "release"
 RELEASE_GOGS = "release/gogs"
 NOW = $(shell date -u '+%Y%m%d%I%M%S')
-GOVET = go tool vet -composites=false -methods=false -structtags=false
 
-.PHONY: build pack release generate clean
+.PHONY: check dist build build-no-gen pack release generate less clean test fixme todo legacy
 
 .IGNORE: public/css/gogs.css
 
@@ -31,10 +28,6 @@ dist: release
 web: build
 	./gogs web
 
-govet:
-	$(GOVET) gogs.go
-	$(GOVET) models pkg routes
-
 build: $(GENERATED)
 	go build $(BUILD_FLAGS) -ldflags '$(LDFLAGS)' -tags '$(TAGS)' -trimpath -o gogs
 
@@ -49,7 +42,7 @@ pack:
 
 release: build pack
 
-generate: $(ASSETS_GENERATED)
+generate: clean $(ASSETS_GENERATED)
 
 internal/assets/conf/conf_gen.go: $(CONF_FILES)
 	-rm -f $@
@@ -66,12 +59,12 @@ internal/assets/public/public_gen.go: $(PUBLIC_FILES)
 	go generate internal/assets/public/public.go
 	gofmt -s -w $@
 
-less: public/css/gogs.css
+less: clean public/css/gogs.min.css
 
-public/css/gogs.css: $(LESS_FILES)
-	@type lessc >/dev/null 2>&1 && lessc --source-map "public/less/gogs.less" $@ || echo "lessc command not found or failed"
+public/css/gogs.min.css: $(LESS_FILES)
+	@type lessc >/dev/null 2>&1 && lessc --clean-css --source-map "public/less/gogs.less" $@ || echo "lessc command not found or failed"
 
-clean-mac:
+clean:
 	find . -name "*.DS_Store" -type f -delete
 
 test:
@@ -83,6 +76,6 @@ fixme:
 todo:
 	grep -rnw "TODO" internal
 
-# Legacy code should be remove by the time of release
+# Legacy code should be removed by the time of release
 legacy:
-	grep -rnw "\(LEGACY\|DEPRECATED\)" internal
+	grep -rnw "\(LEGACY\|Deprecated\)" internal

+ 1 - 1
README_ZH.md

@@ -22,7 +22,7 @@ Gogs(`/gɑgz/`)项目旨在打造一个以最简便的方式搭建简单、
 - 通过 SSH、HTTP 和 HTTPS 协议操作仓库
 - 管理用户、组织和仓库
 - 仓库和组织级 Webhook,包括 Slack、Discord 和钉钉
-- 仓库 Git 钩子和部署密钥
+- 仓库 Git 钩子、部署密钥和 Git LFS
 - 仓库工单(Issue)、合并请求(Pull Request)、Wiki、保护分支和多人协作
 - 从其它代码平台迁移和镜像仓库以及 Wiki
 - 在线编辑仓库文件和 Wiki

+ 11 - 0
SECURITY.md

@@ -0,0 +1,11 @@
+# Security policy
+
+## Supported versions
+
+Only lastest two minor version releases are supported for patching security fixes.
+
+## Reporting a vulnerability
+
+Please send report privately to [security@gogs.io](mailto:security@gogs.io), and include how would you like to be credited.
+
+Thank you!

+ 8 - 1
codecov.yml

@@ -1,2 +1,9 @@
+coverage:
+  range: "60...95"
+  status:
+    project:
+      default:
+        threshold: 1%
+
 comment:
-  layout: 'diff, files'
+  layout: 'diff'

+ 27 - 6
conf/app.ini

@@ -121,7 +121,7 @@ AUTO_INIT = false
 
 ; The maximum number of goroutines that can be run at the same time for a single
 ; fetch request. Usually, the value depend of how many CPU (cores) you have. If
-; the value is non-positive, it matchs the number of CPUs available to the application.
+; the value is non-positive, it matches the number of CPUs available to the application.
 COMMITS_FETCH_CONCURRENCY = 0
 
 [repository.editor]
@@ -158,6 +158,10 @@ PASSWORD =
 SSL_MODE = disable
 ; For "sqlite3" only, make sure to use absolute path.
 PATH = data/gogs.db
+; The maximum open connections of the pool.
+MAX_OPEN_CONNS = 30
+; The maximum idle connections of the pool.
+MAX_IDLE_CONNS = 30
 
 [security]
 ; Whether to show the install page, set this to "true" to bypass it.
@@ -167,9 +171,9 @@ INSTALL_LOCK = false
 SECRET_KEY = !#@FDEWREWR&*(
 ; The days remembered for auto-login.
 LOGIN_REMEMBER_DAYS = 7
-; The cookie name to stoed auto-login information.
+; The cookie name to store auto-login information.
 COOKIE_REMEMBER_NAME = gogs_incredible
-; The cookie name to stored logged in username.
+; The cookie name to store logged in username.
 COOKIE_USERNAME = gogs_awesome
 ; Whether to set secure cookie.
 COOKIE_SECURE = false
@@ -271,6 +275,12 @@ HOST =
 ; The value for "Access-Control-Allow-Origin" header, default is not to present.
 ACCESS_CONTROL_ALLOW_ORIGIN =
 
+[lfs]
+; The storage backend for uploading new objects.
+STORAGE = local
+; The root path to store LFS objects on local file system.
+OBJECTS_PATH = data/lfs-objects
+
 [attachment]
 ; Whether to enabled upload attachments in general.
 ENABLED = true
@@ -311,7 +321,7 @@ GRAVATAR_SOURCE = gravatar
 DISABLE_GRAVATAR = false
 ; Whether to enable federated avatar lookup uses DNS to discover avatar associated
 ; with emails, see https://www.libravatar.org for details.
-; This value will be forced to be false in offline mode or when Gravatar is disbaled.
+; This value will be forced to be false in offline mode or when Gravatar is disabled.
 ENABLE_FEDERATED_AVATAR = false
 
 [markdown]
@@ -403,14 +413,24 @@ MAX_SIZE = 100
 ; Maximum days to keep logger files
 MAX_DAYS = 3
 
+[log.gorm]
+; Whether to enable file rotation.
+ROTATE = true
+; Whether to rotate file every day.
+ROTATE_DAILY = true
+; The maximum file size in MB before next rotate.
+MAX_SIZE = 100
+; The maximum days to keep files.
+MAX_DAYS = 3
+
 [cron]
 ; Enable running cron tasks periodically.
 ENABLED = true
 ; Run cron tasks when Gogs starts.
 RUN_AT_START = false
 
-; Update mirrors
 [cron.update_mirrors]
+; Defines how often the mirror syncer checks if any mirror needs to be synchronized (based on the mirror update interval).
 SCHEDULE = @every 10m
 
 ; Repository health check
@@ -455,7 +475,8 @@ PULL = 300
 GC = 60
 
 [mirror]
-; The default interval in hours for fetching updates.
+; Defines the default interval (in hours) until the next sync for a mirror (after a successful mirror sync).
+; It can be overridden individually for each mirror repository in the settings.
 DEFAULT_INTERVAL = 8
 
 [api]

+ 21 - 9
conf/locale/locale_bg-BG.ini

@@ -43,6 +43,10 @@ issues=Задачи
 
 cancel=Отказ
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Инсталация
 title=Стъпки за инсталиране при първоначално стартиране
@@ -249,7 +253,7 @@ org_still_own_repo=Тази организация все още притежа
 target_branch_not_exist=Целевият клон не съществува.
 
 [user]
-change_avatar=Проми своя аватар
+change_avatar=Промени своя аватар
 join_on=Регистриран
 repositories=Хранилища
 activity=Публична дейност
@@ -259,8 +263,7 @@ following=Следване
 follow=Следване
 unfollow=Не следвай
 
-form.name_reserved=Потребителското име '%s' е запазено.
-form.name_pattern_not_allowed=Потребителското име '%s' не е допустимо.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Профил
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=Притежателят е достигнал настроения лимит от %d брой хранилища.
-form.name_reserved=Името на хранилището '%s' е запазено.
-form.name_pattern_not_allowed=Име на хранилището от вида '%s' не е позволено.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Изисква потребител и парола
 migrate_type=Тип мигриране
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Този потребител няма да
 settings.remove_collaborator_success=Сътрудникът е премахнат.
 settings.search_user_placeholder=Име на потребител...
 settings.org_not_allowed_to_be_collaborator=Невъзможно добавяне на организация като сътрудник.
-settings.add_webhook=Добави уеб-кука
 settings.hooks_desc=Уеб-куките много приличат на обикновен HTTP POST тригер. Когато нещо се случи в Gogs, ние ще изпратим уведомление до сървъра, който посочите. Научете повече в <a target="_blank" href="%s">Ръководство за уеб-куки</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Добави уеб-кука
 settings.webhook_deletion=Изтрий уеб-кука
 settings.webhook_deletion_desc=При изтриване на тази уеб-кука ще се премахне информацията за нея и цялата хронология на нейното изпращане. Желаете ли да продължите?
 settings.webhook_deletion_success=Уеб-куката е изтрита успешно!
@@ -801,6 +805,8 @@ settings.webhook.response=Отговор
 settings.webhook.headers=Заглавки
 settings.webhook.payload=Съдържание
 settings.webhook.body=Тяло
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git куките се изпълняват от Git. Вие може да промените файловете с поддържаните куки в списъка по-долу, за да изпълните външни операции.
 settings.githook_edit_desc=Ако куката е неактивна, ще бъде представено примерно съдържание. Ако оставите съдържанието празно, то тази кука ще бъде изключена.
 settings.githook_name=Име на куката
@@ -927,9 +933,8 @@ team_name_helper=Ще използвате това име при спомена
 team_desc_helper=Каква е целта на този екип?
 team_permission_desc=Какво ниво на достъп трябва да има този екип?
 
-form.name_reserved=Името на организацията '%s' е запазено.
-form.name_pattern_not_allowed=Име на организацията от вида '%s' не е разрешено.
-form.team_name_reserved=Име на екип "%s" е запазено.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Настройки
 settings.options=Опции
@@ -1013,6 +1018,7 @@ dashboard.system_status=Наблюдение на системния стату
 dashboard.statistic_info=Gogs базата данни има <b>%d</b> потребители, <b>%d</b> организации, <b>%d</b> публични ключове, <b>%d</b> хранилища, <b>%d</b> наблюдавания, <b>%d</b> харесвания, <b>%d</b> действия, <b>%d</b> достъпи, <b>%d</b> задачи, <b>%d</b> коментари, <b>%d</b> социални регистрации, <b>%d</b> последователи, <b>%d</b> огледала, <b>%d</b> версии, <b>%d</b> начини на удостоверяване, <b>%d</b> уеб-куки, <b>%d</b> етапи, <b>%d</b> етикети, <b>%d</b> задачи на куки, <b>%d</b> екипи, <b>%d</b> задачи при актуализация, <b>%d</b> прикачени файлове.
 dashboard.operation_name=Име на операцията
 dashboard.operation_switch=Превключи
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Изпълни
 dashboard.clean_unbind_oauth=Почисти несвързани OAuthes
 dashboard.clean_unbind_oauth_success=Всички несвързани OAuthes са изтрити успешно.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Конфигурация на журнал
 config.log_file_root_path=Път към журнал
 config.log_mode=Режим

+ 50 - 38
conf/locale/locale_cs-CZ.ini

@@ -43,6 +43,10 @@ issues=Úkoly
 
 cancel=Zrušit
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalace
 title=Kroky instalace pro první spuštění
@@ -121,7 +125,7 @@ run_user_not_match=Uživatel pro spuštění není aktuální uživatel: %s -> %
 smtp_host_missing_port=V adrese SMTP serveru chybí číslo portu.
 invalid_smtp_from=Hodnota položky SMTP Od: není zadána správně: %v
 save_config_failed=Uložení konfigurace se nezdařilo: %v
-init_failed=Failed to initialize application: %v
+init_failed=Nepodařilo se inicializovat aplikaci: %v
 invalid_admin_setting=Nastavení účtu správce není správné: %v
 install_success=Vítejte! Jsme rádi, že jste si vybrali GIN. Bavte se a opatrujte se.
 invalid_log_root_path=Kořenový adresář souborů systémových záznamů není správný: %v
@@ -259,8 +263,7 @@ following=Sledovaní
 follow=Sledovat
 unfollow=Přestat sledovat
 
-form.name_reserved=Uživatelské jméno '%s' je rezervováno.
-form.name_pattern_not_allowed=Vzor uživatelského jména '%s' není povolen.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Popis repozitáře. Maximální délka 512 znaků.
 repo_description_length=Dostupné znaky
 
 form.reach_limit_of_creation=Vlastník dosáhl maximálního počtu %d vytvořených repositořů.
-form.name_reserved=Název repositáře '%s' je rezervován.
-form.name_pattern_not_allowed=Vzor názvu repositáře '%s' není povolen.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Ověření je vyžadováno
 migrate_type=Typ přenesení
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Tento uživatel po tom, co bude smazán, ji
 settings.remove_collaborator_success=Spolupracovník byl smazán.
 settings.search_user_placeholder=Hledat uživatele...
 settings.org_not_allowed_to_be_collaborator=Není dovoleno přidat organizaci jako spolupracovníka.
+settings.hooks_desc=Webové háčky jsou podobné základním spouštím HTTP POST událostí. Kdykoliv se něco stane v Gogs, bude postaráno o oznámení specifikovanému cílovému serveru. Více se o daném dozvíte v <a target="_blank" href="%s">příručce webových háčků</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Přidat webový háček
-settings.hooks_desc=Webové háčky jsou podobné základním spouštím HTTP POST událostí. Kdykoliv se něco stane v GIN, bude postaráno o oznámení specifikovanému cílovému serveru. Více se o daném dozvíte v <a target="_blank" href="%s">příručce webových háčků</a>.
 settings.webhook_deletion=Smazat webový háček
 settings.webhook_deletion_desc=Smazáním tohoto webového háčku dojte také ke smazání veškerých informací o něm a také historie volání. Chcete pokračovat?
 settings.webhook_deletion_success=Webový háček byl smazán!
@@ -801,6 +805,8 @@ settings.webhook.response=Odpověď
 settings.webhook.headers=Hlavičky
 settings.webhook.payload=Datová část
 settings.webhook.body=Tělo zprávy
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Jelikož háčky Gitu jsou spravovány Gitem samotným, můžete v seznamu níže upravit soubory podporovaných háčku k provádění uživatelských operací.
 settings.githook_edit_desc=Je-li háček neaktivní, bude zobrazen vzorový obsah. Nebude-li zadán žádný obsah, háček bude vypnut.
 settings.githook_name=Název háčku
@@ -927,9 +933,8 @@ team_name_helper=Tento název budete používat při zmiňovaní týmu v konverz
 team_desc_helper=Popište prosím tento tým
 team_permission_desc=Jakou úroveň přístupu má mít tento tým?
 
-form.name_reserved=Název organizace '%s' je již rezervován.
-form.name_pattern_not_allowed=Vzor názvu organizace '%s' není povolen.
-form.team_name_reserved=Název týmu '%s' je vyhrazen.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Nastavení
 settings.options=Možnosti
@@ -1001,18 +1006,19 @@ first_page=První
 last_page=Poslední
 total=Celkem: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
-dashboard.build_commit=Build commit
+dashboard.build_info=Informace o sestavení
+dashboard.app_ver=Verze aplikace
+dashboard.git_version=Git verze
+dashboard.go_version=Go verze
+dashboard.build_time=Čas sestavení
+dashboard.build_commit=Commit sestavení
 dashboard.statistic=Statistika
 dashboard.operations=Operace
 dashboard.system_status=Stav sledování systému
 dashboard.statistic_info=Databáze GIN obsahuje <b>%d</b> uživatelů, <b>%d</b> organizací, <b>%d</b> veřejných klíčů, <b>%d</b> repositářů, <b>%d</b> hlídání, <b>%d</b> oblíbení, <b>%d</b> akcí, <b>%d</b> přístupů, <b>%d</b> úkolů, <b>%d</b> komentářů, <b>%d</b> sociálních účtů, <b>%d</b> sledování, <b>%d</b> zrcadel, <b>%d</b> vydání, <b>%d</b> zdrojů přihlášení, <b>%d</b> webových háčků, <b>%d</b> milníků, <b>%d</b> štítků, <b>%d</b> háčků, <b>%d</b> týmů, <b>%d</b> úkolů změn, <b>%d</b> příloh.
 dashboard.operation_name=Název operace
 dashboard.operation_switch=Přepnout
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Spustit
 dashboard.clean_unbind_oauth=Smazat odpojené asociace OAuth2
 dashboard.clean_unbind_oauth_success=Všechny odpojené asociace OAuth2 byly smazány.
@@ -1162,48 +1168,48 @@ auths.github_api_endpoint=Koncový bod API
 
 config.not_set=(není nastaveno)
 config.server_config=Nastavení serveru
-config.brand_name=Brand name
+config.brand_name=Název značky
 config.run_user=Účet pro spouštění
 config.run_mode=Režim spouštění
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
+config.server.external_url=Externí URL
+config.server.domain=Doména
+config.server.protocol=Protokol
+config.server.http_addr=HTTP adresa
 config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
-config.server.unix_socket_permission=Unix socket permission
-config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
+config.server.cert_file=Soubor certifikátu
+config.server.key_file=Soubor klíče
+config.server.tls_min_version=Minimální verze TLS
+config.server.unix_socket_permission=Oprávnění Unix socket
+config.server.local_root_url=Místní URL kořenového adresáře
+config.server.offline_mode=Offline režim
 config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
-config.server.app_data_path=Application data path
+config.server.enable_gzip=Povolit Gzip
+config.server.app_data_path=Cesta dat aplikace
 config.server.load_assets_from_disk=Load assets from disk
 config.server.landing_url=Landing URL
 
 config.ssh_config=Nastavení SSH
-config.ssh.enabled=Enabled
-config.ssh.domain=Exposed domain
-config.ssh.port=Exposed port
-config.ssh.root_path=Root path
+config.ssh.enabled=Povoleno
+config.ssh.domain=Vystavená doména
+config.ssh.port=Vystavený port
+config.ssh.root_path=Kořenová cesta
 config.ssh.keygen_path=Keygen path
 config.ssh.key_test_path=Key test path
-config.ssh.minimum_key_size_check=Minimum key size check
-config.ssh.minimum_key_sizes=Minimum key sizes
+config.ssh.minimum_key_size_check=Kontrola minimální velikosti klíčů
+config.ssh.minimum_key_sizes=Minimální velikost klíčů
 config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
 config.ssh.start_builtin_server=Start builtin server
 config.ssh.listen_host=Listen host
 config.ssh.listen_port=Listen port
-config.ssh.server_ciphers=Server ciphers
+config.ssh.server_ciphers=Serverové šifry
 
 config.repo_config=Nastavení repositáře
-config.repo.root_path=Root path
-config.repo.script_type=Script type
+config.repo.root_path=Kořenová cesta
+config.repo.script_type=Typ skriptu
 config.repo.ansi_chatset=ANSI charset
 config.repo.force_private=Force private
 config.repo.max_creation_limit=Max creation limit
-config.repo.preferred_licenses=Preferred licenses
+config.repo.preferred_licenses=Upřednostňované licence
 config.repo.disable_http_git=Disable HTTP Git
 config.repo.enable_local_path_migration=Enable local path migration
 config.repo.enable_raw_file_render_mode=Enable raw file render mode
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Nastavení systémových záznamů
 config.log_file_root_path=Kořenový adresář souboru systémových záznamů
 config.log_mode=Režim

+ 160 - 148
conf/locale/locale_de-DE.ini

@@ -43,6 +43,10 @@ issues=Issues
 
 cancel=Abbrechen
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Installation
 title=Installationsschritte für den ersten Start
@@ -121,7 +125,7 @@ run_user_not_match=Der ausführende Benutzer ist nicht der aktuelle Benutzer: %s
 smtp_host_missing_port=In der Adresse des SMTP Host fehlt die Portnummer.
 invalid_smtp_from=SMTP Absender Feld ist nicht gültig: %v
 save_config_failed=Fehler beim Speichern der Konfiguration: %v
-init_failed=Failed to initialize application: %v
+init_failed=Fehler beim Initialisieren der Anwendung: %v
 invalid_admin_setting=Admin-Konto Einstellungen sind ungültig: %v
 install_success=Herzlich Willkommen! Wir sind froh, dass Sie sich für GIN entschieden haben. Wir wünschen viel Vergnügen damit.
 invalid_log_root_path=Pfad zum Log-Verzeichnis ist ungültig: %v
@@ -261,8 +265,7 @@ following=Folge ich
 follow=Folgen
 unfollow=Nicht mehr folgen
 
-form.name_reserved=Der Benutzername '%s' ist reserviert.
-form.name_pattern_not_allowed=Benutzernamen der Form '%s' sind nicht erlaubt.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -428,8 +431,7 @@ repo_description_helper=Beschreibung des Repository. Maximal 512 Zeichen.
 repo_description_length=Verfügbare Zeichen
 
 form.reach_limit_of_creation=Der Besitzer hat die maximale Anzahl von %d erstellbaren Repositories erreicht.
-form.name_reserved=Repository-Name '%s' ist reserviert.
-form.name_pattern_not_allowed=Repository-Namen der Form '%s' sind nicht erlaubt.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Authorisierung benötigt
 migrate_type=Migrationstyp
@@ -790,8 +792,10 @@ settings.collaborator_deletion_desc=Nach dem Löschen wird dieser Benutzer keine
 settings.remove_collaborator_success=Mitarbeiter wurde entfernt.
 settings.search_user_placeholder=Benutzer suchen...
 settings.org_not_allowed_to_be_collaborator=Eine Organisation kann nicht als Mitarbeiter hinzugefügt werden.
+settings.hooks_desc=Webhooks erlauben es Ihnen, externe Dienste zu informieren, wenn etwas Bestimmtes in Ihrem Repository passiert. Gogs sendet dann einen POST-Request an alle angegebenen URLs. Erfahren Sie mehr in unserem <a target="_blank" href="%s">Webhooks Guide</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Webhook hinzufügen
-settings.hooks_desc=Webhooks erlauben es Ihnen, externe Dienste zu informieren, wenn etwas Bestimmtes in Ihrem Repository passiert. GIN sendet dann einen POST-Request an alle angegebenen URLs. Erfahren Sie mehr in unserem <a target="_blank" href="%s">Webhooks Guide</a>.
 settings.webhook_deletion=Webhook entfernen
 settings.webhook_deletion_desc=Das Löschen dieses Webhooks wird alle zugehörigen Informationen und den Übertragungsverlauf entfernen. Wirklich fortfahren?
 settings.webhook_deletion_success=Webhook wurde erfolgreich entfernt!
@@ -805,6 +809,8 @@ settings.webhook.response=Antwort
 settings.webhook.headers=Kopfzeilen
 settings.webhook.payload=Nutzdaten
 settings.webhook.body=Inhalt
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git-Hooks werden von Git selbst bereitgestellt. Sie können die Dateien der unterstützten Hooks in der Liste unten bearbeiten, um eigene Operationen einzubinden.
 settings.githook_edit_desc=Wenn ein Hook inaktiv ist, wird der Standardinhalt benutzt. Lassen Sie den Inhalt leer, um den Hook zu deaktivieren.
 settings.githook_name=Hook-Name
@@ -931,9 +937,8 @@ team_name_helper=Unter diesem Namen können Sie in Diskussionen auf das Team ver
 team_desc_helper=Worum geht es bei diesem Team?
 team_permission_desc=Welche Berechtigungsstufe soll das Team haben?
 
-form.name_reserved=Organisationsname '%s' ist bereits vergeben.
-form.name_pattern_not_allowed=Organisationsnamen der Form '%s' sind nicht erlaubt.
-form.team_name_reserved=Der Teamname '%s' ist reserviert.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Einstellungen
 settings.options=Optionen
@@ -1005,18 +1010,19 @@ first_page=Erste
 last_page=Letzte
 total=Gesamt: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
-dashboard.build_commit=Build commit
+dashboard.build_info=Build-Informationen
+dashboard.app_ver=Anwendungsversion
+dashboard.git_version=Git-Version
+dashboard.go_version=Go-Version
+dashboard.build_time=Build-Zeit
+dashboard.build_commit=Build-Commit
 dashboard.statistic=Statistik
 dashboard.operations=Operationen
 dashboard.system_status=Systemmonitor-Status
 dashboard.statistic_info=GIN Datenbank hat <b>%d</b> Benutzer, <b>%d</b> Organisationen, <b>%d</b> öffentliche Schlüssel, <b>%d</b> Repositories, <b>%d</b> Beobachtet, <b>%d</b> Favoriten, <b>%d</b> Aktionen, <b>%d</b> Zugriffe, <b>%d</b> Issues, <b>%d</b> Kommentare, <b>%d</b> Konten sozialer Medien, <b>%d</b> Folgende, <b>%d</b> Mirror, <b>%d</b> Releases, <b>%d</b> Login-Quellen, <b>%d</b> Webhooks, <b>%d</b> Meilensteine, <b>%d</b> Label, <b>%d</b> Hook-Tasks, <b>%d</b> Teams, <b>%d</b> Aktualisierungs-Tasks, <b>%d</b> Anhänge.
 dashboard.operation_name=Name der Operation
 dashboard.operation_switch=Wechseln
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Ausführen
 dashboard.clean_unbind_oauth=Nicht verbundene OAuths bereinigen
 dashboard.clean_unbind_oauth_success=Alle nicht verbundenen OAuth-Tokens wurden gelöscht.
@@ -1166,167 +1172,173 @@ auths.github_api_endpoint=API Endpunkt
 
 config.not_set=(nicht festgelegt)
 config.server_config=Serverkonfiguration
-config.brand_name=Brand name
+config.brand_name=Markenname
 config.run_user=Ausführender Benutzer
 config.run_mode=Laufzeit-Modus
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
-config.server.unix_socket_permission=Unix socket permission
-config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
-config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
-config.server.app_data_path=Application data path
-config.server.load_assets_from_disk=Load assets from disk
-config.server.landing_url=Landing URL
+config.server.external_url=Externe URL
+config.server.domain=Domäne
+config.server.protocol=Protokoll
+config.server.http_addr=HTTP-Adresse
+config.server.http_port=HTTP-Port
+config.server.cert_file=Zertifikatsdatei
+config.server.key_file=Schlüsseldatei
+config.server.tls_min_version=Minimale TLS-Version
+config.server.unix_socket_permission=Unix-Socket-Berechtigung
+config.server.local_root_url=Lokale Root-URL
+config.server.offline_mode=Offline-Modus
+config.server.disable_router_log=Router-Log deaktivieren
+config.server.enable_gzip=Gzip aktivieren
+config.server.app_data_path=Anwendungsdatenpfad
+config.server.load_assets_from_disk=Assets von Festplatte laden
+config.server.landing_url=Startseite
 
 config.ssh_config=SSH Konfiguration
-config.ssh.enabled=Enabled
-config.ssh.domain=Exposed domain
-config.ssh.port=Exposed port
-config.ssh.root_path=Root path
-config.ssh.keygen_path=Keygen path
-config.ssh.key_test_path=Key test path
-config.ssh.minimum_key_size_check=Minimum key size check
-config.ssh.minimum_key_sizes=Minimum key sizes
-config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
-config.ssh.start_builtin_server=Start builtin server
-config.ssh.listen_host=Listen host
-config.ssh.listen_port=Listen port
-config.ssh.server_ciphers=Server ciphers
+config.ssh.enabled=Aktiviert
+config.ssh.domain=Exponierte Domain
+config.ssh.port=Exponierter Port
+config.ssh.root_path=Wurzelpfad
+config.ssh.keygen_path=Keygenpfad
+config.ssh.key_test_path=Schlüsseltestpfad
+config.ssh.minimum_key_size_check=Prüfung der Mindestschlüssellänge
+config.ssh.minimum_key_sizes=Mindestschlüssellängen
+config.ssh.rewrite_authorized_keys_at_start=Beim Start "authorized_keys" umschreiben
+config.ssh.start_builtin_server=Eingebauten Server starten
+config.ssh.listen_host=Listen-Host
+config.ssh.listen_port=Listen-Port
+config.ssh.server_ciphers=Serverchiffren
 
 config.repo_config=Repository-Konfiguration
-config.repo.root_path=Root path
-config.repo.script_type=Script type
-config.repo.ansi_chatset=ANSI charset
-config.repo.force_private=Force private
-config.repo.max_creation_limit=Max creation limit
-config.repo.preferred_licenses=Preferred licenses
-config.repo.disable_http_git=Disable HTTP Git
-config.repo.enable_local_path_migration=Enable local path migration
-config.repo.enable_raw_file_render_mode=Enable raw file render mode
-config.repo.commits_fetch_concurrency=Commits fetch concurrency
-config.repo.editor.line_wrap_extensions=Editor line wrap extensions
-config.repo.editor.previewable_file_modes=Editor previewable file modes
-config.repo.upload.enabled=Upload enabled
-config.repo.upload.temp_path=Upload temporary path
-config.repo.upload.allowed_types=Upload allowed types
-config.repo.upload.file_max_size=Upload file size limit
-config.repo.upload.max_files=Upload files limit
+config.repo.root_path=Wurzelpfad
+config.repo.script_type=Skript-Typ
+config.repo.ansi_chatset=ANSI-Zeichensatz
+config.repo.force_private=Privat erzwingen
+config.repo.max_creation_limit=Maximales Erstellungslimit
+config.repo.preferred_licenses=Bevorzugte Lizenzen
+config.repo.disable_http_git=HTTP-Git deaktivieren
+config.repo.enable_local_path_migration=Lokale Pfadmigration aktivieren
+config.repo.enable_raw_file_render_mode=Darstellen von Roh-Dateien aktivieren
+config.repo.commits_fetch_concurrency=Anzahl gleichzeitiger Commit-/Fetch-Prozesse
+config.repo.editor.line_wrap_extensions=Editor Erweiterungen für Zeilenumbrüche
+config.repo.editor.previewable_file_modes=Vorschau der Dateimodi des Editors
+config.repo.upload.enabled=Upload aktiviert
+config.repo.upload.temp_path=Temporärer Pfad für Uploads
+config.repo.upload.allowed_types=Erlaubte Upload-Typen
+config.repo.upload.file_max_size=Upload-Dateigrößenlimit
+config.repo.upload.max_files=Upload-Dateilimit
 
 config.db_config=Datenbankkonfiguration
-config.db.type=Type
+config.db.type=Typ
 config.db.host=Host
 config.db.name=Name
-config.db.user=User
-config.db.ssl_mode=SSL mode
-config.db.ssl_mode_helper=(for "postgres" only)
-config.db.path=Path
-config.db.path_helper=(for "sqlite3"only)
-
-config.security_config=Security configuration
-config.security.login_remember_days=Login remember days
-config.security.cookie_remember_name=Remember cookie
-config.security.cookie_username=Username cookie
-config.security.cookie_secure=Enable secure cookie
-config.security.reverse_proxy_auth_user=Reverse proxy authentication header
-config.security.enable_login_status_cookie=Enable login status cookie
-config.security.login_status_cookie_name=Login status cookie
-
-config.email_config=Email configuration
-config.email.enabled=Enabled
-config.email.subject_prefix=Subject prefix
+config.db.user=Benutzer
+config.db.ssl_mode=SSL-Modus
+config.db.ssl_mode_helper=(nur für "postgres")
+config.db.path=Pfad
+config.db.path_helper=(nur für "sqlite3")
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
+
+config.security_config=Sicherheitskonfiguration
+config.security.login_remember_days=Anzahl Tage zum Speichern des Logins
+config.security.cookie_remember_name=Cookie merken
+config.security.cookie_username=Benutzernamen-Cookie
+config.security.cookie_secure=Sicheres Cookie aktivieren
+config.security.reverse_proxy_auth_user=Reverse-Proxy-Authentifizierungs-Header
+config.security.enable_login_status_cookie=Login-Status-Cookie aktivieren
+config.security.login_status_cookie_name=Login-Status-Cookie
+
+config.email_config=E-Mail-Konfiguration
+config.email.enabled=Aktiviert
+config.email.subject_prefix=Betreff-Präfix
 config.email.host=Host
-config.email.from=From
-config.email.user=User
-config.email.disable_helo=Disable HELO
-config.email.helo_hostname=HELO hostname
-config.email.skip_verify=Skip certificate verify
-config.email.use_certificate=Use custom certificate
-config.email.cert_file=Certificate file
-config.email.key_file=Key file
-config.email.use_plain_text=Use plain text
-config.email.add_plain_text_alt=Add plain text alternative
-config.email.send_test_mail=Send test email
-config.email.test_mail_failed=Failed to send test email to '%s': %v
-config.email.test_mail_sent=Test email has been sent to '%s'.
-
-config.auth_config=Authentication configuration
-config.auth.activate_code_lives=Activate code lives
-config.auth.reset_password_code_lives=Reset password code lives
-config.auth.require_email_confirm=Require email confirmation
-config.auth.require_sign_in_view=Require sign in view
-config.auth.disable_registration=Disable registration
-config.auth.enable_registration_captcha=Enable registration captcha
-config.auth.enable_reverse_proxy_authentication=Enable reverse proxy authentication
-config.auth.enable_reverse_proxy_auto_registration=Enable reverse proxy auto registration
-config.auth.reverse_proxy_authentication_header=Reverse proxy authentication header
-
-config.user_config=User configuration
-config.user.enable_email_notify=Enable email notification
+config.email.from=Von
+config.email.user=Benutzer
+config.email.disable_helo=HELO deaktivieren
+config.email.helo_hostname=HELO Hostname
+config.email.skip_verify=Zertifikatsüberprüfung überspringen
+config.email.use_certificate=Benutzerdefiniertes Zertifikat verwenden
+config.email.cert_file=Zertifikatsdatei
+config.email.key_file=Schlüsseldatei
+config.email.use_plain_text=Klartext verwenden
+config.email.add_plain_text_alt=Klartext-Alternative hinzufügen
+config.email.send_test_mail=Test-E-Mail senden
+config.email.test_mail_failed=Fehler beim Senden der Test-E-Mail an '%s': %v
+config.email.test_mail_sent=Test-E-Mail wurde an '%s ' gesendet.
+
+config.auth_config=Authentifizierungskonfiguration
+config.auth.activate_code_lives=Aktivierungscode Lebensdauer
+config.auth.reset_password_code_lives=Gültigkeitsdauer Zurücksetzungs-Code
+config.auth.require_email_confirm=E-Mail-Bestätigung erforderlich
+config.auth.require_sign_in_view=Anmeldung erforderlich
+config.auth.disable_registration=Registrierung deaktivieren
+config.auth.enable_registration_captcha=Registrierungs-Captcha aktivieren
+config.auth.enable_reverse_proxy_authentication=Reverse-Proxy-Authentifizierung aktivieren
+config.auth.enable_reverse_proxy_auto_registration=Automatische Reverse-Proxy-Registrierung aktivieren
+config.auth.reverse_proxy_authentication_header=Reverse-Proxy-Authentifizierungs-Header
+
+config.user_config=Benutzerkonfiguration
+config.user.enable_email_notify=E-Mail-Benachrichtigung aktivieren
 
 config.session_config=Session-Konfiguration
-config.session.provider=Provider
-config.session.provider_config=Provider config
+config.session.provider=Anbieter
+config.session.provider_config=Anbieter-Konfiguration
 config.session.cookie_name=Cookie
-config.session.https_only=HTTPS only
-config.session.gc_interval=GC interval
-config.session.max_life_time=Max life time
-config.session.csrf_cookie_name=CSRF cookie
+config.session.https_only=Nur HTTPS
+config.session.gc_interval=GC-Intervall
+config.session.max_life_time=Maximale Lebensdauer
+config.session.csrf_cookie_name=CSRF-Cookie
 
 config.cache_config=Cache-Konfiguration
 config.cache.adapter=Adapter
-config.cache.interval=GC interval
+config.cache.interval=GC-Intervall
 config.cache.host=Host
 
 config.http_config=HTTP-Konfiguration
-config.http.access_control_allow_origin=Access control allow origin
+config.http.access_control_allow_origin=Access-Control-Allow-Origin
 
-config.attachment_config=Attachment configuration
-config.attachment.enabled=Enabled
-config.attachment.path=Path
-config.attachment.allowed_types=Allowed types
-config.attachment.max_size=Size limit
-config.attachment.max_files=Files limit
+config.attachment_config=Anhang-Konfiguration
+config.attachment.enabled=Aktiviert
+config.attachment.path=Pfad
+config.attachment.allowed_types=Erlaubte Typen
+config.attachment.max_size=Größenlimit
+config.attachment.max_files=Dateilimit
 
-config.release_config=Release configuration
-config.release.attachment.enabled=Attachment enabled
-config.release.attachment.allowed_types=Attachment allowed types
-config.release.attachment.max_size=Attachment size limit
-config.release.attachment.max_files=Attachment files limit
+config.release_config=Release-Konfiguration
+config.release.attachment.enabled=Anhang aktiviert
+config.release.attachment.allowed_types=Erlaubte Anhang-Typen
+config.release.attachment.max_size=Größenlimit für Anhang
+config.release.attachment.max_files=Dateilimit für Anhang
 
 config.picture_config=Konfiguration der Profilbilder
-config.picture.avatar_upload_path=User avatar upload path
-config.picture.repo_avatar_upload_path=Repository avatar upload path
-config.picture.gravatar_source=Gravatar source
-config.picture.disable_gravatar=Disable Gravatar
-config.picture.enable_federated_avatar=Enable federated avatars
+config.picture.avatar_upload_path=Benutzer-Avatar Upload-Pfad
+config.picture.repo_avatar_upload_path=Repository-Avatar Upload-Pfad
+config.picture.gravatar_source=Gravatar-Quelle
+config.picture.disable_gravatar=Gravatar deaktivieren
+config.picture.enable_federated_avatar=Föderierte Avatare aktivieren
 
-config.mirror_config=Mirror configuration
-config.mirror.default_interval=Default interval
+config.mirror_config=Mirror-Konfiguration
+config.mirror.default_interval=Standardintervall
 
 config.webhook_config=Webhook-Konfiguration
-config.webhook.types=Types
-config.webhook.deliver_timeout=Deliver timeout
-config.webhook.skip_tls_verify=Skip TLS verify
+config.webhook.types=Typen
+config.webhook.deliver_timeout=Zeitlimit für Zustellung
+config.webhook.skip_tls_verify=TLS-Prüfung überspringen
 
 config.git_config=Git Konfiguration
-config.git.disable_diff_highlight=Disable diff syntax highlight
-config.git.max_diff_lines=Diff lines limit (for a single file)
-config.git.max_diff_line_characters=Diff characters limit (for a single line)
-config.git.max_diff_files=Diff files limit (for a single diff)
-config.git.gc_args=GC arguments
-config.git.migrate_timeout=Migration timeout
-config.git.mirror_timeout=Mirror fetch timeout
-config.git.clone_timeout=Clone timeout
-config.git.pull_timeout=Pull timeout
-config.git.gc_timeout=GC timeout
+config.git.disable_diff_highlight=Diff-Syntaxhervorhebung ausschalten
+config.git.max_diff_lines=Zeilenlimit für Diff (für eine einzelne Datei)
+config.git.max_diff_line_characters=Zeichenlimit für Diff (für eine einzelne Datei)
+config.git.max_diff_files=Dateilimit für Diff (für einen einzelnen Diff)
+config.git.gc_args=GC-Argumente
+config.git.migrate_timeout=Zeitlimit für Migration
+config.git.mirror_timeout=Zeitlimit zum Spiegeln
+config.git.clone_timeout=Clone-Timeout
+config.git.pull_timeout=Pull-Timeout
+config.git.gc_timeout=GC-Timeout
+
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
 
 config.log_config=Konfiguration des Loggings
 config.log_file_root_path=Log-Verzeichnis
@@ -1401,7 +1413,7 @@ months=%[2]s %[1]d Monaten
 years=%[2]s %[1]d Jahren
 raw_seconds=Sekunden
 raw_minutes=Minuten
-raw_hours=hours
+raw_hours=Stunden
 
 [dropzone]
 default_message=Zum Hochladen hier klicken oder Datei hier ablegen.

+ 20 - 8
conf/locale/locale_en-GB.ini

@@ -45,6 +45,10 @@ issues=Issues
 
 cancel=Cancel
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Installation
 title=Install Steps For First-time Run
@@ -265,8 +269,7 @@ following=Following
 follow=Follow
 unfollow=Unfollow
 
-form.name_reserved=Username '%s' is reserved.
-form.name_pattern_not_allowed=Username pattern '%s' is not allowed.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profile
@@ -435,8 +438,7 @@ repo_description_helper=The title of the dataset or other brief sentence to desc
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=The owner has reached maximum creation limit of %d repositories.
-form.name_reserved=Repository name '%s' is reserved.
-form.name_pattern_not_allowed=Repository name pattern '%s' is not allowed.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Need Authorisation
 migrate_type=Migration Type
@@ -797,8 +799,10 @@ settings.collaborator_deletion_desc=This user will no longer have collaboration
 settings.remove_collaborator_success=Collaborator has been removed.
 settings.search_user_placeholder=Search user...
 settings.org_not_allowed_to_be_collaborator=Organisation is not allowed to be added as a collaborator.
+settings.hooks_desc=Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in Gogs, we will handle the notification to the target host you specify. Learn more in this <a target="_blank" href="%s">Webhooks Guide</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Add Webhook
-settings.hooks_desc=Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in GIN, we will handle the notification to the target host you specify. Learn more in this <a target="_blank" href="%s">Webhooks Guide</a>.
 settings.webhook_deletion=Delete Webhook
 settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
 settings.webhook_deletion_success=Webhook has been deleted successfully!
@@ -812,6 +816,8 @@ settings.webhook.response=Response
 settings.webhook.headers=Headers
 settings.webhook.payload=Payload
 settings.webhook.body=Body
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to perform custom operations.
 settings.githook_edit_desc=If the hook is inactive, sample content will be presented. Leaving content to an empty value will disable this hook.
 settings.githook_name=Hook Name
@@ -938,9 +944,8 @@ team_name_helper=You'll use this name to mention this team in conversations.
 team_desc_helper=What is this team all about?
 team_permission_desc=What permission level should this team have?
 
-form.name_reserved=Organisation name '%s' is reserved.
-form.name_pattern_not_allowed=Organisation name pattern '%s' is not allowed.
-form.team_name_reserved=Team name '%s' is reserved.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Settings
 settings.options=Options
@@ -1024,6 +1029,7 @@ dashboard.system_status=System Monitor Status
 dashboard.statistic_info=GIN database has <b>%d</b> users, <b>%d</b> organisations, <b>%d</b> public keys, <b>%d</b> repositories, <b>%d</b> watches, <b>%d</b> stars, <b>%d</b> actions, <b>%d</b> accesses, <b>%d</b> issues, <b>%d</b> comments, <b>%d</b> social accounts, <b>%d</b> follows, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> login sources, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> hook tasks, <b>%d</b> teams, <b>%d</b> update tasks, <b>%d</b> attachments.
 dashboard.operation_name=Operation Name
 dashboard.operation_switch=Switch
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Run
 dashboard.clean_unbind_oauth=Clean unbound OAuthes
 dashboard.clean_unbind_oauth_success=All unbind OAuthes have been deleted successfully.
@@ -1236,6 +1242,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1335,6 +1343,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Log Configuration
 config.log_file_root_path=Log File Root Path
 config.log_mode=Mode

+ 21 - 9
conf/locale/locale_en-US.ini

@@ -45,6 +45,10 @@ issues = Issues
 
 cancel = Cancel
 
+[status]
+page_not_found = Page Not Found
+internal_server_error = Internal Server Error
+
 [install]
 install = Installation
 title = Install Steps For First-time Run
@@ -265,8 +269,7 @@ following = Following
 follow = Follow
 unfollow = Unfollow
 
-form.name_reserved = Username '%s' is reserved.
-form.name_pattern_not_allowed = Username pattern '%s' is not allowed.
+form.name_not_allowed = User name or pattern %q is not allowed.
 
 [settings]
 profile = Profile
@@ -438,8 +441,7 @@ repo_description_helper = The title of the dataset or other brief sentence to de
 repo_description_length = Available characters
 
 form.reach_limit_of_creation = The owner has reached maximum creation limit of %d repositories.
-form.name_reserved = Repository name '%s' is reserved.
-form.name_pattern_not_allowed = Repository name pattern '%s' is not allowed.
+form.name_not_allowed = Repository name or pattern %q is not allowed.
 
 need_auth = Need Authorization
 migrate_type = Migration Type
@@ -803,8 +805,10 @@ settings.invite_collaborator = Invite Collaborator
 settings.invite_placeholder = Enter mail adress to invite
 settings.invite_collaborator_warn = Be aware that this will send out invitation mails!
 settings.org_not_allowed_to_be_collaborator = Organization is not allowed to be added as a collaborator.
-settings.add_webhook = Add Webhook
-settings.hooks_desc = Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in GIN, we will handle the notification to the target host you specify. Learn more in this <a target="_blank" href="%s">Webhooks Guide</a>.
+settings.hooks_desc = Webhooks are much like basic HTTP POST event triggers. Whenever something occurs in Gogs, we will handle the notification to the target host you specify.
+settings.webhooks.add_new = Add a new webhook:
+settings.webhooks.choose_a_type = Choose a type...
+settings.add_webhook = Add webhook
 settings.webhook_deletion = Delete Webhook
 settings.webhook_deletion_desc = Delete this webhook will remove its information and all delivery history. Do you want to continue?
 settings.webhook_deletion_success = Webhook has been deleted successfully!
@@ -818,6 +822,8 @@ settings.webhook.response = Response
 settings.webhook.headers = Headers
 settings.webhook.payload = Payload
 settings.webhook.body = Body
+settings.webhook.err_cannot_parse_payload_url = Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses = Non admins are not allowed to use local addresses.
 settings.githooks_desc = Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to perform custom operations.
 settings.githook_edit_desc = If the hook is inactive, sample content will be presented. Leaving content to an empty value will disable this hook.
 settings.githook_name = Hook Name
@@ -944,9 +950,8 @@ team_name_helper = You'll use this name to mention this team in conversations.
 team_desc_helper = What is this team all about?
 team_permission_desc = What permission level should this team have?
 
-form.name_reserved = Organization name '%s' is reserved.
-form.name_pattern_not_allowed = Organization name pattern '%s' is not allowed.
-form.team_name_reserved = Team name '%s' is reserved.
+form.name_not_allowed = Organization name or pattern %q is not allowed.
+form.team_name_not_allowed = Team name or pattern %q is not allowed.
 
 settings = Settings
 settings.options = Options
@@ -1030,6 +1035,7 @@ dashboard.system_status = System Monitor Status
 dashboard.statistic_info = GIN database has <b>%d</b> users, <b>%d</b> organizations, <b>%d</b> public keys, <b>%d</b> repositories, <b>%d</b> watches, <b>%d</b> stars, <b>%d</b> actions, <b>%d</b> accesses, <b>%d</b> issues, <b>%d</b> comments, <b>%d</b> social accounts, <b>%d</b> follows, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> login sources, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> hook tasks, <b>%d</b> teams, <b>%d</b> update tasks, <b>%d</b> attachments.
 dashboard.operation_name = Operation Name
 dashboard.operation_switch = Switch
+dashboard.select_operation_to_run = Please select operation to run
 dashboard.operation_run = Run
 dashboard.clean_unbind_oauth = Clean unbound OAuthes
 dashboard.clean_unbind_oauth_success = All unbind OAuthes have been deleted successfully.
@@ -1242,6 +1248,8 @@ config.db.ssl_mode = SSL mode
 config.db.ssl_mode_helper = (for "postgres" only)
 config.db.path = Path
 config.db.path_helper = (for "sqlite3"only)
+config.db.max_open_conns = Maximum open connections
+config.db.max_idle_conns = Maximum idle connections
 
 config.security_config = Security configuration
 config.security.login_remember_days = Login remember days
@@ -1341,6 +1349,10 @@ config.git.clone_timeout = Clone timeout
 config.git.pull_timeout = Pull timeout
 config.git.gc_timeout = GC timeout
 
+config.lfs_config = LFS configuration
+config.lfs.storage = Storage
+config.lfs.objects_path = Objects path
+
 config.log_config = Log configuration
 config.log_file_root_path = Log file root path
 config.log_mode = Mode

+ 20 - 8
conf/locale/locale_es-ES.ini

@@ -43,6 +43,10 @@ issues=Incidencias
 
 cancel=Cancelar
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalación
 title=Pasos de la instalación por primera vez
@@ -259,8 +263,7 @@ following=Siguiendo
 follow=Seguir
 unfollow=Dejar de seguir
 
-form.name_reserved=El usuario '%s' está reservado.
-form.name_pattern_not_allowed=El patrón de nombre de usuario '%s' no está permitido.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Perfil
@@ -426,8 +429,7 @@ repo_description_helper=Descripción del repositorio. Longitud máxima de 512 ca
 repo_description_length=Caracteres disponibles
 
 form.reach_limit_of_creation=El propietario ha alcanzado el límite máximo de %d repositorios creados.
-form.name_reserved=El nombre del repositorio '%s' está reservado.
-form.name_pattern_not_allowed=El patrón del nombre del repositorio '%s' no está permitido.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Requiere autorización
 migrate_type=Tipo de migración
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Este usuario no podrá colaborar en este rep
 settings.remove_collaborator_success=El colaborador ha sido eliminado.
 settings.search_user_placeholder=Buscar usuario...
 settings.org_not_allowed_to_be_collaborator=Las organizaciones no tiene permitido ser añadidas como colaboradores.
+settings.hooks_desc=Los Webhooks permiten a servicios externos recibir notificaciones cuando sucedan ciertos eventos en Gogs. Cuando sucedan los eventos especificados, enviaremos una petición POST a cada una de las URLs indicadas. Para obtener más información, consulta nuestra <a target="_blank" href="%s">Guía de Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Añadir Webhook
-settings.hooks_desc=Los Webhooks permiten a servicios externos recibir notificaciones cuando sucedan ciertos eventos en GIN. Cuando sucedan los eventos especificados, enviaremos una petición POST a cada una de las URLs indicadas. Para obtener más información, consulta nuestra <a target="_blank" href="%s">Guía de Webhooks</a>.
 settings.webhook_deletion=Eliminar Webhook
 settings.webhook_deletion_desc=Al borrar este webhook se eliminará su información y todo su historial. ¿Desea continuar?
 settings.webhook_deletion_success=¡Webhook eliminado con éxito!
@@ -801,6 +805,8 @@ settings.webhook.response=Respuesta
 settings.webhook.headers=Encabezado
 settings.webhook.payload=Payload
 settings.webhook.body=Cuerpo del mensaje
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Los Git Hooks son una funcionalidad del propio Git, puedes editar los ficheros de los hooks soportados en la siguiente lista para aplicar operaciones personalizadas.
 settings.githook_edit_desc=Si el hook no está activo, se mostrará contenido de ejemplo. Dejar el contenido vacío deshabilitará este hook.
 settings.githook_name=Nombre del Hook
@@ -927,9 +933,8 @@ team_name_helper=Utiliza este nombre para mencionar a este equipo en las convers
 team_desc_helper=¿En qué consiste este equipo?
 team_permission_desc=¿Qué nivel de permisos debería tener este equipo?
 
-form.name_reserved=El nombre de la organización '%s' está reservado.
-form.name_pattern_not_allowed=El patrón de nombre de la organización '%s' no está permitido.
-form.team_name_reserved=El nombre de equipo '%s' está reservado.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Configuración
 settings.options=Opciones
@@ -1013,6 +1018,7 @@ dashboard.system_status=Estado del Monitor del Sistema
 dashboard.statistic_info=La base de datos de GIN contiene <b>%d</b> usuarios, <b>%d</b> organizaciones, <b>%d</b> claves públicas, <b>%d</b> repositorios, <b>%d</b> vigilados, <b>%d</b> destacados, <b>%d</b> acciones, <b>%d</b> accesos, <b>%d</b> incidencias, <b>%d</b> comentarios, <b>%d</b> cuentas de redes sociales, <b>%d</b> seguidores, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> fuentes de login, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> etiquetas, <b>%d</b> hooks, <b>%d</b> equipos, <b>%d</b> tareas actualizadas, <b>%d</b> adjuntos.
 dashboard.operation_name=Nombre de la operación
 dashboard.operation_switch=Interruptor
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Ejecutar
 dashboard.clean_unbind_oauth=Limpiar solicitudes de OAuth sin confirmar
 dashboard.clean_unbind_oauth_success=Las solicitudes de OAuth sin confirmar se han eliminado correctamente.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Configuración del Log
 config.log_file_root_path=Ruta de los Ficheros de Log
 config.log_mode=Modo

+ 20 - 8
conf/locale/locale_fa-IR.ini

@@ -43,6 +43,10 @@ issues=مسائل
 
 cancel=لغو
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=نصب
 title=مراحل نصب برای اولین اجرا
@@ -259,8 +263,7 @@ following=دنبال می کند
 follow=دنبال کردن
 unfollow=لغو دنبال کردن
 
-form.name_reserved=نام کاربری "%s" استفاده شده است.
-form.name_pattern_not_allowed=الگوی نام کاربری '%s' مجاز نیست.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=پروفایل
@@ -428,8 +431,7 @@ repo_description_helper=توضیحات مخرن. حداکثر طول ۵۱۲ کا
 repo_description_length=کاراکترهای موجود
 
 form.reach_limit_of_creation=مخزن های دارنده حساب به حداکثر تعداد مجاز %d رسیده است.
-form.name_reserved=یک مخزن با نام '%s' از قبل وجود دارد.
-form.name_pattern_not_allowed=ساختار '%s' برای نام مخزن مجاز نیست.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=نیاز به مجوز
 migrate_type=نوع انتقال
@@ -788,8 +790,10 @@ settings.collaborator_deletion_desc=این کاربر پس از حذف دیگر
 settings.remove_collaborator_success=همكار حذف شد.
 settings.search_user_placeholder=جستجوی کاربر...
 settings.org_not_allowed_to_be_collaborator=سازمان ها را نمیتوان به عنوان همکار افزود.
-settings.add_webhook=اضافه‌کردن Webhook
 settings.hooks_desc=Webhook ها مانند یک درخواست POST در HTTP اند. هرگاه رخدادی در gogs رخ می دهد، ما نوتیفیکیشنی برای هاستی که شما تعریف کرده اید ارسال می کنیم. برای اطلاعات بیشتر <a target="_blank" href="%s"> راهنمای webhook</a> را مطالعه کنید.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=اضافه‌کردن Webhook
 settings.webhook_deletion=حذف Webhook
 settings.webhook_deletion_desc=حذف این webhook باعث می شود که تمامی اطلاعات آن و تاریخچه ی تمام دلیوری های آن حذف شود. آیا ادامه میدهید؟
 settings.webhook_deletion_success=Webhook با موفقیت حذف شد!
@@ -803,6 +807,8 @@ settings.webhook.response=پاسخ
 settings.webhook.headers=هدر
 settings.webhook.payload=Payload
 settings.webhook.body=بدنه
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git Hook ها توسط تیم Git ایجاد شده اند، شما می توانید فایل hook های پشتیبانی شده را ویرایش کنید تا بتوانید عملیات دلخواه خودتان را انجام دهید.
 settings.githook_edit_desc=در صورتیکه hook غیرفعال باشد، محتوای نمونه ای موجود در آن ارائه خواهد شد. برای اینکه به کلی غیر فعال شود، محتوا را پاک کنید تا خالی شود.
 settings.githook_name=نام hook
@@ -929,9 +935,8 @@ team_name_helper=ما از این نام برای اشاره به این تیم
 team_desc_helper=این تیم درکل در مورد چیست؟
 team_permission_desc=این تیم چه سطح دسترسی میتواند داشته باشد؟
 
-form.name_reserved=نام سازمان %s رزرو شده است.
-form.name_pattern_not_allowed=الگوی نام سازمان به صورت "%s" مجاز نیست.
-form.team_name_reserved=نام تیم "%s" رزرو شده است.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=تنظيمات
 settings.options=گزینه‌‌‌‌‌‌ها
@@ -1015,6 +1020,7 @@ dashboard.system_status=سیستم مانیتور وضعیت
 dashboard.statistic_info=دیتابیس gogs شامل <b>%d</b> کاربران, <b>%d</b> سازمان ها, <b>%d</b> کلید های عمومی, <b>%d</b> مخازن, <b>%d</b> مشاهده ها, <b>%d</b> ستاره دار ها, <b>%d</b> فعالیت ها, <b>%d</b> دسترسی ها, <b>%d</b> مسائل, <b>%d</b> نظرات, <b>%d</b> حساب ها کاربری شبکه های اجتماعی, <b>%d</b> دنیال کردن ها, <b>%d</b>mirror, <b>%d</b> ریلیز ها, <b>%d</b> نقاط ورود به سیستم, <b>%d</b> webhooks, <b>%d</b> نقاط عطف یا milestone ها, <b>%d</b> برچسب, <b>%d</b> hook وظایف, <b>%d</b> تیم, <b>%d</b> به روزرسانی ها وظایف افراد, <b>%d</b> پیوست هاست.
 dashboard.operation_name=نام عملیات
 dashboard.operation_switch=سویچ
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=اجرا
 dashboard.clean_unbind_oauth=پاک کردن OAuthe های ناخواسته
 dashboard.clean_unbind_oauth_success=تمامی oAuth های غیرمتصل با موفقیت حذف شدند.
@@ -1227,6 +1233,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1326,6 +1334,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=پیکربندی لاگ
 config.log_file_root_path=مسیر ریشه ی فایل لاگ
 config.log_mode=حالت

+ 23 - 11
conf/locale/locale_fi-FI.ini

@@ -43,6 +43,10 @@ issues=Ongelmat
 
 cancel=Peruuta
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Asennus
 title=Asennusvaiheet ottaessa ensi kertaa käyttöön
@@ -71,9 +75,9 @@ run_user=Suorita käyttäjänä
 run_user_helper=Käyttäjällä täytyy olla oikeus repositoryn juuripolkuun. Käyttäjällä täytyy myös olla oikeus suorittaa GIN.
 domain=Verkkotunnus
 domain_helper=Tämä vaikuttaa SSH klooni URLeihin.
-ssh_port=SSH portti
+ssh_port=SSH-portti
 ssh_port_helper=Portti numero jota SSH palvelimesi käyttää, jätä tyhjäksi poistaaksesi käytöstä SSH toiminnon.
-use_builtin_ssh_server=Käytä sisäänrakennettua SSH palvelinta
+use_builtin_ssh_server=Käytä sisäänrakennettua SSH-palvelinta
 use_builtin_ssh_server_popup=Käynnistä sisäänrakennettu SSH-palvelin Git-operaatioille, järjestelmän SSH-palvelusta erottautumiseksi.
 http_port=HTTP portti
 http_port_helper=Portti numero jota sovellus tulee kuuntelemaan.
@@ -259,8 +263,7 @@ following=Seurataan
 follow=Seuraa
 unfollow=Lopeta seuraaminen
 
-form.name_reserved=Käyttäjätunnus '%s' on varattu.
-form.name_pattern_not_allowed=Käyttäjätunnus mallia '%s' ei ole sallittu.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profiili
@@ -426,8 +429,7 @@ repo_description_helper=Repon kuvaus. Enintään 512 merkkiä.
 repo_description_length=Käytettävissä olevat merkit
 
 form.reach_limit_of_creation=Omistaja on saavuttanut maksimi luontirajan %d repoa.
-form.name_reserved=Repon nimi '%s' on varattu.
-form.name_pattern_not_allowed=Repon nimi mallia '%s' ei ole sallittu.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Tarvitaan lupa
 migrate_type=Siirtotyyppi
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Tällä käyttäjällä ei tule enää olema
 settings.remove_collaborator_success=Yhteistyökumppani on poistettu.
 settings.search_user_placeholder=Etsi käyttäjä...
 settings.org_not_allowed_to_be_collaborator=Yhteistyökumppaniksi ei voi lisätä organisaatiota.
-settings.add_webhook=Lisää webkoukku
 settings.hooks_desc=Webkoukut muistuttavat paljon perus HTTP POST tapahtuma laukaisimia. Aina kun jotain tapahtuu Gogsissa, käsittelemme ilmoituksen määrittäämääsi kohteeseen. Lisätietoja <a target="_blank" href="%s">webkoukku oppaassa</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Lisää webkoukku
 settings.webhook_deletion=Poista webkoukku
 settings.webhook_deletion_desc=Tämän webkoukun poistaminen poistaa sen tiedot ja kaiken toimitushistorian. Haluatko jatkaa?
 settings.webhook_deletion_success=Webkoukku on poistettu onnistuneesti!
@@ -801,6 +805,8 @@ settings.webhook.response=Vastaus
 settings.webhook.headers=Otsikot
 settings.webhook.payload=Payload
 settings.webhook.body=Body
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git koukkujen voimanlähteenä on Git itse, voit muokata tuettujen koukkujen tiedostoja allaolevassa luettelossa suorittaaksesi mukautettuja toimintoja.
 settings.githook_edit_desc=Jos koukku ei ole käytössä, esitellään esimerkkisisältö. Sisällön jättäminen tyhjäksi arvoksi poistaa tämän koukun käytöstä.
 settings.githook_name=Koukun nimi
@@ -927,9 +933,8 @@ team_name_helper=Käytät tätä nimeä mainitessasi tämän tiimin keskusteluis
 team_desc_helper=Mistä on kyse tässä tiimissä?
 team_permission_desc=Mikä käyttöoikeustaso tuliti tällä tiimillä olla?
 
-form.name_reserved=Organisaation nimi '%s' on varattu.
-form.name_pattern_not_allowed=Organisaation nimi mallia '%s' ei ole sallittu.
-form.team_name_reserved=Tiimin nimi '%s' on varattu.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Asetukset
 settings.options=Valinnaiset
@@ -1013,6 +1018,7 @@ dashboard.system_status=Järjestelmänvalvonnan tila
 dashboard.statistic_info=GIN tietokannassa on <b>%d</b> käyttäjää, <b>%d</b> organisaatiota, <b>%d</b> julkista avainta, <b>%d</b> repoa, <b>%d</b> tarkkailijaa, <b>%d</b> tähteä, <b>%d</b> toimea, <b>%d</b> sisäänkirjautunutta, <b>%d</b> ongelmaa, <b>%d</b> kommenttia, <b>%d</b> sosiaalista tiliä, <b>%d</b> seuraajaa, <b>%d</b> peiliä, <b>%d</b> julkaisua, <b>%d</b> kirjautumis lähdettä, <b>%d</b> webkoukkua, <b>%d</b> merkkipaalua, <b>%d</b> tunnistetta, <b>%d</b> koukku tehtävää, <b>%d</b> tiimiä, <b>%d</b> päivitys tehtävää, <b>%d</b> liitetiedostoa.
 dashboard.operation_name=Toiminnon nimi
 dashboard.operation_switch=Vaihda
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Suorita
 dashboard.clean_unbind_oauth=Puhdista ei-liitetyt OAuthit
 dashboard.clean_unbind_oauth_success=Kaikki ei-liitetyt OAuthit on poistettu onnistuneesti.
@@ -1161,7 +1167,7 @@ auths.login_source_exist=Kirjautumislähde '%s' on jo olemassa
 auths.github_api_endpoint=API päätepiste
 
 config.not_set=(ei ole asetettu)
-config.server_config=Palvelin asetukset
+config.server_config=Palvelinasetukset
 config.brand_name=Brand name
 config.run_user=Suorita käyttäjänä
 config.run_mode=Suoritustila
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Loki asetukset
 config.log_file_root_path=Lokitiedoston juuren polku
 config.log_mode=Tila

+ 20 - 8
conf/locale/locale_fr-FR.ini

@@ -43,6 +43,10 @@ issues=Tickets
 
 cancel=Annuler
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Installation
 title=Instructions pour la première exécution
@@ -259,8 +263,7 @@ following=Abonnements
 follow=Suivre
 unfollow=Ne plus suivre
 
-form.name_reserved=Le nom '%s' est réservé.
-form.name_pattern_not_allowed=Motif '%s' interdit pour les noms d'utilisateur.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Description du dépôt. 512 caractères maximum.
 repo_description_length=Caractères disponibles
 
 form.reach_limit_of_creation=Le propriétaire a atteint le nombre maximal de %d dépôts créés.
-form.name_reserved=Le nom de dépôt '%s' est réservé.
-form.name_pattern_not_allowed=Motif '%s' interdit pour les noms de dépôt.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Nécessite une Autorisation
 migrate_type=Type de migration
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Cet utilisateur n'aura plus accès pour coll
 settings.remove_collaborator_success=Collaborateur supprimé.
 settings.search_user_placeholder=Rechercher un utilisateur...
 settings.org_not_allowed_to_be_collaborator=Une organisation n'est pas autorisée à être ajoutée en tant que collaborateur.
+settings.hooks_desc=Les Webhooks sont des déclencheurs de POST HTTP . Lorsque qu'un événement se produit dans Gogs, une notification sera envoyée vers l'hôte cible préalablement spécifié. Apprenez-en davantage dans le <a target="_blank" href="%s">Guide des Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Ajouter un Webhook
-settings.hooks_desc=Les Webhooks sont des déclencheurs de POST HTTP . Lorsque qu'un événement se produit dans GIN, une notification sera envoyée vers l'hôte cible préalablement spécifié. Apprenez-en davantage dans le <a target="_blank" href="%s">Guide des Webhooks</a>.
 settings.webhook_deletion=Supprimer le Webhook
 settings.webhook_deletion_desc=Supprimer ce webhook va supprimer ses informations et l'historique de livraison. Voulez-vous continuer ?
 settings.webhook_deletion_success=Le webhook a été supprimé avec succès !
@@ -801,6 +805,8 @@ settings.webhook.response=Réponse
 settings.webhook.headers=Entêtes 
 settings.webhook.payload=Payload
 settings.webhook.body=Corps
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Les Hooks Git sont alimentés par Git lui même. Les Hooks compatibles sont modifiables dans la liste ci-dessous pour effectuer des opérations personnalisées.
 settings.githook_edit_desc=Si un Hook est inactif, un exemple de contenu vous sera proposé. Un contenu laissé vide signifie un Hook inactif.
 settings.githook_name=Nom du Hook
@@ -927,9 +933,8 @@ team_name_helper=Ce nom sera utilisé pour mentionner l'équipe dans les convers
 team_desc_helper=Présentation de l'équipe
 team_permission_desc=Quel niveau d'accès cette équipe devrait-elle posséder ?
 
-form.name_reserved=Le nom d'organisation '%s' est réservé.
-form.name_pattern_not_allowed=Motif '%s' interdit pour les noms d'organisation.
-form.team_name_reserved=Le nom d'équipe « %s » est réservé.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Paramètres
 settings.options=Options
@@ -1013,6 +1018,7 @@ dashboard.system_status=État du système
 dashboard.statistic_info=La base de données GIN contient <b>%d</b> utilisateurs, <b>%d</b> organisations, <b>%d</b> clés publiques, <b>%d</b> dépôts, <b>%d</b> surveillances de dépôts, <b>%d</b> votes, <b>%d</b> actions, <b>%d</b> accès, <b>%d</b> tickets, <b>%d</b> commentaires, <b>%d</b> comptes de réseaux sociaux, <b>%d</b> abonnements, <b>%d</b> miroirs, <b>%d</b> versions, <b>%d</b> connexions d'origine, <b>%d</b> webhooks, <b>%d</b> versions, <b>%d</b> labels, <b>%d</b> tâches hook, <b>%d</b> équipes, <b>%d</b> tâches de mise à jour, <b>%d</b> fichiers.
 dashboard.operation_name=Nom de l'Opération
 dashboard.operation_switch=Basculer
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Exécuter
 dashboard.clean_unbind_oauth=Nettoyer les associations OAuthes
 dashboard.clean_unbind_oauth_success=Tous unbind OAuthes ont été supprimés avec succès.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Configuration du Journal
 config.log_file_root_path=Emplacement Racine du Fichier Journal
 config.log_mode=Mode

+ 20 - 8
conf/locale/locale_gl-ES.ini

@@ -43,6 +43,10 @@ issues=Incidencias
 
 cancel=Cancelar
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalación
 title=Pasos da instalación por primeira vez
@@ -260,8 +264,7 @@ following=Seguindo
 follow=Seguir
 unfollow=Deixar de seguir
 
-form.name_reserved=O usuario '%s' está reservado.
-form.name_pattern_not_allowed=O patrón de nome de usuario '%s' non está permitido.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Perfil
@@ -427,8 +430,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=El propietario ha alcanzado el límite máximo de %d repositorios creados.=O propietario acadou o límite máximo de %d repositorios creados.
-form.name_reserved=El nombre del repositorio '%s' está reservado.=O nome do repositorio '%s' está reservado.
-form.name_pattern_not_allowed=El patrón del nombre del repositorio '%s' no está permitido.=O patrón do nome do repositorio '%s' non está permitido.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Requiere autorización=Require autorización
 migrate_type=Tipo de migración
@@ -787,8 +789,10 @@ settings.collaborator_deletion_desc=Este usuario non poderá colaborar neste rep
 settings.remove_collaborator_success=O colaborador foi eliminado.
 settings.search_user_placeholder=Buscar usuario...
 settings.org_not_allowed_to_be_collaborator=As organizacións non teñen permitido ser engadidas como colaboradores.
+settings.hooks_desc=Os Webhooks permiten a servizos externos recibir notificacións cando sucedan certos eventos en Gogs. Cando sucedan os eventos especificados, enviaremos unha petición POST a cada unha das URLs indicadas. Para obter máis información, consulta a nosa <a target="_blank" href="%s">Guía de Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Engadir Webhook
-settings.hooks_desc=Os Webhooks permiten a servizos externos recibir notificacións cando sucedan certos eventos en GIN. Cando sucedan os eventos especificados, enviaremos unha petición POST a cada unha das URLs indicadas. Para obter máis información, consulta a nosa <a target="_blank" href="%s">Guía de Webhooks</a>.
 settings.webhook_deletion=Eliminar Webhook
 settings.webhook_deletion_desc=Ao borrar este webhook eliminarase a súa información e todo o seu historial. Desexa continuar?
 settings.webhook_deletion_success=Webhook eliminado con éxito!
@@ -802,6 +806,8 @@ settings.webhook.response=Resposta
 settings.webhook.headers=Encabezado
 settings.webhook.payload=Payload
 settings.webhook.body=Corpo da mensaxe
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Os Git Hooks son unha funcionalidade do propio Git, podes editar os ficheiros dos hooks soportados na seguinte lista para aplicar operacións personalizadas.
 settings.githook_edit_desc=Se o hook non está activo, mostrarase contido de exemplo. Deixar o contido baleiro deshabilitará este hook.
 settings.githook_name=Nome do Hook
@@ -928,9 +934,8 @@ team_name_helper=Utiliza este nome para mencionar este equipo nas conversas.
 team_desc_helper=En que consiste este equipo?
 team_permission_desc=Que nivel de permisos debería ter este equipo?
 
-form.name_reserved=O nome da organización '%s' está reservado.
-form.name_pattern_not_allowed=O patrón de nome da organización '%s' non está permitido.
-form.team_name_reserved=Team name '%s' is reserved.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Configuración
 settings.options=Opcións
@@ -1014,6 +1019,7 @@ dashboard.system_status=Estado do Monitor do Sistema
 dashboard.statistic_info=A base de datos de GIN contén <b>%d</b> usuarios, <b>%d</b> organizacións, <b>%d</b> claves públicas, <b>%d</b> repositorios, <b>%d</b> vixiados, <b>%d</b> destacados, <b>%d</b> accións, <b>%d</b> accesos, <b>%d</b> incidencias, <b>%d</b> comentarios, <b>%d</b> contas de redes sociais, <b>%d</b> seguidores, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> fontes de login, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> etiquetas, <b>%d</b> hooks, <b>%d</b> equipos, <b>%d</b> tarefas actualizadas, <b>%d</b> adxuntos.
 dashboard.operation_name=Nome da operación
 dashboard.operation_switch=Interruptor
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Executar
 dashboard.clean_unbind_oauth=Limpar solicitudes de OAuth sen confirmar
 dashboard.clean_unbind_oauth_success=As solicitudes de OAuth sen confirmar elimináronse correctamente.
@@ -1226,6 +1232,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1325,6 +1333,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Configuración do log
 config.log_file_root_path=Ruta dos ficheiros de log
 config.log_mode=Mode

+ 20 - 8
conf/locale/locale_hu-HU.ini

@@ -43,6 +43,10 @@ issues=Problémák
 
 cancel=Mégse
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Telepítés
 title=Telepítés első indításkor
@@ -259,8 +263,7 @@ following=Követve
 follow=Követés
 unfollow=Követés törlése
 
-form.name_reserved='%s' felhasználónév már foglalt.
-form.name_pattern_not_allowed=A felhasználónév ('%s') nem engedélyezett.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Tároló leírása. Maximum 512 karakter hosszúságú.
 repo_description_length=Rendelkezésre álló karakterek
 
 form.reach_limit_of_creation=A tulajdonos túllépte a maximum létrehozható tárolók számát (%d).
-form.name_reserved=Ez a tároló név ('%s') le van foglalva.
-form.name_pattern_not_allowed=Ez a tároló név ('%s') nem megengedett.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Hitelesítés szükséges
 migrate_type=Migráció típusa
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Ennek a felhasználónak nem lesz joga közr
 settings.remove_collaborator_success=Az eggyüttműködő eltávolítva.
 settings.search_user_placeholder=Felhasználók keresése...
 settings.org_not_allowed_to_be_collaborator=Szervezet hozzáadása együttműködőként nem engedélyezett.
-settings.add_webhook=Webhook hozzáadása
 settings.hooks_desc=A Webhook-ok olyanok, mint az alapvető HTTP POST esemény triggerek. Amikor valami történik a Gogsban, akkor küldünk róla értesítést a címre amit beállítasz. Többet olvashatsz erről a <a target="_blank" href="%s">Webhooks Guide-ban</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Webhook hozzáadása
 settings.webhook_deletion=Webhook Törlése
 settings.webhook_deletion_desc=Ennek a Webhook-nak a törlése eltávolít róla minden információt, és a korábbi kézbesítéseknek a naplóját is. Biztosan folytatja?
 settings.webhook_deletion_success=Webhook sikeresen törölve lett!
@@ -801,6 +805,8 @@ settings.webhook.response=Válasz
 settings.webhook.headers=Fejlécek
 settings.webhook.payload=Tartalom
 settings.webhook.body=Törzs
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=A GIT hook-okat maga a Git működteti, szerkesztheted a támogatott hook-ok fájljait a következő listában hogy egyéni műveleteket is végezzenek.
 settings.githook_edit_desc=Ha a hook nincs aktiválva, akkor egy minta sablon lesz mutatva. Ha a tartalmát üresen hagyja, akkor ez a hook ki lesz kapcsolva.
 settings.githook_name=Hook megnevezés
@@ -927,9 +933,8 @@ team_name_helper=Ezzel a névvel tudsz majd a csapatra hivatkozni.
 team_desc_helper=Miről szól ez a csapat?
 team_permission_desc=Milyen jogosultsága legyen ennek a csapatnak?
 
-form.name_reserved=Ez a szervezetnév ('%s') le van foglalva.
-form.name_pattern_not_allowed=A szervezetnév ('%s') nem engedélyezett.
-form.team_name_reserved=A csoportnév ('%s') a rendszer számára van fenntartva.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Beállítások
 settings.options=Opciók
@@ -1013,6 +1018,7 @@ dashboard.system_status=Rendszerfigyelő Állapota
 dashboard.statistic_info=Az adatbázisban található: <b>%d</b> felhasználó, <b>%d</b> szervezet, <b>%d</b> publikus kulcs, <b>%d</b> tároló, <b>%d</b> figyelő, <b>%d</b> csillagozás, <b>%d</b> művelet, <b>%d</b> hozzáférés, <b>%d</b> probléma, <b>%d</b> megjegyzés, <b>%d</b> közösségi fiók, <b>%d</b> követő, <b>%d</b> tükör, <b>%d</b> kiadás, <b>%d</b> authentikáció, <b>%d</b> webhook, <b>%d</b> mérföldkő, <b>%d</b> cimke, <b>%d</b> hook feladat, <b>%d</b> csoport, <b>%d</b> frissítési feladat, <b>%d</b> csatolmány.
 dashboard.operation_name=Művelet neve
 dashboard.operation_switch=Átváltás
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Futtatás
 dashboard.clean_unbind_oauth=A nem használt OAuthok kitakarítása
 dashboard.clean_unbind_oauth_success=Minden nem használt OAuth sikeresen kitakarítva.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Naplózás beállítása
 config.log_file_root_path=Naplófájl gyökérútvonal
 config.log_mode=Mód

+ 20 - 8
conf/locale/locale_id-ID.ini

@@ -43,6 +43,10 @@ issues=Masalah
 
 cancel=Batal
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalasi
 title=Langkah-langkah untuk Menjalankan Pertama Kali
@@ -259,8 +263,7 @@ following=Mengikuti
 follow=Ikuti
 unfollow=Berhenti mengikuti
 
-form.name_reserved=Username '%s' tidak tersedia.
-form.name_pattern_not_allowed=Pola username '%s' tidak diperbolehkan.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Deskripsi repositori maksimal 512 karakter.
 repo_description_length=Karakter tersedia
 
 form.reach_limit_of_creation=Pemiliknya telah mencapai batas pembuatan maksimum %d repositori.
-form.name_reserved=Nama repositori '%s' dicadangkan.
-form.name_pattern_not_allowed=Pola nama repositori '%s' tidak diperbolehkan.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Butuh Otorisasi
 migrate_type=Jenis migrasi
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Pengguna ini tidak lagi memiliki akses kolab
 settings.remove_collaborator_success=Kolaborator telah dihapus.
 settings.search_user_placeholder=Cari pengguna...
 settings.org_not_allowed_to_be_collaborator=Organisasi tidak diperbolehkan untuk ditambahkan sebagai kolaborator.
-settings.add_webhook=Tambahkan Webhook
 settings.hooks_desc=Webhooks seperti pemicu peristiwa HTTP POST dasar. Kapan pun terjadi sesuatu di Gog, kami akan menangani pemberitahuan tersebut ke host target yang Anda tentukan. Pelajari lebih lanjut di <a target="_blank" href=" %s "> Panduan Webhooks </a> ini.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Tambahkan Webhook
 settings.webhook_deletion=Hapus Webhook
 settings.webhook_deletion_desc=Hapus halaman web ini akan menghapus informasinya dan semua riwayat pengiriman. Apakah Anda ingin melanjutkan?
 settings.webhook_deletion_success=Webhook telah berhasil dihapus!
@@ -801,6 +805,8 @@ settings.webhook.response=Tanggapan
 settings.webhook.headers=Header
 settings.webhook.payload=Payload
 settings.webhook.body=Tubuh
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git Hooks didukung oleh Git itu sendiri, Anda dapat mengedit file kait yang didukung dalam daftar di bawah untuk melakukan operasi kustom.
 settings.githook_edit_desc=Jika hook tidak aktif, konten sampel akan disajikan. Meninggalkan konten ke nilai kosong akan menonaktifkan hook ini.
 settings.githook_name=Nama Hook
@@ -927,9 +933,8 @@ team_name_helper=Anda akan menggunakan nama ini lagi tim ini dalam percakapan.
 team_desc_helper=Apa tentang semua tim ini?
 team_permission_desc=Apa tingkat izin ini harus?
 
-form.name_reserved=Nama organisasi %s" di sediakan.
-form.name_pattern_not_allowed=Organization name pattern '%s' is not allowed.
-form.team_name_reserved=Team name '%s' is reserved.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Pengaturan
 settings.options=Opsi
@@ -1013,6 +1018,7 @@ dashboard.system_status=Status Monitor Sistem
 dashboard.statistic_info=GogsDatabase memiliki <b>%d</b> pengguna, <b>%d</b> organisasi, <b>%d</b> kunci publik, <b>%d</b> repositori, <b>%d</b> jamtangan, <b>%d</b> bintang, <b>%d</b>actions, <b>%d</b> akses, <b>%d</b> isu, <b>%d</b> komentar, <b>%d</b> akun sosial, <b>%d</b> berikut, <b>%d<b> mirror, <b>%d</b> rilis, <b>%d</b> sumber masuk, <b>%d</b> webhooks, <b>%d</b> tonggak,<b>%d</b> label, <b>%d</b> tugas hook, <b>%d</b> tim, <b>%d</b> memperbarui tugas, <b>%d</b> lampiran.
 dashboard.operation_name=Nama operasi
 dashboard.operation_switch=Beralih
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Menjalankan
 dashboard.clean_unbind_oauth=Bersihkan OAuth yang tidak terikat
 dashboard.clean_unbind_oauth_success=Semua unbind OAuthes telah berhasil dihapus.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Log configuration
 config.log_file_root_path=Log file root path
 config.log_mode=Mode

+ 20 - 8
conf/locale/locale_it-IT.ini

@@ -43,6 +43,10 @@ issues=Problemi
 
 cancel=Annulla
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Installazione
 title=Passi d'installazione per il primo avvio
@@ -259,8 +263,7 @@ following=Seguiti
 follow=Segui
 unfollow=Non seguire più
 
-form.name_reserved=L'username '%s' è riservato.
-form.name_pattern_not_allowed=La struttura del nome utente '%s' non è consentita.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profilo
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Caratteri disponibili
 
 form.reach_limit_of_creation=Il proprietario ha raggiunto il limite massimo di %d repository creati.
-form.name_reserved=Il nome repository %s è riservato.
-form.name_pattern_not_allowed=La struttura del nome del repository %s non è consentita.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Richiesta di autorizzazione
 migrate_type=Tipo di migrazione
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Questo utente non potrà più collaborare a
 settings.remove_collaborator_success=Il collaboratore è stato rimosso.
 settings.search_user_placeholder=Cerca utente...
 settings.org_not_allowed_to_be_collaborator=Un'organizzazione non può essere aggiunta come collaboratore.
+settings.hooks_desc=I Webhooks sono molto simili a un basilare evento trigger HTTP POST. Ogni volta che qualcosa si verifica in Gogs, tratteremo la notifica all'host di destinazione specificato. Ulteriori informazioni in questa <a target="_blank" href="%s">Guida ai Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Aggiungi Webhook
-settings.hooks_desc=I Webhooks sono molto simili a un basilare evento trigger HTTP POST. Ogni volta che qualcosa si verifica in GIN, tratteremo la notifica all'host di destinazione specificato. Ulteriori informazioni in questa <a target="_blank" href="%s">Guida ai Webhooks</a>.
 settings.webhook_deletion=Elimina Webhook
 settings.webhook_deletion_desc=Delete this webhook will remove its information and all delivery history. Do you want to continue?
 settings.webhook_deletion_success=Il Webhook è stato eliminato con successo!
@@ -801,6 +805,8 @@ settings.webhook.response=Risposta
 settings.webhook.headers=Headers
 settings.webhook.payload=Payload
 settings.webhook.body=Body
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Gli Hooks di Git sono una funzionalità di Git stesso, puoi modificare i file degli hooks supportati nell'elenco qui sotto per compiere azioni personalizzate.
 settings.githook_edit_desc=Se l'hook è inattivo, sarà presentato un contenuto esempio. Lasciando il contenuto vuoto disattiverai questo hook.
 settings.githook_name=Nome hook
@@ -927,9 +933,8 @@ team_name_helper=Verrà usato questo nome per riferirsi a questo team nella conv
 team_desc_helper=In cosa consiste questo team?
 team_permission_desc=Quale livello di autorizzazione dovrebbe avere questa squadra?
 
-form.name_reserved=Il nome organizzazione '%s' è riservato.
-form.name_pattern_not_allowed=La struttura del nome dell'organizzazione '%s' non è consentita.
-form.team_name_reserved=Non puoi utilizzare '%s' come nome del Team.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Impostazioni
 settings.options=Opzioni
@@ -1013,6 +1018,7 @@ dashboard.system_status=Stato del Monitor di Sistema
 dashboard.statistic_info=Il database di GIN ha <b>%d</b> utenti, <b>%d</b> organizzazioni, <b>%d</b> chiavi pubbliche, <b>%d</b> repository, <b>%d</b> utenti che seguono, <b>%d</b> voti, <b>%d</b> azioni, <b>%d</b> accessi, <b>%d</b> problemi, <b>%d</b> commenti, <b>%d</b> account sociali, <b>%d</b> utenti seguiti, <b>%d</b> mirror, <b>%d</b> rilasci, <b>%d</b> fonti di accesso, <b>%d</b> webhook, <b>%d</b> traguardi, <b>%d</b> etichette, <b>%d</b> incarichi hook, <b>%d</b> team, <b>%d</b> attività di aggiornamento, <b>%d</b> allegati.
 dashboard.operation_name=Nome Operazione
 dashboard.operation_switch=Cambia
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Esegui
 dashboard.clean_unbind_oauth=Pulire OAuthes non associati
 dashboard.clean_unbind_oauth_success=Tutti gli OAuthes non associati eliminati con successo.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Configurazione Log
 config.log_file_root_path=Percorso Root del File di Log
 config.log_mode=Modalità

+ 62 - 50
conf/locale/locale_ja-JP.ini

@@ -43,6 +43,10 @@ issues=課題
 
 cancel=キャンセル
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=インストール
 title=インストールをする前に必要な準備をしましょう
@@ -121,7 +125,7 @@ run_user_not_match=実行ユーザーは現在のユーザーではありませ
 smtp_host_missing_port=SMTPホストのポートが見つかりません。
 invalid_smtp_from=SMTP From フィールドの値が有効ではありません: %v
 save_config_failed=構成の保存に失敗した: %v
-init_failed=Failed to initialize application: %v
+init_failed=アプリケーションの初期化に失敗しました: %v
 invalid_admin_setting=管理者アカウントの設定が無効です: %v
 install_success=ようこそ!我々はあなたが GIN を選んでくれて嬉しいです!楽しみましょう!
 invalid_log_root_path=リポジトリのルート パスが無効です: %v
@@ -259,8 +263,7 @@ following=フォロー
 follow=フォロー
 unfollow=フォロー解除
 
-form.name_reserved=ユーザー名 '%s' は使用されています。
-form.name_pattern_not_allowed=ユーザー名のパターン '%s' は許可されていません。
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=プロフィール
@@ -426,8 +429,7 @@ repo_description_helper=リポジトリの説明 (512文字以内)
 repo_description_length=利用可能な文字
 
 form.reach_limit_of_creation=リポジトリの最大作成数 %d にすでに達しています。
-form.name_reserved=リポジトリ名 '%s' は使用されています。
-form.name_pattern_not_allowed=リポジトリ名に '%s' は使用できません。
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=認証が必要
 migrate_type=マイグレーションの種類
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=削除後、このユーザーはこのリ
 settings.remove_collaborator_success=共同編集者が削除されました。
 settings.search_user_placeholder=ユーザーを検索...
 settings.org_not_allowed_to_be_collaborator=組織を共同編集者として追加することはできません。
+settings.hooks_desc=Webhooksは、Gogsで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Webhook を追加
-settings.hooks_desc=Webhooksは、GINで特定のイベントの発生時に指定された外部サービスに通知を許可します。イベントが発生すると、それぞれ指定されたUrlに、POSTリクエストが送られます。詳細はこちらのの <a target="_blank"href="%s"> Webhooks ガイド</a>をご覧ください。
 settings.webhook_deletion=Webhook を削除
 settings.webhook_deletion_desc=このwebhookを削除すると、すべての情報と配信履歴が削除されます。続行しますか?
 settings.webhook_deletion_success=Webhook が正常に削除されました。
@@ -801,6 +805,8 @@ settings.webhook.response=レスポンス
 settings.webhook.headers=ヘッダ
 settings.webhook.payload=ペイロード
 settings.webhook.body=ボディ
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git のフックは Git 自体によって提供されています。以下のリストのファイルを編集して、サポートされているフックのカスタム操作を適用することができます。
 settings.githook_edit_desc=もしフックがアクティブではない場合は、サンプルコンテンツが表示されます。コンテンツを空白にするにはこのフックを無効にします。
 settings.githook_name=フックの名前
@@ -927,9 +933,8 @@ team_name_helper=会話の時、この名前を使用しチーム名を表明し
 team_desc_helper=このチームに関する全ての情報は?
 team_permission_desc=このチームに必要な権限レベルは?
 
-form.name_reserved=組織名 '%s' は使用されています。
-form.name_pattern_not_allowed=組織名のパターン '%s' は許可されていません。
-form.team_name_reserved=チーム名 '%s' は使用されています。
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=設定
 settings.options=オプション
@@ -1001,10 +1006,10 @@ first_page=First
 last_page=Last
 total=合計: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
+dashboard.build_info=ビルド情報
+dashboard.app_ver=アプリケーションのバージョン
+dashboard.git_version=Git バージョン
+dashboard.go_version=Go バージョン
 dashboard.build_time=Build time
 dashboard.build_commit=Build commit
 dashboard.statistic=統計
@@ -1013,6 +1018,7 @@ dashboard.system_status=システム モニターのステータス
 dashboard.statistic_info=GIN データベースは <b>%d</b> 人のユーザー、<b>%d</b> 個の組織、<b>%d</b> 個の公開鍵、<b>%d</b> 個のリポジトリ、<b>%d</b> 個のウォッチ、<b>%d</b> 個のスター、<b>%d</b> 回のアクション、<b>%d</b> 回のアクセス、<b>%d</b> 個の課題、<b>%d</b> 個のコメント、<b>%d</b> 個のソーシャルアカウント、<b>%d</b> 個のフォロー、<b>%d</b> 個のミラー、<b>%d</b> 個のリリース、<b>%d</b> 個のログイン元、<b>%d</b> 個のwebフック、<b>%d</b> 個のマイルストーン、<b>%d</b> 個のラベル、<b>%d</b> 個のフックタスク、<b>%d</b> 個のチーム、<b>%d</b> 更新タスク、<b>%d</b> 個の添付ファイルの情報を保持しています。
 dashboard.operation_name=操作の名前
 dashboard.operation_switch=スイッチ
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=実行
 dashboard.clean_unbind_oauth=結び付けられていない OAuth をクリーン
 dashboard.clean_unbind_oauth_success=結び付けられていない全ての OAuth を正常に削除しました。
@@ -1162,22 +1168,22 @@ auths.github_api_endpoint=APIエンドポイント
 
 config.not_set=(未設定)
 config.server_config=サーバーの構成
-config.brand_name=Brand name
+config.brand_name=ブランド名
 config.run_user=実行ユーザー
 config.run_mode=実行モード
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
-config.server.unix_socket_permission=Unix socket permission
+config.server.external_url=外部 URL 
+config.server.domain=ドメイン
+config.server.protocol=プロトコル
+config.server.http_addr=HTTPアドレス
+config.server.http_port=HTTP ポート
+config.server.cert_file=証明書ファイル
+config.server.key_file=キーファイル
+config.server.tls_min_version=最小TLSバージョン
+config.server.unix_socket_permission=Unixソケットの権限
 config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
-config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
+config.server.offline_mode=オフラインモード
+config.server.disable_router_log=ルーターログを無効にする
+config.server.enable_gzip=Gzip を有効化
 config.server.app_data_path=Application data path
 config.server.load_assets_from_disk=Load assets from disk
 config.server.landing_url=Landing URL
@@ -1189,22 +1195,22 @@ config.ssh.port=Exposed port
 config.ssh.root_path=Root path
 config.ssh.keygen_path=Keygen path
 config.ssh.key_test_path=Key test path
-config.ssh.minimum_key_size_check=Minimum key size check
-config.ssh.minimum_key_sizes=Minimum key sizes
+config.ssh.minimum_key_size_check=最小キーサイズチェック
+config.ssh.minimum_key_sizes=最小キーサイズ
 config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
-config.ssh.start_builtin_server=Start builtin server
-config.ssh.listen_host=Listen host
-config.ssh.listen_port=Listen port
+config.ssh.start_builtin_server=内蔵サーバーを起動
+config.ssh.listen_host=待受ホスト
+config.ssh.listen_port=待受ポート
 config.ssh.server_ciphers=Server ciphers
 
 config.repo_config=リポジトリの設定
 config.repo.root_path=Root path
 config.repo.script_type=Script type
 config.repo.ansi_chatset=ANSI charset
-config.repo.force_private=Force private
-config.repo.max_creation_limit=Max creation limit
+config.repo.force_private=非公開にする
+config.repo.max_creation_limit=最大作成数
 config.repo.preferred_licenses=Preferred licenses
-config.repo.disable_http_git=Disable HTTP Git
+config.repo.disable_http_git=HTTP Git の無効化
 config.repo.enable_local_path_migration=Enable local path migration
 config.repo.enable_raw_file_render_mode=Enable raw file render mode
 config.repo.commits_fetch_concurrency=Commits fetch concurrency
@@ -1221,16 +1227,18 @@ config.db.type=Type
 config.db.host=Host
 config.db.name=Name
 config.db.user=User
-config.db.ssl_mode=SSL mode
-config.db.ssl_mode_helper=(for "postgres" only)
+config.db.ssl_mode=SSL モード
+config.db.ssl_mode_helper=("postgres"のみ)
 config.db.path=Path
-config.db.path_helper=(for "sqlite3"only)
+config.db.path_helper=("sqlite3"のみ)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
-config.security_config=Security configuration
+config.security_config=セキュリティ設定
 config.security.login_remember_days=Login remember days
 config.security.cookie_remember_name=Remember cookie
 config.security.cookie_username=Username cookie
-config.security.cookie_secure=Enable secure cookie
+config.security.cookie_secure=セキュアなクッキーを有効にする
 config.security.reverse_proxy_auth_user=Reverse proxy authentication header
 config.security.enable_login_status_cookie=Enable login status cookie
 config.security.login_status_cookie_name=Login status cookie
@@ -1271,14 +1279,14 @@ config.session_config=セッションの設定
 config.session.provider=Provider
 config.session.provider_config=Provider config
 config.session.cookie_name=Cookie
-config.session.https_only=HTTPS only
-config.session.gc_interval=GC interval
+config.session.https_only=HTTPS のみ
+config.session.gc_interval=GC 間隔
 config.session.max_life_time=Max life time
 config.session.csrf_cookie_name=CSRF cookie
 
 config.cache_config=キャッシュの設定
 config.cache.adapter=Adapter
-config.cache.interval=GC interval
+config.cache.interval=GC 間隔
 config.cache.host=Host
 
 config.http_config=HTTP の設定
@@ -1288,23 +1296,23 @@ config.attachment_config=Attachment configuration
 config.attachment.enabled=Enabled
 config.attachment.path=Path
 config.attachment.allowed_types=Allowed types
-config.attachment.max_size=Size limit
-config.attachment.max_files=Files limit
+config.attachment.max_size=サイズ制限
+config.attachment.max_files=ファイルの制限
 
-config.release_config=Release configuration
+config.release_config=リリースの構成
 config.release.attachment.enabled=Attachment enabled
 config.release.attachment.allowed_types=Attachment allowed types
-config.release.attachment.max_size=Attachment size limit
+config.release.attachment.max_size=添付ファイルのサイズ制限
 config.release.attachment.max_files=Attachment files limit
 
 config.picture_config=画像の設定
 config.picture.avatar_upload_path=User avatar upload path
 config.picture.repo_avatar_upload_path=Repository avatar upload path
 config.picture.gravatar_source=Gravatar source
-config.picture.disable_gravatar=Disable Gravatar
+config.picture.disable_gravatar=Gravatarを無効にする
 config.picture.enable_federated_avatar=Enable federated avatars
 
-config.mirror_config=Mirror configuration
+config.mirror_config=ミラー構成
 config.mirror.default_interval=Default interval
 
 config.webhook_config=Webhook設定
@@ -1317,13 +1325,17 @@ config.git.disable_diff_highlight=Disable diff syntax highlight
 config.git.max_diff_lines=Diff lines limit (for a single file)
 config.git.max_diff_line_characters=Diff characters limit (for a single line)
 config.git.max_diff_files=Diff files limit (for a single diff)
-config.git.gc_args=GC arguments
+config.git.gc_args=GC の引数
 config.git.migrate_timeout=Migration timeout
 config.git.mirror_timeout=Mirror fetch timeout
 config.git.clone_timeout=Clone timeout
-config.git.pull_timeout=Pull timeout
+config.git.pull_timeout=Pull タイムアウト
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=ログの設定
 config.log_file_root_path=ログファイルのルートパス
 config.log_mode=モード

+ 51 - 39
conf/locale/locale_ko-KR.ini

@@ -43,6 +43,10 @@ issues=이슈
 
 cancel=취소
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=설치
 title=첫 실행을 위한 설치단계
@@ -259,8 +263,7 @@ following=팔로우 중
 follow=추적하기
 unfollow=추적해제
 
-form.name_reserved=사용자 이름 '%s'는 예약되어 있습니다.
-form.name_pattern_not_allowed=사용자 이름 패턴 '%s'은 허용 되지 않습니다.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=프로필
@@ -426,8 +429,7 @@ repo_description_helper=저장소 설명.최대 512길이의 문자열이 가능
 repo_description_length=가능한 문자열입니다.
 
 form.reach_limit_of_creation=소유자가 저장소 만들기 최대 제한에 (%d개) 도달했습니다.
-form.name_reserved=저장소 이름 '%s'은 예약 되어 있습니다.
-form.name_pattern_not_allowed=저장소 이름 패턴 '%s'은 허용 되지 않습니다.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=인증 필요
 migrate_type=마이그레이션 유형
@@ -787,8 +789,10 @@ settings.collaborator_deletion_desc=이 사용자는 더 이상 이 저장소의
 settings.remove_collaborator_success=공동작업자가 삭제 되었습니다.
 settings.search_user_placeholder=사용자 검색...
 settings.org_not_allowed_to_be_collaborator=조직을 공동 작업자로 추가할 수 없습니다.
-settings.add_webhook=Webhook 추가
 settings.hooks_desc=웹후크는 기본적인 HTTP POST 이벤트 트리거입니다. Gogs에서 무슨 일이 발생할 때마다, 지정한 대상 호스트에 알림을 보냅니다. <a target="_blank" href="%s">웹후크 안내서</a>에서 자세히 알아보십시오.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Webhook 추가
 settings.webhook_deletion=Webhook 삭제
 settings.webhook_deletion_desc=이 웹훅을 삭제하면 정보와 모든 전송기록이 제거됩니다. 계속 하시겠습니까?
 settings.webhook_deletion_success=Webhook을 성공적으로 삭제했습니다!
@@ -802,6 +806,8 @@ settings.webhook.response=응답
 settings.webhook.headers=제목
 settings.webhook.payload=페이로드
 settings.webhook.body=본문
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git Hooks는 Git 자체에서 제공되며, 아래 목록에서 지원되는 후크 파일을 편집하여 사용자 정의 작업을 수행 할 수 있습니다.
 settings.githook_edit_desc=후크가 비활성인 경우 샘플 콘텐츠가 표시됩니다. 내용을 빈 값으로 두면 이 훅은 비활성화됩니다.
 settings.githook_name=Hook 이름
@@ -928,9 +934,8 @@ team_name_helper=대화에서 이 팀을 언급할 때 이 이름을 사용합
 team_desc_helper=이 팀은 무엇입니까?
 team_permission_desc=이 팀이 가진 권한이 무엇입니까?
 
-form.name_reserved=조직이름 '%s'는 예약되어있습니다.
-form.name_pattern_not_allowed=조직이름 패턴 '%s'는 허용되지 않았습니다.
-form.team_name_reserved=팀명  '%s'는 예약되어 있습니다.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=설정
 settings.options=옵션
@@ -1014,6 +1019,7 @@ dashboard.system_status=시스템 모니터 상태
 dashboard.statistic_info=Gogs 데이터베이스에는 <b>%d</b>명의 사용자, <b>%d</b> 조직, <b>%d</b> 공개 키, <b>%d</b> 저장소, <b>%d</b> 주시, <b>%d</b> 별, <b>%d</b> 활동, <b>%d</b> 접근, <b>%d</b> 이슈, <b>%d</b> 댓글, <b>%d</b> 소셜 계정, <b>%d</b> 팔로우, <b>%d</b> 미러, <b>%d</b> 릴리즈, <b>%d</b> 로그인 소스, <b>%d</b> 웹훅, <b>%d</b> 마일스톤, <b>%d</b> 라벨, <b>%d</b> 훅 태스크, <b>%d</b> 팀, <b>%d</b> 업데이트 태스크, <b>%d</b> 첨부파일이 있습니다.
 dashboard.operation_name=작업 명
 dashboard.operation_switch=스위치
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=실행
 dashboard.clean_unbind_oauth=연결되지 않은 OAuth들을 정리
 dashboard.clean_unbind_oauth_success=연결되지 않은 모든 OAuth들이 성공적으로 삭제되었습니다.
@@ -1226,6 +1232,8 @@ config.db.ssl_mode=SSL 모드
 config.db.ssl_mode_helper=("postgres" 전용)
 config.db.path=경로
 config.db.path_helper={"sqlite3" 전용)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=보안 설정
 config.security.login_remember_days=로그인 기억 날짜
@@ -1269,61 +1277,65 @@ config.user_config=User configuration
 config.user.enable_email_notify=Enable email notification
 
 config.session_config=세션 설정
-config.session.provider=Provider
-config.session.provider_config=Provider config
-config.session.cookie_name=Cookie
-config.session.https_only=HTTPS only
-config.session.gc_interval=GC interval
+config.session.provider=공급자
+config.session.provider_config=공급자 설정
+config.session.cookie_name=쿠키
+config.session.https_only=HTTPS
+config.session.gc_interval=GC 간격
 config.session.max_life_time=Max life time
-config.session.csrf_cookie_name=CSRF cookie
+config.session.csrf_cookie_name=CSRF 쿠키
 
 config.cache_config=캐시 설정
 config.cache.adapter=Adapter
-config.cache.interval=GC interval
-config.cache.host=Host
+config.cache.interval=GC 간격
+config.cache.host=호스트
 
 config.http_config=HTTP 설정
 config.http.access_control_allow_origin=Access control allow origin
 
 config.attachment_config=Attachment configuration
-config.attachment.enabled=Enabled
-config.attachment.path=Path
-config.attachment.allowed_types=Allowed types
-config.attachment.max_size=Size limit
-config.attachment.max_files=Files limit
-
-config.release_config=Release configuration
-config.release.attachment.enabled=Attachment enabled
-config.release.attachment.allowed_types=Attachment allowed types
-config.release.attachment.max_size=Attachment size limit
-config.release.attachment.max_files=Attachment files limit
+config.attachment.enabled=활성화됨
+config.attachment.path=경로
+config.attachment.allowed_types=허용 유형
+config.attachment.max_size=크기 제한
+config.attachment.max_files=파일 제한
+
+config.release_config=릴리즈 설정
+config.release.attachment.enabled=첨부 파일 활성화됨
+config.release.attachment.allowed_types=허용되는 첨부 파일 유형
+config.release.attachment.max_size=첨부 파일 크기 제한
+config.release.attachment.max_files=첨부 파일 제한
 
 config.picture_config=이미지 설정
-config.picture.avatar_upload_path=User avatar upload path
+config.picture.avatar_upload_path=사용자 아바타 업로드 경로
 config.picture.repo_avatar_upload_path=Repository avatar upload path
 config.picture.gravatar_source=Gravatar source
 config.picture.disable_gravatar=Disable Gravatar
 config.picture.enable_federated_avatar=Enable federated avatars
 
 config.mirror_config=Mirror configuration
-config.mirror.default_interval=Default interval
+config.mirror.default_interval=기본 간격
 
 config.webhook_config=웹훅 설정
-config.webhook.types=Types
-config.webhook.deliver_timeout=Deliver timeout
-config.webhook.skip_tls_verify=Skip TLS verify
+config.webhook.types=유형
+config.webhook.deliver_timeout=배달 제한 시간
+config.webhook.skip_tls_verify=TLS 검증 건너뛰기
 
 config.git_config=깃 설정
 config.git.disable_diff_highlight=Disable diff syntax highlight
 config.git.max_diff_lines=Diff lines limit (for a single file)
 config.git.max_diff_line_characters=Diff characters limit (for a single line)
 config.git.max_diff_files=Diff files limit (for a single diff)
-config.git.gc_args=GC arguments
-config.git.migrate_timeout=Migration timeout
-config.git.mirror_timeout=Mirror fetch timeout
-config.git.clone_timeout=Clone timeout
-config.git.pull_timeout=Pull timeout
-config.git.gc_timeout=GC timeout
+config.git.gc_args=GC 인수
+config.git.migrate_timeout=마이그레이션 제한 시간
+config.git.mirror_timeout=미러 페치 제한 시간
+config.git.clone_timeout=클론 제한 시간
+config.git.pull_timeout=풀 제한 시간
+config.git.gc_timeout=GC 제한 시간
+
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
 
 config.log_config=로그 설정
 config.log_file_root_path=로그 파일 최상위 경로
@@ -1398,7 +1410,7 @@ months=%d 달 %s
 years=%d 년 %s
 raw_seconds=초
 raw_minutes=분
-raw_hours=hours
+raw_hours=시간
 
 [dropzone]
 default_message=여기에 파일을 끌어 놓거나 클릭하여 업로드하세요.

+ 20 - 8
conf/locale/locale_lv-LV.ini

@@ -43,6 +43,10 @@ issues=Problēmas
 
 cancel=Atcelt
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalācija
 title=Instalācijas soļi pirmo reizi palaižot
@@ -259,8 +263,7 @@ following=Seko
 follow=Sekot
 unfollow=Nesekot
 
-form.name_reserved=Lietotāja vārds '%s' jau ir aizņemts.
-form.name_pattern_not_allowed=Lietotāja vārds '%s' nav atļauts.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profils
@@ -426,8 +429,7 @@ repo_description_helper=Repozitorija apraksts. Maksimālais garums 512 rakstzīm
 repo_description_length=Pieejamās rakstzīmes
 
 form.reach_limit_of_creation=Īpašnieks sasniedza maksimālu pieļaujamo (%d) izveidoto repozitoriju skaitu.
-form.name_reserved=Repozitorija nosaukums '%s' ir rezervēts.
-form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Nepieciešama autorizācija
 migrate_type=Migrācijas veids
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Šim lietotājam pēc dzēšanas vairs nebū
 settings.remove_collaborator_success=Līdzstrādnieks tika noņemts.
 settings.search_user_placeholder=Meklēt lietotāju...
 settings.org_not_allowed_to_be_collaborator=Organizāciju nav atļauts pievienot kā līdzstrādnieku.
-settings.add_webhook=Pievienot tīmekļa āķi
 settings.hooks_desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikomiem, kas notiek Git servisā. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Lai uzzinātu sīkāk skatieties <a target="_blank" href="%s">Tīmekļa āķu rokasgrāmatā</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Pievienot tīmekļa āķi
 settings.webhook_deletion=Dzēst tīmekļa āķi
 settings.webhook_deletion_desc=Dzēšot tīmekļa āķi tiks dzēsta visa ar to saistītā informācija un izpildes vēsture. Vai vēlaties turpināt?
 settings.webhook_deletion_success=Tīmekļa āķis tika veiksmīgi izdzēsts!
@@ -801,6 +805,8 @@ settings.webhook.response=Atbilde
 settings.webhook.headers=Galvenes
 settings.webhook.payload=Derīgā krava
 settings.webhook.body=Saturs
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git āķus apstrādā pats Git. Jūs varat labot atbalsīto āku failus sarakstā zemāk, lai veiktu pielāgotas darbības.
 settings.githook_edit_desc=Ja āķis nav aktīvs, tiks attēlots piemērs kā to izmantot. Atstājot āķa saturu tukšu, tas tiks atspējots.
 settings.githook_name=Āķa nosaukums
@@ -927,9 +933,8 @@ team_name_helper=Šo nosaukumu varēs izmantot, lai pieminētu komandu sarunās.
 team_desc_helper=Komandas apraksts
 team_permission_desc=Kādām tiesībām šai komandai būtu jābūt?
 
-form.name_reserved=Organizācijas nosaukums '%s' ir rezervēts.
-form.name_pattern_not_allowed=Organizācijas nosaukums '%s' nav atļauts.
-form.team_name_reserved=Komandas vārds '%s' ir rezervēts.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Iestatījumi
 settings.options=Opcijas
@@ -1013,6 +1018,7 @@ dashboard.system_status=Sistēmas uzraudzības statuss
 dashboard.statistic_info=GIN datu bāze satur <b>%d</b> lietotājus, <b>%d</b> organizācijas, <b>%d</b> publiskās atslēgas, <b>%d</b> repozitorijus, <b>%d</b> vērošanas, <b>%d</b> atzīmētas zvaigznītes, <b>%d</b> darbības, <b>%d</b> piekļuves, <b>%d</b> problēmas, <b>%d</b> komentārus, <b>%d</b> sociālos kontus, <b>%d</b> sekošanas, <b>%d</b> spoguļošanas, <b>%d</b> izlaides, <b>%d</b> login sources, <b>%d</b> tīmekļa āķus, <b>%d</b> starpposmus, <b>%d</b> etiķetes, <b>%d</b> āķu uzdevumus, <b>%d</b> komandas, <b>%d</b> labotus uzdevumus, <b>%d</b> pielikumus.
 dashboard.operation_name=Darbības nosaukums
 dashboard.operation_switch=Pārslēgt
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Palaist
 dashboard.clean_unbind_oauth=Notīrīt nesaistītās OAuth biļetes
 dashboard.clean_unbind_oauth_success=Visas nesaistītās OAuth biļetes tika veiksmīgi izdzēstas.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Žurnalizēšanas konfigurācija
 config.log_file_root_path=Žurnalizēšanas failu glabāšanas vieta
 config.log_mode=Režīms

+ 20 - 8
conf/locale/locale_nl-NL.ini

@@ -43,6 +43,10 @@ issues=Issues
 
 cancel=Annuleren
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Installatie
 title=Installatiestappen voor de eerste keer opstarten
@@ -259,8 +263,7 @@ following=Volgt
 follow=Volg
 unfollow=Niet meer volgen
 
-form.name_reserved=De gebruikersnaam '%s' is gereserveerd.
-form.name_pattern_not_allowed=Het gebruikersnaam patroon '%s' is niet toegestaan.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profiel
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=De eigenaar heeft maximale creatie limiet van %d repositories bereikt.
-form.name_reserved=Repositorienaam '%s' is gereserveerd.
-form.name_pattern_not_allowed=Repositorie naampatroon '%s' is niet toegestaan.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Autorisatie vereist
 migrate_type=Migratie type
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Deze gebruiker zal niet langer toegang hebbe
 settings.remove_collaborator_success=medewerker is verwijderd.
 settings.search_user_placeholder=Zoek gebruiker...
 settings.org_not_allowed_to_be_collaborator=De organisatie kan niet toegevoegd worden als medewerker.
+settings.hooks_desc=Webhooks dat de externe diensten om kennisgevingen te ontvangen wanneer bepaalde gebeurtenissen op Gogs plaatsvinden. Wanneer de opgegeven gebeurtenissen plaatsvinden, sturen we een POST-aanvraag naar elk van de URL's die u opgeeft. Meer informatie vindt u in onze <a target="_blank" href="%s"> Webhooks gids</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Webhook toevoegen
-settings.hooks_desc=Webhooks dat de externe diensten om kennisgevingen te ontvangen wanneer bepaalde gebeurtenissen op GIN plaatsvinden. Wanneer de opgegeven gebeurtenissen plaatsvinden, sturen we een POST-aanvraag naar elk van de URL's die u opgeeft. Meer informatie vindt u in onze <a target="_blank" href="%s"> Webhooks gids</a>.
 settings.webhook_deletion=Webhook verwijderen
 settings.webhook_deletion_desc=Verwijderen van deze webhook zal de informatie en alle geschiedenis verwijderen. Wilt u doorgaan?
 settings.webhook_deletion_success=Webhook is succesvol verwijderd!
@@ -801,6 +805,8 @@ settings.webhook.response=Antwoord
 settings.webhook.headers=Headers
 settings.webhook.payload=Lading
 settings.webhook.body=Inhoud
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git haken worden aangedreven door Git zelf, u kunt bestanden van ondersteunde haken in de lijst hieronder om aangepaste acties van toepassing bewerken.
 settings.githook_edit_desc=Als haak niet actief is, zal monster inhoud worden gepresenteerd. Verlof inhoud leeg zal deze haak uitschakelen.
 settings.githook_name=Haak naam
@@ -927,9 +933,8 @@ team_name_helper=U gebruikt deze naam om dit team te vermelden in conversaties.
 team_desc_helper=Waar gaat dit team doen?
 team_permission_desc=Welke privileges zou dit team moeten hebben?
 
-form.name_reserved=Organisatienaam '%s' is gereserveerd.
-form.name_pattern_not_allowed=Organisatie naampatroon '%s' is niet toegestaan.
-form.team_name_reserved=Team name '%s' is reserved.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Instellingen
 settings.options=Opties
@@ -1013,6 +1018,7 @@ dashboard.system_status=Status Systeemmonitor
 dashboard.statistic_info=GIN database heeft <b>%d</b> gebruikers, <b>%d</b> organisaties, <b>%d</b> openbare sleutels, <b>%d</b> repositories, <b>%d</b> volgers, <b>%d</b> sterren, <b>%d</b> acties, <b>%d</b> participanten, <b>%d</b> issues, <b>%d</b> reacties, <b>%d</b> sociale accounten, <b>%d</b> volgers, <b>%d</b> mirrors, <b>%d</b> publicaties, <b>%d</b> login bronnen, <b>%d</b> webhooks, <b>%d</b> mijlpalen, <b>%d</b> labels, <b>%d</b> hook taken, <b>%d</b> teams, <b>%d</b> bijgewerkte taken, <b>%d</b> bijlagen.
 dashboard.operation_name=Bewerking naam
 dashboard.operation_switch=Omschakelen
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Uitvoeren
 dashboard.clean_unbind_oauth=Clean unbound OAuths
 dashboard.clean_unbind_oauth_success=Alle OAuthes binding hebben verwijderd.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Logconfiguratie
 config.log_file_root_path=Log bestand basis pad
 config.log_mode=Mode

+ 49 - 37
conf/locale/locale_pl-PL.ini

@@ -43,6 +43,10 @@ issues=Problemy
 
 cancel=Anuluj
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalacja
 title=Kroki instalacyjne dla pierwszego uruchomienia
@@ -121,7 +125,7 @@ run_user_not_match=Użytkownik aplikacji nie jest aktualnym użytkownikiem: %s -
 smtp_host_missing_port=W SMTP Host brakuje portu w adresie.
 invalid_smtp_from=Pole SMTP OD nie jest prawidłowe: %v
 save_config_failed=Nie udało się zapisać konfiguracji: %v
-init_failed=Failed to initialize application: %v
+init_failed=Nie udało się zainicjować aplikacji: %v
 invalid_admin_setting=Nieprawidłowe ustawienia konta admina: %v
 install_success=Cześć! Cieszymy się, że wybierałeś GIN, baw się dobrze.
 invalid_log_root_path=Ścieżka dla logów jest niepoprawna: %v
@@ -259,8 +263,7 @@ following=Obserwowani
 follow=Obserwuj
 unfollow=Przestań obserwować
 
-form.name_reserved=Nazwa użytkownika „%s” jest zarezerwowana.
-form.name_pattern_not_allowed=Wzorzec nazwy użytkownika „%s” jest niedozwolony.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Opis repozytorium. Maksymalnie 512 znaków.
 repo_description_length=Dostępne znaki
 
 form.reach_limit_of_creation=Właściciel osiągnął limit maksymalnej ilości repozytoriów %d.
-form.name_reserved=Nazwa repozytorium „%s” jest zarezerwowana.
-form.name_pattern_not_allowed=Wzorzec nazwy repozytorium „%s” jest niedozwolony.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Wymaga autoryzacji
 migrate_type=Typ migracji
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Ten użytkownik nie będzie miał dostępu w
 settings.remove_collaborator_success=Współpracownik został usunięty.
 settings.search_user_placeholder=Szukaj użytkownika...
 settings.org_not_allowed_to_be_collaborator=Organizacji nie można dodać jako współpracownika.
+settings.hooks_desc=Webooki działają tak jak proste wywołania HTTP POST. Jeśli cokolwiek zdarzy się w Gogs, wyślemy powiadomienie do wybranego hosta. Więcej informacji można znaleźć w <a target="_blank" href="%s">przewodniku webhooków</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Dodaj webhooka
-settings.hooks_desc=Webooki działają tak jak proste wywołania HTTP POST. Jeśli cokolwiek zdarzy się w GIN, wyślemy powiadomienie do wybranego hosta. Więcej informacji można znaleźć w <a target="_blank" href="%s">przewodniku webhooków</a>.
 settings.webhook_deletion=Usuń webhooka
 settings.webhook_deletion_desc=Usunięcie tego webooka spowoduje usunięcie powiązanych informacji i wpisów w historii. Czy chcesz kontynuować?
 settings.webhook_deletion_success=Webhook został pomyślnie usunięty!
@@ -801,6 +805,8 @@ settings.webhook.response=Odpowiedź
 settings.webhook.headers=Nagłówki
 settings.webhook.payload=Zawartość
 settings.webhook.body=Treść
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Hooki Git są obsługiwane bezpośrednio przez Git. Pliki obsługiwanych hooków z poniższej listy mogą być edytowane, aby wykonywać niestandardowe operacje.
 settings.githook_edit_desc=Jeśli hook jest nieaktywny, zaprezentowana zostanie przykładowa treść. Pozostawienie pustej wartości wyłączy ten hook.
 settings.githook_name=Nazwa hooka
@@ -927,9 +933,8 @@ team_name_helper=Będziesz używał tej nazwy do wywoływania tego zespołu w dy
 team_desc_helper=Czym zajmuje się ten zespół?
 team_permission_desc=Jaki poziom uprawnień powinien mieć ten zespół?
 
-form.name_reserved=Nazwa organizacji „%s” jest zarezerwowana.
-form.name_pattern_not_allowed=Wzorzec nazwy organizacji „%s” jest niedozwolony.
-form.team_name_reserved=Nazwa zespołu '%s' jest zarezerwowana.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Ustawienia
 settings.options=Opcje
@@ -1001,11 +1006,11 @@ first_page=Pierwsza
 last_page=Ostatnia
 total=Ogółem: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
+dashboard.build_info=Informacje o kompilacji
+dashboard.app_ver=Wersja aplikacji
+dashboard.git_version=Wersja Git
+dashboard.go_version=Wersja Go
+dashboard.build_time=Data kompilacji
 dashboard.build_commit=Build commit
 dashboard.statistic=Statystyki
 dashboard.operations=Operacje
@@ -1013,6 +1018,7 @@ dashboard.system_status=Stan monitora systemu
 dashboard.statistic_info=Baza danych GIN zawiera <b>%d</b> użytkowników, <b>%d</b> organizacji, <b>%d</b> kluczy publicznych, <b>%d</b> repozytoriów, <b>%d</b> obserwujących, <b>%d</b> polubionych, <b>%d</b> akcji, <b>%d</b> tokenów, <b>%d</b> problemów, <b>%d</b> komenatrzy, <b>%d</b> kont społecznościowych, <b>%d</b> obserwacji, <b>%d</b> mirrorów, <b>%d</b> wydań, <b>%d</b> login sources, <b>%d</b> webhooków, <b>%d</b> kamieni milowych, <b>%d</b> labels, <b>%d</b> zadań hooków, <b>%d</b> zespołów, <b>%d</b> zadań aktualizacji, <b>%d</b> załączników.
 dashboard.operation_name=Nazwa operacji
 dashboard.operation_switch=Przełącz
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Uruchom
 dashboard.clean_unbind_oauth=Usuń niepowiązane wpisy OAuth
 dashboard.clean_unbind_oauth_success=Wszystkie niepowiązane wpisy OAuth zostały pomyślnie usunięte.
@@ -1162,28 +1168,28 @@ auths.github_api_endpoint=Punkt końcowy API
 
 config.not_set=(nie ustawiono)
 config.server_config=Konfiguracja serwera
-config.brand_name=Brand name
+config.brand_name=Nazwa marki
 config.run_user=Użytkownik uruchomieniowy
 config.run_mode=Tryb uruchamienia
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
+config.server.external_url=Zewnętrzny URL
+config.server.domain=Domena
+config.server.protocol=Protokół
+config.server.http_addr=Adres HTTP
+config.server.http_port=Port HTTP
+config.server.cert_file=Pliki certyfikatu
+config.server.key_file=Plik klucza
+config.server.tls_min_version=Minimalna wersja TLS
 config.server.unix_socket_permission=Unix socket permission
 config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
-config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
-config.server.app_data_path=Application data path
-config.server.load_assets_from_disk=Load assets from disk
+config.server.offline_mode=Tryb offline
+config.server.disable_router_log=Wyłącz dziennik routera
+config.server.enable_gzip=Włącz Gzip
+config.server.app_data_path=Ścieżka danych aplikacji
+config.server.load_assets_from_disk=Wczytaj zasoby z dysku
 config.server.landing_url=Landing URL
 
 config.ssh_config=Konfiguracja SSH
-config.ssh.enabled=Enabled
+config.ssh.enabled=Aktywne
 config.ssh.domain=Exposed domain
 config.ssh.port=Exposed port
 config.ssh.root_path=Root path
@@ -1192,19 +1198,19 @@ config.ssh.key_test_path=Key test path
 config.ssh.minimum_key_size_check=Minimum key size check
 config.ssh.minimum_key_sizes=Minimum key sizes
 config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
-config.ssh.start_builtin_server=Start builtin server
+config.ssh.start_builtin_server=Uruchom wbudowany serwer
 config.ssh.listen_host=Listen host
-config.ssh.listen_port=Listen port
+config.ssh.listen_port=Port nasłuchu
 config.ssh.server_ciphers=Server ciphers
 
 config.repo_config=Konfiguracja repozytorium
-config.repo.root_path=Root path
-config.repo.script_type=Script type
-config.repo.ansi_chatset=ANSI charset
-config.repo.force_private=Force private
+config.repo.root_path=Ścieżka katalogu głównego
+config.repo.script_type=Typ skryptu
+config.repo.ansi_chatset=Zestaw znaków ANSI
+config.repo.force_private=Wymuś tryb prywatny
 config.repo.max_creation_limit=Max creation limit
-config.repo.preferred_licenses=Preferred licenses
-config.repo.disable_http_git=Disable HTTP Git
+config.repo.preferred_licenses=Wybrana licencja
+config.repo.disable_http_git=Wyłącz Git przez HTTP
 config.repo.enable_local_path_migration=Enable local path migration
 config.repo.enable_raw_file_render_mode=Enable raw file render mode
 config.repo.commits_fetch_concurrency=Commits fetch concurrency
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Konfiguracja dziennika
 config.log_file_root_path=Ścieżka plików dziennika
 config.log_mode=Tryb

+ 20 - 8
conf/locale/locale_pt-BR.ini

@@ -43,6 +43,10 @@ issues=Problemas
 
 cancel=Cancelar
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalação
 title=Etapas de instalação para primeira execução
@@ -259,8 +263,7 @@ following=Seguindo
 follow=Seguir
 unfollow=Deixar de seguir
 
-form.name_reserved=O nome de usuário '%s' não pode ser usado.
-form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de usuário.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Perfil
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=O proprietário atingiu o limite máximo de criação de repositórios de %d.
-form.name_reserved=O nome de repositório '%s' não pode ser usado.
-form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de repositório.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Precisa de autorização
 migrate_type=Tipo de migração
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Este usuário não terá mais acesso de cola
 settings.remove_collaborator_success=O colaborador foi removido.
 settings.search_user_placeholder=Pesquisar usuário...
 settings.org_not_allowed_to_be_collaborator=Organização não tem permissão para ser adicionada como um colaborador.
+settings.hooks_desc=Hooks da web ou Webhooks permitem serviços externos serem notificados quando certos eventos acontecem no Gogs. Quando acontecem os eventos especificados, enviaremos uma solicitação POST para cada uma das URLs que você fornecer. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Adicionar Webhook
-settings.hooks_desc=Hooks da web ou Webhooks permitem serviços externos serem notificados quando certos eventos acontecem no GIN. Quando acontecem os eventos especificados, enviaremos uma solicitação POST para cada uma das URLs que você fornecer. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
 settings.webhook_deletion=Deletar Webhook
 settings.webhook_deletion_desc=Deletar este Webhook vai remover sua informação e todo o histórico de entrega. Deseja continuar?
 settings.webhook_deletion_success=Webhook deletado com sucesso!
@@ -801,6 +805,8 @@ settings.webhook.response=Resposta
 settings.webhook.headers=Cabeçalhos
 settings.webhook.payload=Payload
 settings.webhook.body=Corpo
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Hooks do Git são ofertados pelo próprio Git, você pode editar arquivos de hooks suportados na lista abaixo para aplicar operações personalizadas.
 settings.githook_edit_desc=Se o hook não estiver ativo, o conteúdo de exemplo será apresentado. Deixar o conteúdo em branco irá desativar esse hook.
 settings.githook_name=Nome do Hook
@@ -927,9 +933,8 @@ team_name_helper=Você usará este nome para mencionar esta equipe em conversas.
 team_desc_helper=Do que trata essa equipe?
 team_permission_desc=Que nível de permissão esta equipe deve ter?
 
-form.name_reserved=O nome de organização '%s' não pode ser usado.
-form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome de organização.
-form.team_name_reserved=O nome nome de equipe '%s' está reservado.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Configurações
 settings.options=Opções
@@ -1013,6 +1018,7 @@ dashboard.system_status=Status do monitor de sistema
 dashboard.statistic_info=O banco de dados do GIN contém <b>%d</b> usuários, <b>%d</b> organizações, <b>%d</b> chaves públicas, <b>%d</b> repositórios, <b>%d</b> observadores, <b>%d</b> estrelas, <b>%d</b> ações, <b>%d</b> acessos, <b>%d</b> questões, <b>%d</b> comentários, <b>%d</b> contas sociais, <b>%d</b> seguidores, <b>%d</b> espelhos, <b>%d</b> versões, <b>%d</b>  origens de login, <b>%d</b> Hooks da Web, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> tarefas hook, <b>%d</b> equipes, <b>%d</b> tarefas de atualização, <b>%d</b> anexos.
 dashboard.operation_name=Nome da operação
 dashboard.operation_switch=Trocar
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Executar
 dashboard.clean_unbind_oauth=Limpar OAuthes não acoplados
 dashboard.clean_unbind_oauth_success=Todos OAuthes desvinculados foram excluídos com sucesso.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Configuração de log
 config.log_file_root_path=Caminho raiz para arquivo de log
 config.log_mode=Modo

+ 50 - 38
conf/locale/locale_pt-PT.ini

@@ -43,6 +43,10 @@ issues=Questões
 
 cancel=Cancelar
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Instalação
 title=Procedimentos para a instalação inicial
@@ -121,7 +125,7 @@ run_user_not_match=O utilizador de execução não é igual ao utilizador actual
 smtp_host_missing_port=Porta em falta no endereço SMTP.
 invalid_smtp_from=Campo SMTP From inválido: %v
 save_config_failed=Falha ao salvar a configuração: %v
-init_failed=Failed to initialize application: %v
+init_failed=Falha ao inicializar a aplicação: %v
 invalid_admin_setting=Configuração do utilizador de administração está inválida: %v
 install_success=Bem-vindo! Estamos contentes por ter escolhido o Gogs, esperemos que goste.
 invalid_log_root_path=Caminho da pasta de logs inválida: %v
@@ -259,8 +263,7 @@ following=Seguindo
 follow=Seguir
 unfollow=Deixar de seguir
 
-form.name_reserved=O nome de utilizador '%s' não pode ser usado.
-form.name_pattern_not_allowed=Não é permitido usar o padrão '%s' para o nome do utilizador.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Perfil
@@ -426,8 +429,7 @@ repo_description_helper=Descrição do repositório. Máximo de 512 caracteres.
 repo_description_length=Caracteres disponíveis
 
 form.reach_limit_of_creation=O criador chegou ao limite de criação de %d repositórios.
-form.name_reserved=O nome do repositório '%s' é reservado.
-form.name_pattern_not_allowed=Não é permitido utilizar o padrão '%s' para nome de repositório.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Autorização necessária
 migrate_type=Tipo de migração
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Este utilizador perderá acesso ao repositó
 settings.remove_collaborator_success=Colaborador foi removido.
 settings.search_user_placeholder=Procurar utilizador...
 settings.org_not_allowed_to_be_collaborator=A organização não tem permissão para ser adicionada como colaboradora.
-settings.add_webhook=Adicionar Webhook
 settings.hooks_desc=Webhooks são muito parecidos com triggers básicos de eventos HTTP POST. Sempre que algo ocorre no Gogs, vamos lidar com a notificação para o host de destino especificado. Saiba mais no nosso <a target="_blank" href="%s"> Guia de Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Adicionar Webhook
 settings.webhook_deletion=Apagar um Webhook
 settings.webhook_deletion_desc=Apagar este Webhook vai remover sua informação e todo o histórico de entrega. Deseja continuar?
 settings.webhook_deletion_success=Webhook foi apagado com sucesso!
@@ -801,6 +805,8 @@ settings.webhook.response=Resposta
 settings.webhook.headers=Cabeçalho
 settings.webhook.payload=Payload
 settings.webhook.body=Corpo
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Hooks do Git são disponibilizados pelo próprio Git, pode editar ficheiros de Hooks suportados na lista abaixo para aplicar operações personalizadas.
 settings.githook_edit_desc=Se o hook estiver inativo, o conteúdo de exemplo será apresentado. Deixar o conteúdo em branco irá desativar este hook.
 settings.githook_name=Nome do Hook
@@ -927,9 +933,8 @@ team_name_helper=Utilizara este nome para mencionar esta equipa em conversas.
 team_desc_helper=Do que se trata essa equipa?
 team_permission_desc=Que nível de permissão esta equipa deve ter?
 
-form.name_reserved=O nome de organização '%s' está reservado.
-form.name_pattern_not_allowed=Não é permitido utilizar o padrão '%s' para o nome de organização.
-form.team_name_reserved=O nome nome de equipa '%s' está reservado.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Configurações
 settings.options=Opções
@@ -1001,18 +1006,19 @@ first_page=Primeiro
 last_page=Último
 total=Total: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
-dashboard.build_commit=Build commit
+dashboard.build_info=Informações da compilação
+dashboard.app_ver=Versão da Aplicação
+dashboard.git_version=Versão do Git
+dashboard.go_version=Versão do Go
+dashboard.build_time=Tempo de compilação
+dashboard.build_commit=Submissão da compilação
 dashboard.statistic=Estatísticas
 dashboard.operations=Operações
 dashboard.system_status=Monitorização de estado do sistema
 dashboard.statistic_info=A base de dados do Gogs contém <b>%d</b> utilizadores, <b>%d</b> organizações, <b>%d</b> chaves públicas, <b>%d</b> repositórios, <b>%d</b> observadores, <b>%d</b> estrelas, <b>%d</b> ações, <b>%d</b> acessos, <b>%d</b> questões, <b>%d</b> comentários, <b>%d</b> contas sociais, <b>%d</b> seguidores, <b>%d</b> mirrors, <b>%d</b> versões, <b>%d</b> origens de login, <b>%d</b> Hooks da Web, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> tarefas hook, <b>%d</b> equipas, <b>%d</b> tarefas de atualização, <b>%d</b> anexos.
 dashboard.operation_name=Nome de operação
 dashboard.operation_switch=Mudar
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Executar
 dashboard.clean_unbind_oauth=Limpar OAuthes desvinculados
 dashboard.clean_unbind_oauth_success=Todos OAuthes desvinculados foram excluídos com sucesso.
@@ -1162,33 +1168,33 @@ auths.github_api_endpoint=Endpoint da API
 
 config.not_set=(não definido)
 config.server_config=Configuração do Servidor
-config.brand_name=Brand name
+config.brand_name=Nome da marca
 config.run_user=Utilizador de execução
 config.run_mode=Mode de execução
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
-config.server.unix_socket_permission=Unix socket permission
-config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
-config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
-config.server.app_data_path=Application data path
-config.server.load_assets_from_disk=Load assets from disk
-config.server.landing_url=Landing URL
+config.server.external_url=URL externo
+config.server.domain=Domínio
+config.server.protocol=Protocolo
+config.server.http_addr=Endereço HTTP
+config.server.http_port=Porta HTTP
+config.server.cert_file=Ficheiro de certificado criptográfico
+config.server.key_file=Ficheiro da chave criptográfica privada
+config.server.tls_min_version=Versão mínima TLS
+config.server.unix_socket_permission=Permissão de soquete Unix
+config.server.local_root_url=URL raíz local
+config.server.offline_mode=Modo offline
+config.server.disable_router_log=Desativar o log do Router
+config.server.enable_gzip=Activar Gzip
+config.server.app_data_path=Caminho de dados da aplicação
+config.server.load_assets_from_disk=Carregar activos do disco
+config.server.landing_url=URL de Destino
 
 config.ssh_config=Configuração SSH
-config.ssh.enabled=Enabled
-config.ssh.domain=Exposed domain
-config.ssh.port=Exposed port
-config.ssh.root_path=Root path
-config.ssh.keygen_path=Keygen path
-config.ssh.key_test_path=Key test path
+config.ssh.enabled=Activado
+config.ssh.domain=Domínio exposto
+config.ssh.port=Porta exposta
+config.ssh.root_path=Caminho para a raíz
+config.ssh.keygen_path=Localização do gerador de chaves criptográficas
+config.ssh.key_test_path=Localização do teste das chaves criptográficas
 config.ssh.minimum_key_size_check=Minimum key size check
 config.ssh.minimum_key_sizes=Minimum key sizes
 config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Configuração de Log
 config.log_file_root_path=Caminho Raiz para Ficheiro Log
 config.log_mode=Modo

+ 41 - 29
conf/locale/locale_ru-RU.ini

@@ -43,6 +43,10 @@ issues=Задачи
 
 cancel=Отмена
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Установка
 title=Установочные шаги для первого запуска
@@ -121,7 +125,7 @@ run_user_not_match=Текущий пользователь не является
 smtp_host_missing_port=Не указан порт в адресе хоста SMTP.
 invalid_smtp_from=Поле SMTP From неправильное: %v
 save_config_failed=Не удалось сохранить конфигурацию: %v
-init_failed=Failed to initialize application: %v
+init_failed=Не удалось инициализировать приложение: %v
 invalid_admin_setting=Указан недопустимый параметр учетной записи администратора: %v
 install_success=Добро пожаловать! Мы рады, что вы выбрали GIN. Веселитесь и берегите себя.
 invalid_log_root_path=Недопустимый путь для логов: %v
@@ -259,8 +263,7 @@ following=Подписан
 follow=Подписаться
 unfollow=Отписаться
 
-form.name_reserved=Имя пользователя '%s' зарезервировано.
-form.name_pattern_not_allowed=Имя пользователя «%s» не допускается.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Профиль
@@ -426,8 +429,7 @@ repo_description_helper=Описание репозитория. Максима
 repo_description_length=Доступные символы
 
 form.reach_limit_of_creation=У владельца достигнут максимальный предел в %d создаваемых репозиториев.
-form.name_reserved=Имя репозитория  '%s'  зарезервировано.
-form.name_pattern_not_allowed=Шаблон имени репозитория '%s' не допускается.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Требуется авторизация
 migrate_type=Тип миграции
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Этот пользователь больш
 settings.remove_collaborator_success=Соавтор был удален.
 settings.search_user_placeholder=Поиск пользователя...
 settings.org_not_allowed_to_be_collaborator=Организации не могут быть добавлены как соавторы.
+settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на Gogs. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" href="%s">Руководстве по Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Добавить Webhook
-settings.hooks_desc=Webhooks позволяют внешним службам получать уведомления при возникновении определенных событий на GIN. При возникновении указанных событий мы отправим запрос POST на каждый заданный вами URL. Узнать больше можно в нашем <a target="_blank" href="%s">Руководстве по Webhooks</a>.
 settings.webhook_deletion=Удалить веб-хук
 settings.webhook_deletion_desc=Удаление этого веб-хука приведет к удалению всей, связанной с ним, информации, включая историю. Хотите продолжить?
 settings.webhook_deletion_success=Веб-хук успешно удален!
@@ -801,6 +805,8 @@ settings.webhook.response=Ответ
 settings.webhook.headers=Заголовки
 settings.webhook.payload=Содержимое запроса
 settings.webhook.body=Тело ответа
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git-хуки предоставляются Git самим по себе, вы можете изменять файлы поддерживаемых хуков из списка ниже чтобы выполнять внешние операции.
 settings.githook_edit_desc=Если хук не активен, будет подставлен пример содержимого. Пустое значение в этом поле приведет к отключению хука.
 settings.githook_name=Название Hook'a
@@ -927,9 +933,8 @@ team_name_helper=Вы будете использовать это имя для
 team_desc_helper=Что это за команда?
 team_permission_desc=Какой уровень разрешений должен быть у этой команды?
 
-form.name_reserved=Наименование организации  '%s' зарезервированно.
-form.name_pattern_not_allowed=Шаблон организации  '%s' не допускается.
-form.team_name_reserved=Имя команды '%s' зарезервировано.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Настройки
 settings.options=Опции
@@ -1001,18 +1006,19 @@ first_page=Первый
 last_page=Последний
 total=Всего: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
-dashboard.build_commit=Build commit
+dashboard.build_info=Информация о сборке
+dashboard.app_ver=Версия приложения
+dashboard.git_version=Версия Git
+dashboard.go_version=Версия Go
+dashboard.build_time=Время сборки
+dashboard.build_commit=Коммит сборки
 dashboard.statistic=Статистика
 dashboard.operations=Операции
 dashboard.system_status=Статус системного монитора
 dashboard.statistic_info=В базе данных GIN записано <b>%d</b> пользователей, <b>%d</b> организаций, <b>%d</b> публичных ключей, <b>%d</b> репозиториев, <b>%d</b> подписок на репозитории, <b>%d</b> добавлений в избранное, <b>%d</b> действий, <b>%d</b> доступов, <b>%d</b> задач, <b>%d</b> комментариев, <b>%d</b> социальных учетных записей, <b>%d</b> подписок на пользователей, <b>%d</b> зеркал, <b>%d</b> релизов, <b>%d</b> источников входа, <b>%d</b> веб-хуков, <b>%d</b> этапов, <b>%d</b> меток, <b>%d</b> задач хуков, <b>%d</b> команд, <b>%d</b> задач по обновлению, <b>%d</b> присоединенных файлов.
 dashboard.operation_name=Наименование Операции
 dashboard.operation_switch=Переключить
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Запуск
 dashboard.clean_unbind_oauth=Удалить не привязанные OAUth
 dashboard.clean_unbind_oauth_success=Не привязанные OAuth аккаунты успешно удалены.
@@ -1162,22 +1168,22 @@ auths.github_api_endpoint=Конечная точка API
 
 config.not_set=(не задано)
 config.server_config=Конфигурация сервера
-config.brand_name=Brand name
+config.brand_name=Название бренда
 config.run_user=Запуск пользователем
 config.run_mode=Режим выполнения
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
+config.server.external_url=Внешний URL
+config.server.domain=Домен
+config.server.protocol=Протокол
+config.server.http_addr=HTTP адрес
+config.server.http_port=Порт HTTP
+config.server.cert_file=Файл сертификата
+config.server.key_file=Файл ключа
+config.server.tls_min_version=Минимальная версия TLS
 config.server.unix_socket_permission=Unix socket permission
 config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
+config.server.offline_mode=Автономный режим
 config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
+config.server.enable_gzip=Включить Gzip
 config.server.app_data_path=Application data path
 config.server.load_assets_from_disk=Load assets from disk
 config.server.landing_url=Landing URL
@@ -1189,8 +1195,8 @@ config.ssh.port=Exposed port
 config.ssh.root_path=Root path
 config.ssh.keygen_path=Keygen path
 config.ssh.key_test_path=Key test path
-config.ssh.minimum_key_size_check=Minimum key size check
-config.ssh.minimum_key_sizes=Minimum key sizes
+config.ssh.minimum_key_size_check=Проверка минимальной длины ключа
+config.ssh.minimum_key_sizes=Минимальные размеры ключа
 config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
 config.ssh.start_builtin_server=Start builtin server
 config.ssh.listen_host=Listen host
@@ -1204,7 +1210,7 @@ config.repo.ansi_chatset=ANSI charset
 config.repo.force_private=Force private
 config.repo.max_creation_limit=Max creation limit
 config.repo.preferred_licenses=Preferred licenses
-config.repo.disable_http_git=Disable HTTP Git
+config.repo.disable_http_git=Выключить HTTP Git
 config.repo.enable_local_path_migration=Enable local path migration
 config.repo.enable_raw_file_render_mode=Enable raw file render mode
 config.repo.commits_fetch_concurrency=Commits fetch concurrency
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Конфигурация журнала
 config.log_file_root_path=Путь до папки с логами
 config.log_mode=Режим

+ 20 - 8
conf/locale/locale_sk-SK.ini

@@ -43,6 +43,10 @@ issues=Issues
 
 cancel=Zrušiť
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Inštalácia
 title=Postup prvotnej inštalácie
@@ -259,8 +263,7 @@ following=Sledovaní
 follow=Sledovať
 unfollow=Prestať sledovať
 
-form.name_reserved=Používateľské meno '%s' je vyhradené.
-form.name_pattern_not_allowed=Vzor používateľského mena '%s' nieje povolený.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Popis repozitára. Maximálna dĺžka 512 znakov.
 repo_description_length=Dostupné znaky
 
 form.reach_limit_of_creation=Vlastník dosiahol maximálneho počtu %d vytvorených repozitárov.
-form.name_reserved=Repozitár s názvom '%s' je vyhradený.
-form.name_pattern_not_allowed=Repozitár so vzorom názvu '%s' nieje povolený.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Je potrebná autorizácia
 migrate_type=Typ migrácie
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Tento užívateľ po tom, čo bude odstráne
 settings.remove_collaborator_success=Spolupracovník bol odstránený.
 settings.search_user_placeholder=Hľadať užívateľa...
 settings.org_not_allowed_to_be_collaborator=Nieje dovolené pridať organizáciu ako spolupracovníka.
-settings.add_webhook=Pridať webhook
 settings.hooks_desc=Webové háčiky sú podobné základným spúšťačom HTTP, POST udalostí. Kedykoľvek sa niečo stane v Gogs, bude postarané o oznámenie špecifickému cieľovému serveru. Viac o danom sa dozviete v <a target="_blank" href="%s"> príručke webových háčikov </a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Pridať webhook
 settings.webhook_deletion=Odstrániť webhook
 settings.webhook_deletion_desc=Odstránením tohto webového háčika sa odstránia všetky informácie o ňom a tiež história volaní. Chcete pokračovať?
 settings.webhook_deletion_success=Webový háčik bol odstránený!
@@ -801,6 +805,8 @@ settings.webhook.response=Odpoveď
 settings.webhook.headers=Hlavičky
 settings.webhook.payload=Payload
 settings.webhook.body=Telo
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Háčiky Gitu sú spravované Gitom samotným, môžete v zozname nižšie upraviť súbory podporovaných háčikov k prevádzaniu užívateľských operácií.
 settings.githook_edit_desc=Pokiaľ je hook neaktívny, zobrazí sa ukážkový obsah. Ponechanie prázdneho obsahu zakáže tento hook.
 settings.githook_name=Názov hooku
@@ -927,9 +933,8 @@ team_name_helper=Tento názov budete používať pri pomenovaní týmu v konverz
 team_desc_helper=Prosím popíšte tento tým
 team_permission_desc=Akú úroveň prístupu má mať tento tým?
 
-form.name_reserved=Názov organizácie '%s' je už rezervovaný.
-form.name_pattern_not_allowed=Vzor názvu organizácie '%s' nieje povolený.
-form.team_name_reserved=Názov týmu '%s' je vyhradený.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Nastavenia
 settings.options=Možnosti
@@ -1013,6 +1018,7 @@ dashboard.system_status=Monitor stavu systému
 dashboard.statistic_info=Gogs databáza obsahuje <b>%d</b> používateľov, <b>%d</b> organizácií, <b>%d</b> verejných kľúčov, <b>%d</b> repozitárov, <b>%d</b> sledovaní, <b>%d</b> hviezd, <b>%d</b> akcií, <b>%d</b> prístupov, <b>%d</b> issues, <b>%d</b> komentárov, <b>%d</b> sociálnych účtov, <b>%d</b> nasledovaní, <b>%d</b> mirrorov, <b>%d</b> vydaní, <b>%d</b> zdrojov prihlásení, <b>%d</b> webhookov, <b>%d</b> míľnikov, <b>%d</b> štítkov, <b>%d</b> hook úloh, <b>%d</b> tímov, <b>%d</b> aktualizačných úloh, <b>%d</b> príloh.
 dashboard.operation_name=Názov operácie
 dashboard.operation_switch=Prepnúť
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Spustiť
 dashboard.clean_unbind_oauth=Odstráň nenaviazané OAuth tokeny
 dashboard.clean_unbind_oauth_success=Všetky nenaviazané OAuth tokeny boli úspešne odstránené.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Nastavenie systémových záznamov
 config.log_file_root_path=Koreňový adresár súboru systémových záznamov
 config.log_mode=Režim

+ 20 - 8
conf/locale/locale_sr-SP.ini

@@ -43,6 +43,10 @@ issues=Дискусије
 
 cancel=Откажи
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Инсталација
 title=Инсталационе кораке за првог покретања
@@ -259,8 +263,7 @@ following=Пратим
 follow=Прати
 unfollow=Престани да пратиш
 
-form.name_reserved=Корисничко име '%s' је резервирано.
-form.name_pattern_not_allowed=Корисничко име ликом '%s' није дозвољено.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Профил
@@ -426,8 +429,7 @@ repo_description_helper=Опис спремишта. Максимум 512 кар
 repo_description_length=Доступни карактери
 
 form.reach_limit_of_creation=Власник има максимум број %d спремишта.
-form.name_reserved=Име спремишта '%s' је резервирано.
-form.name_pattern_not_allowed=Име спремишта по шаблоном '%s' није дозвољено.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Потребна ауторизација
 migrate_type=Тип миграције
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Овај корисник неће имат
 settings.remove_collaborator_success=Сарадник је уклоњен.
 settings.search_user_placeholder=Претрага корисника...
 settings.org_not_allowed_to_be_collaborator=Неможе се додати организација као сарадник.
+settings.hooks_desc=Webhooks омогућавају спољашњим услугама да приме обавештења када се нешто одређено догоди на Gogs. Сазнајте више у овом <a target="_blank" href="%s">водичу за Webhooks</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Додај Webhook
-settings.hooks_desc=Webhooks омогућавају спољашњим услугама да приме обавештења када се нешто одређено догоди на GIN. Сазнајте више у овом <a target="_blank" href="%s">водичу за Webhooks</a>.
 settings.webhook_deletion=Уклони Webhook
 settings.webhook_deletion_desc=Брисање овог Webhook ће довести до уклањања сву наведену информацију, укључујући и историју. Да ли желите да наставите?
 settings.webhook_deletion_success=Webhook успешно избрисан!
@@ -801,6 +805,8 @@ settings.webhook.response=Одговор
 settings.webhook.headers=Наслови
 settings.webhook.payload=Садржај захтева
 settings.webhook.body=Тело
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git Hooks пружају Git сами по себи. Можете ажурирати датотеке са подржаним hooks са пратећег списка операције.
 settings.githook_edit_desc=Aко Webhook није активан, примерни садржај ће бити представљен. Ако оставите празно, Webhook ће бити онемогућен.
 settings.githook_name=Име Hook-а
@@ -927,9 +933,8 @@ team_name_helper=Ви ћете користити то име помињете 
 team_desc_helper=Шта је циљ овог тима?
 team_permission_desc=Који ниво приступа треба имати овај тим?
 
-form.name_reserved=Име организације '%s' је резервирано.
-form.name_pattern_not_allowed=Шаблон имена '%s' није дозвољено.
-form.team_name_reserved=Име тима '%s' је резервисано.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Подешавања
 settings.options=Опције
@@ -1013,6 +1018,7 @@ dashboard.system_status=Статус системског монитора
 dashboard.statistic_info=У бази података GIN забележено је <b>%d</b> корисника, <b>%d</b> организације, <b>%d</b> јавних кључева, <b>%d</b> спремишта, <b>%d</b> watches, <b>%d</b> фаворита, <b>%d</b> акције, <b>%d</b> доступа, <b>%d</b> задатака, <b>%d</b> коментара, <b>%d</b> друштвених рачуна, <b>%d</b> пратње, <b>%d</b> огледала, <b>%d</b> издања, <b>%d</b> извора улаза, <b>%d</b> webhooks, <b>%d</b> фаза, <b>%d</b> лабела, <b>%d</b> hook задатака, <b>%d</b> тимова, <b>%d</b> задатака за надоградњу, <b>%d</b> прилога.
 dashboard.operation_name=Име операције
 dashboard.operation_switch=Пребаци
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Покрени
 dashboard.clean_unbind_oauth=Уклони неповазане OAuth
 dashboard.clean_unbind_oauth_success=Неповезане OAuth налози су успешно избрисани.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Kонфигурација журнала
 config.log_file_root_path=Пут до журнала
 config.log_mode=Режим

+ 20 - 8
conf/locale/locale_sv-SE.ini

@@ -43,6 +43,10 @@ issues=Problem
 
 cancel=Avbryt
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Installation
 title=Steg för att installera för första gången
@@ -259,8 +263,7 @@ following=Följer
 follow=Följ
 unfollow=Sluta följa
 
-form.name_reserved=Användarnamnet "%s" är reserverad.
-form.name_pattern_not_allowed=Användarnamnet '%s' är inte tillåtet.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=Ägaren har nått maxgränsen av %d skapade repon.
-form.name_reserved=Namnet '%s' på utvecklingskatalogen är reserverat.
-form.name_pattern_not_allowed=Reponamnet '%s' är inte tillåtet.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Tillstånd Krävs
 migrate_type=Migreringstyp
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Denna användare kommer förlora sin åtkoms
 settings.remove_collaborator_success=Deltagare har tagits bort.
 settings.search_user_placeholder=Sök användare...
 settings.org_not_allowed_to_be_collaborator=Organisationen kan inte läggas till som en deltagare.
+settings.hooks_desc=Webbhookar påminner mycket om vanliga HTTP POST-händelseutlösare. När något inträffar i Gogs, kommer vi att meddela måldatorn som du anger. Läs mera i <a target="_blank" href="%s">Webbhook Guide</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Lägg Till Webbhook
-settings.hooks_desc=Webbhookar påminner mycket om vanliga HTTP POST-händelseutlösare. När något inträffar i GIN, kommer vi att meddela måldatorn som du anger. Läs mera i <a target="_blank" href="%s">Webbhook Guide</a>.
 settings.webhook_deletion=Ta Bort Webbhook
 settings.webhook_deletion_desc=Borttagning av denna webbhook kommer att ta bort all dess information och all leveranshistorik. Är du säker på att du vill fortsätta?
 settings.webhook_deletion_success=Webbhook har tagits bort!
@@ -801,6 +805,8 @@ settings.webhook.response=Svar
 settings.webhook.headers=Huvuden
 settings.webhook.payload=Nyttolast
 settings.webhook.body=Innehåll
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git-krokar är en del av Git själv. För att utföra anpassade operationer kan du redigera filerna för de krokar som stöds i listan nedan.
 settings.githook_edit_desc=Om kroken är inaktiv visas exempelinnehåll. Inaktivera denna krok genom att lämna innehållet tomt.
 settings.githook_name=Kroknamn
@@ -927,9 +933,8 @@ team_name_helper=Du kan använda detta namn för att nämna denna grupp i konver
 team_desc_helper=Vad handlar denna grupp om?
 team_permission_desc=Vilka behörigheter ska denna grupp ha?
 
-form.name_reserved=Organisationsnamnet "%s" är reserverat.
-form.name_pattern_not_allowed=Organisationsnamnet '%s' är inte tillåtet.
-form.team_name_reserved=Team name '%s' is reserved.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Inställningar
 settings.options=Alternativ
@@ -1013,6 +1018,7 @@ dashboard.system_status=Systemstatus
 dashboard.statistic_info=GIN-databasen innehåller <b>%d</b> användare, <b>%d</b> organisationer, <b>%d</b> publika nyckar, <b>%d</b> förråd, <b>%d</b> vakter, <b>%d</b> stjärnor, <b>%d</b> handlingar, <b>%d</b> åtkomster, <b>%d</b> ärenden, <b>%d</b> kommentarer, <b>%d</b> sociala konton, <b>%d</b> följbegäran, <b>%d</b> speglingar, <b>%d</b> släpp, <b>%d</b> inloggningskällor, <b>%d</b> webbkrokar, <b>%d</b> milstolpar, <b>%d</b> etiketter, <b>%d</b> krokuppgifter, <b>%d</b> team, <b>%d</b> uppdateringsuppgifter, <b>%d</b> bilagor.
 dashboard.operation_name=Operationsnamn
 dashboard.operation_switch=Byt till
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Kör
 dashboard.clean_unbind_oauth=Rensa obundna OAuth-begäran
 dashboard.clean_unbind_oauth_success=Alla obundna OAuth-begäran har tagit
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Logg-konfiguration
 config.log_file_root_path=Log file root path
 config.log_mode=Mode

+ 69 - 57
conf/locale/locale_tr-TR.ini

@@ -43,6 +43,10 @@ issues=Sorunlar
 
 cancel=İptal
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Kurulum
 title=İlk Kez Çalıştırma İçin Kurulum Adımları
@@ -121,7 +125,7 @@ run_user_not_match=Çalıştırma kullanıcısı geçerli kullanıcı değil: %s
 smtp_host_missing_port=SMTP ana makine adresindeki bağlantı noktası eksik.
 invalid_smtp_from=SMTP form alanı geçerli değil: %v
 save_config_failed=Yapılandırma kaydedilemedi: %v
-init_failed=Failed to initialize application: %v
+init_failed=Uygulama başlatılamadı: %v
 invalid_admin_setting=Yönetici hesap ayarları geçersiz: %v
 install_success=Merhaba! GIN'u tercih ettiğiniz için çok mutluyuz, keyfini çıkarın!
 invalid_log_root_path=Günlük kök dizini geçersiz: %v
@@ -259,8 +263,7 @@ following=Takip Edilenler
 follow=Takip Et
 unfollow=Takibi Bırak
 
-form.name_reserved=Kullanıcı adı '%s' başka birine ayrılmış.
-form.name_pattern_not_allowed=Kullanıcı adında '%s' modeline izin verilmez.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Profil
@@ -374,7 +377,7 @@ delete_token=Sil
 access_token_deletion=Kişisel Erişim Anahtarını Silme
 access_token_deletion_desc=Bu kişisel erişim anahtarını silerseniz uygulamanıza ilişkin tüm erişimler de kaldırılacaktır. Devam etmek istiyor musunuz?
 delete_token_success=Kişisel erişim anahtarı başarıyla kaldırıldı! Uygulamanızı güncellemeyi de unutmayın!
-token_name_exists=Token with same name already exists.
+token_name_exists=Aynı ada sahip simge zaten var.
 
 orgs.none=Hiçbir organizasyonların üyesi değilsiniz.
 orgs.leave_title=Organizasyondan ayrıl
@@ -426,8 +429,7 @@ repo_description_helper=Depo açıklaması. Maksimum 512 karakter uzunluğu.
 repo_description_length=Mevcut karakterler
 
 form.reach_limit_of_creation=Sahip, maksimum %d depo oluşturma limitine ulaşmıştır.
-form.name_reserved=Depo ismi '%s' başkasına ayrılmış.
-form.name_pattern_not_allowed=Depo isminde '%s' modeline izin verilmiyor.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Yetkilendirme Gereklidir
 migrate_type=Göç Türü
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Kullanıcı, silme işleminden sonra bu depo
 settings.remove_collaborator_success=Katkıcı silindi.
 settings.search_user_placeholder=Kullanıcı ara...
 settings.org_not_allowed_to_be_collaborator=Organizasyon, bir katkıcı olarak eklenemez.
+settings.hooks_desc=Web istekleri, HTTP POST olay tetikleyicileri gibidirler. Gogs'ta ne zaman bir şey olsa, hedef belirttiğiniz sunuculara bildirim yapabilecek duruma geliriz. Daha fazla bilgiyi <a target="_blank" href="%s">Web İstekleri Kılavuzu</a>'nda bulabilirsiniz.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Web İsteği Ekle
-settings.hooks_desc=Web istekleri, HTTP POST olay tetikleyicileri gibidirler. GIN'ta ne zaman bir şey olsa, hedef belirttiğiniz sunuculara bildirim yapabilecek duruma geliriz. Daha fazla bilgiyi <a target="_blank" href="%s">Web İstekleri Kılavuzu</a>'nda bulabilirsiniz.
 settings.webhook_deletion=Web İsteğini Sil
 settings.webhook_deletion_desc=Bu web isteğini silerseniz buna bağlı olan tüm bilgiler ve dağıtım geçmişi de silinecektir. Devam etmek istiyor musunuz?
 settings.webhook_deletion_success=Web isteği başarıyla silindi!
@@ -801,6 +805,8 @@ settings.webhook.response=Cevaplar
 settings.webhook.headers=Başlıklar
 settings.webhook.payload=Yükler
 settings.webhook.body=Gövde
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git istekleri, Git'in kendisi tarafından güçlendirilmiştir. Özel işlemleri gerçekleştirmek için aşağıdaki listedeki desteklenen isteklerin dosyalarını düzenleyebilirsiniz.
 settings.githook_edit_desc=İstek aktif değilse örnek içerik sunulacaktır. İçeriği boş bırakmak, isteği devre dışı bırakmayı beraberinde getirecektir.
 settings.githook_name=İstek İsmi
@@ -927,9 +933,8 @@ team_name_helper=Sohbetlerde bu takımdan bahsetmek için bu ismi kullanacaksın
 team_desc_helper=Bu takım ne hakkında?
 team_permission_desc=Bu takım, ne gibi bir izin seviyesine sahiptir?
 
-form.name_reserved=Organizasyon adı '%s' başka birisine ayrılmış.
-form.name_pattern_not_allowed=Organizasyon adı modeli '%s' geçersiz.
-form.team_name_reserved='%s' takım ismi başka birine ayrılmış.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Ayarlar
 settings.options=Seçenekler
@@ -1001,18 +1006,19 @@ first_page=İlk
 last_page=Son
 total=Toplam: %d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
-dashboard.build_commit=Build commit
+dashboard.build_info=Derleme Bilgisi
+dashboard.app_ver=Uygulama sürümü
+dashboard.git_version=Git sürümü
+dashboard.go_version=Go sürümü
+dashboard.build_time=Derleme zamanı
+dashboard.build_commit=Derleme işlemesi
 dashboard.statistic=İstatistik
 dashboard.operations=İşlemler
 dashboard.system_status=Sistem İzleme Durumu
 dashboard.statistic_info=GIN veritabanında <b>%d</b> kullanıcı, <b>%d</b> organizasyon, <b>%d</b> genel anahtar, <b>%d</b> depo, <b>%d</b> izleme, <b>%d</b> yıldız, <b>%d</b> hareket, <b>%d</b> erişim, <b>%d</b> sorun, <b>%d</b> yorum, <b>%d</b> sosyal hesap, <b>%d</b> takip, <b>%d</b> yansı, <b>%d</b> sürüm, <b>%d</b> giriş kaynağı, <b>%d</b> web isteği, <b>%d</b> kilometre taşı, <b>%d</b> etiket, <b>%d</b> istek görevi, <b>%d</b> takım, <b>%d</b> güncellenmiş görev, <b>%d</b> ek var.
 dashboard.operation_name=İşlem Adı
 dashboard.operation_switch=Geç
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Çalıştır
 dashboard.clean_unbind_oauth=Bağlanmamış OAuth'ları Temizle
 dashboard.clean_unbind_oauth_success=Bağlanmamış tüm OAuth'lar başarıyla silindi.
@@ -1158,56 +1164,56 @@ auths.delete_auth_desc=Bu yetkilendirme silinecek. Devam etmek istiyor musunuz?
 auths.still_in_used=Bu yetkilendirme hala bazı kullanıcılar tarafından kullanılıyor. Lütfen öncelikle bunları silin ya da başka oturum açma türlerine çevirin.
 auths.deletion_success=Yetkilendirme başarıyla silindi!
 auths.login_source_exist='%s' giriş kaynağı zaten mevcut.
-auths.github_api_endpoint=API Endpoint
+auths.github_api_endpoint=API Uç Noktası
 
 config.not_set=(ayarlı değil)
 config.server_config=Sunucu Yapılandırması
-config.brand_name=Brand name
+config.brand_name=Marka adı
 config.run_user=Çalıştırma Kullanıcısı
 config.run_mode=Çalıştırma Modu
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
-config.server.unix_socket_permission=Unix socket permission
-config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
-config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
-config.server.app_data_path=Application data path
-config.server.load_assets_from_disk=Load assets from disk
-config.server.landing_url=Landing URL
+config.server.external_url=Dış URL
+config.server.domain=Alan Adı
+config.server.protocol=Protokol
+config.server.http_addr=HTTP adresi
+config.server.http_port=HTTP portu
+config.server.cert_file=Sertifika dosyası
+config.server.key_file=Anahtar dosyası
+config.server.tls_min_version=En az TLS sürümü
+config.server.unix_socket_permission=Unix soket izni
+config.server.local_root_url=Yerel kök URL'si
+config.server.offline_mode=Çevrimdışı kip
+config.server.disable_router_log=Yönlendirici günlüğünü devre dışı bırak
+config.server.enable_gzip=Gzip'i etkinleştir
+config.server.app_data_path=Uygulama veri yolu
+config.server.load_assets_from_disk=Varlıkları diskten yükle
+config.server.landing_url=Açılış URL'si
 
 config.ssh_config=SSH Yapılandırması
-config.ssh.enabled=Enabled
-config.ssh.domain=Exposed domain
-config.ssh.port=Exposed port
-config.ssh.root_path=Root path
-config.ssh.keygen_path=Keygen path
-config.ssh.key_test_path=Key test path
-config.ssh.minimum_key_size_check=Minimum key size check
-config.ssh.minimum_key_sizes=Minimum key sizes
-config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
-config.ssh.start_builtin_server=Start builtin server
-config.ssh.listen_host=Listen host
-config.ssh.listen_port=Listen port
-config.ssh.server_ciphers=Server ciphers
+config.ssh.enabled=Etkin
+config.ssh.domain=Maruz kalan alan adı
+config.ssh.port=Maruz kalan port
+config.ssh.root_path=Kök yolu
+config.ssh.keygen_path=Keygen yolu
+config.ssh.key_test_path=Anahtar test yolu
+config.ssh.minimum_key_size_check=En az anahtar boyutu denetimi
+config.ssh.minimum_key_sizes=En az anahtar boyutları
+config.ssh.rewrite_authorized_keys_at_start=Başlangıçta "yetkili_anahtarlar" ı yeniden yaz
+config.ssh.start_builtin_server=Yerleşik sunucuyu başlat
+config.ssh.listen_host=Ana makineyi dinle
+config.ssh.listen_port=Port'u dinle
+config.ssh.server_ciphers=Sunucu şifreleri
 
 config.repo_config=Depo Yapılandırması
-config.repo.root_path=Root path
-config.repo.script_type=Script type
-config.repo.ansi_chatset=ANSI charset
-config.repo.force_private=Force private
-config.repo.max_creation_limit=Max creation limit
-config.repo.preferred_licenses=Preferred licenses
-config.repo.disable_http_git=Disable HTTP Git
-config.repo.enable_local_path_migration=Enable local path migration
-config.repo.enable_raw_file_render_mode=Enable raw file render mode
-config.repo.commits_fetch_concurrency=Commits fetch concurrency
+config.repo.root_path=Kök yolu
+config.repo.script_type=Betik türü
+config.repo.ansi_chatset=ANSI karakter kümesi
+config.repo.force_private=Özeli zorla
+config.repo.max_creation_limit=En fazla oluşturma sınırı
+config.repo.preferred_licenses=Tercih edilen lisanslar
+config.repo.disable_http_git=HTTP Git'i devre dışı bırak
+config.repo.enable_local_path_migration=Yerel yol göçünü etkinleştir
+config.repo.enable_raw_file_render_mode=Ham dosya oluşturma modunu etkinleştir
+config.repo.commits_fetch_concurrency=İşlemeler eşzamanlılık getirir
 config.repo.editor.line_wrap_extensions=Editor line wrap extensions
 config.repo.editor.previewable_file_modes=Editor previewable file modes
 config.repo.upload.enabled=Upload enabled
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Log Yapılandırması
 config.log_file_root_path=Log Dosyası Kök Yolu
 config.log_mode=Mod

+ 20 - 8
conf/locale/locale_uk-UA.ini

@@ -43,6 +43,10 @@ issues=Проблеми
 
 cancel=Скасувати
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Установка
 title=Кроки установки перед першим запуском
@@ -259,8 +263,7 @@ following=Слідкувати
 follow=Підписатися
 unfollow=Відписатися
 
-form.name_reserved=Ім'я користувача "%s" зарезервовано.
-form.name_pattern_not_allowed=Шаблон Імені користувача '%s' не допускається.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Профіль
@@ -426,8 +429,7 @@ repo_description_helper=Опис репозиторію. До 512-ти симв
 repo_description_length=Доступні символи
 
 form.reach_limit_of_creation=Власник досягнув максимальної кількості у %d створених репозиторіїв.
-form.name_reserved=Назва репозиторія '%s' зарезервовано.
-form.name_pattern_not_allowed=Шаблон назви репозиторія '%s' не є дозволеним.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Потрібна авторизація
 migrate_type=Тип міграції
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Цей користувач більше н
 settings.remove_collaborator_success=Співавтора було видалено.
 settings.search_user_placeholder=Пошук користувача...
 settings.org_not_allowed_to_be_collaborator=Організації не можуть бути додані як співавтори.
+settings.hooks_desc=Web-хуки схожі на HTTP POST тригери подій. Яка б подія не виникла в Gogs, ми можемо обробити повідомлення про неї на сторонньому хості який ви задаєте. Взнайте більше у <a target="_blank" href="%s">Webhooks Guide</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=Додати Webhook
-settings.hooks_desc=Web-хуки схожі на HTTP POST тригери подій. Яка б подія не виникла в GIN, ми можемо обробити повідомлення про неї на сторонньому хості який ви задаєте. Взнайте більше у <a target="_blank" href="%s">Webhooks Guide</a>.
 settings.webhook_deletion=Видалити Webhook
 settings.webhook_deletion_desc=Видалення цього web-хуку призведе до видалення інформації про нього та усієї історії поставок. Впевнені, що бажаєте продовжити?
 settings.webhook_deletion_success=Webhook успішно видалено!
@@ -801,6 +805,8 @@ settings.webhook.response=Відповідь
 settings.webhook.headers=Заголовки
 settings.webhook.payload=Зміст
 settings.webhook.body=Тіло
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git хуки керуються самим Git, ви можете редагувати файли хуків, що підтримуються згідно списку нище, щоб виконувати будь-які операції.
 settings.githook_edit_desc=Якщо хук неактивний, буде представлено зразок вмісту. Порожнє значення у цьому полі призведе до вимкнення хуку.
 settings.githook_name=Ім'я хуку
@@ -927,9 +933,8 @@ team_name_helper=Ви будете використовувати це ім'я 
 team_desc_helper=Що це за команда?
 team_permission_desc=Який рівень дозволів має бути у цієї команди?
 
-form.name_reserved=Назву організації '%s' зарезервовано.
-form.name_pattern_not_allowed=Шаблон назви організації '%s' не дозволено.
-form.team_name_reserved=Ім'я команди '%s' зарезервовано.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Налаштування
 settings.options=Опції
@@ -1013,6 +1018,7 @@ dashboard.system_status=Статус системного монітору
 dashboard.statistic_info=База даних GIN має <b>%d</b> користувачів, <b>%d</b> організацій, <b>%d</b> публічних ключів, <b>%d</b> репозиторіїв, <b>%d</b> спостерігачів, <b>%d</b> зірок, <b>%d</b> дій, <b>%d</b> відвідувань, <b>%d</b> обговорень, <b>%d</b> коментарів, <b>%d</b> соціальних облікових записів, <b>%d</b> підписників, <b>%d</b> дзеркал, <b>%d</b> релізів, <b>%d</b> джерел входу, <b>%d</b> webhook-ів, <b>%d</b> етапів, <b>%d</b> міток, <b>%d</b> hook задач, <b>%d</b> команд, <b>%d</b> оновлень завдань, <b>%d</b> вкладень.
 dashboard.operation_name=Назва операції
 dashboard.operation_switch=Перемикнути
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Запустити
 dashboard.clean_unbind_oauth=Видалити неприв'язані OAuth
 dashboard.clean_unbind_oauth_success=Усі неприв'язані OAuth було знищено.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Конфігурація журналу
 config.log_file_root_path=Повний шлях до Log-файлу
 config.log_mode=Режим

+ 20 - 8
conf/locale/locale_vi-VN.ini

@@ -43,6 +43,10 @@ issues=Các vấn đề
 
 cancel=Hủy bỏ
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=Cài đặt
 title=Cài đặt cho lần chạy đầu tiên
@@ -259,8 +263,7 @@ following=Đang theo dõi
 follow=Theo dõi
 unfollow=Bỏ theo dõi
 
-form.name_reserved=Tên người dùng '%s' đã được dành riêng.
-form.name_pattern_not_allowed=Tên người dùng '%s' là không được phép.
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=Hồ sơ
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=Chủ sở hữu đã đạt giới hạn tối đa %d kho.
-form.name_reserved=Tên kho '%s' đã được dành riêng.
-form.name_pattern_not_allowed=Tên kho '%s' là không được phép.
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=Cần xác thực Ủy quyền
 migrate_type=Migration Type
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=Người dùng này sẽ không có quyền
 settings.remove_collaborator_success=Cộng tác viên đã được gỡ bỏ.
 settings.search_user_placeholder=Tìm kiếm người dùng...
 settings.org_not_allowed_to_be_collaborator=Tổ chức không được phép được thêm vào như là một cộng tác viên.
-settings.add_webhook=Thêm Webhook
 settings.hooks_desc=Webhooks nhiều như cơ bản HTTP bài sự kiện gây nên. Bất cứ khi nào một cái gì đó xảy ra tại Gogs, chúng tôi sẽ xử lý thông báo máy chủ mục tiêu mà bạn chỉ định. Tìm hiểu thêm trong này <a target="_blank" href="%s">Webhooks hướng dẫn</a>.
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=Thêm Webhook
 settings.webhook_deletion=Xóa Webhook
 settings.webhook_deletion_desc=Xóa bỏ điều này webhook sẽ loại bỏ tất cả phân phối lịch sử và thông tin của nó. Bạn có muốn tiếp tục?
 settings.webhook_deletion_success=Webhook đã được xoá thành công!
@@ -801,6 +805,8 @@ settings.webhook.response=Phản hồi
 settings.webhook.headers=Tiêu đề
 settings.webhook.payload=Trả phí
 settings.webhook.body=Nội dung
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git Hooks are powered by Git itself, you can edit files of supported hooks in the list below to perform custom operations.
 settings.githook_edit_desc=If the hook is inactive, sample content will be presented. Leaving content to an empty value will disable this hook.
 settings.githook_name=Tên Hook
@@ -927,9 +933,8 @@ team_name_helper=Bạn sẽ sử dụng tên này đề cập đến nhóm này
 team_desc_helper=Thông tin về nhóm này là gì?
 team_permission_desc=Cấp độ quyền nhóm này có?
 
-form.name_reserved=Tên tổ chức '%s' được dành riêng.
-form.name_pattern_not_allowed=Tên tổ chức '%s' là không được phép.
-form.team_name_reserved=Tên nhóm '%s' được dành riêng.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=Các cài đặt
 settings.options=Tuỳ chọn
@@ -1013,6 +1018,7 @@ dashboard.system_status=Tình trạng quản lý hệ thống
 dashboard.statistic_info=Gogs database có <b>%d</b> users, <b>%d</b> organizations, <b>%d</b> public keys, <b>%d</b> repositories, <b>%d</b> watches, <b>%d</b> stars, <b>%d</b> actions, <b>%d</b> accesses, <b>%d</b> issues, <b>%d</b> comments, <b>%d</b> social accounts, <b>%d</b> follows, <b>%d</b> mirrors, <b>%d</b> releases, <b>%d</b> login sources, <b>%d</b> webhooks, <b>%d</b> milestones, <b>%d</b> labels, <b>%d</b> hook tasks, <b>%d</b> teams, <b>%d</b> update tasks, <b>%d</b> attachments.
 dashboard.operation_name=Tên hành động
 dashboard.operation_switch=Chuyển đổi
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=Chạy
 dashboard.clean_unbind_oauth=Clean unbound OAuthes
 dashboard.clean_unbind_oauth_success=Tất cả các unbind OAuthes đã được xóa thành công.
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=Cấu hình Log
 config.log_file_root_path=Đường dẫn gốc file Log
 config.log_mode=Chế độ

+ 168 - 155
conf/locale/locale_zh-CN.ini

@@ -43,6 +43,10 @@ issues=工单管理
 
 cancel=取消
 
+[status]
+page_not_found=页面未找到
+internal_server_error=内部服务器错误
+
 [install]
 install=安装页面
 title=首次运行安装程序
@@ -121,7 +125,7 @@ run_user_not_match=运行系统用户非当前用户:%s -> %s
 smtp_host_missing_port=SMTP 地址缺少端口号。
 invalid_smtp_from=SMTP From 字段不合法:%v
 save_config_failed=应用配置保存失败:%v
-init_failed=Failed to initialize application: %v
+init_failed=初始化应用程序失败:%v
 invalid_admin_setting=管理员帐户设置不正确:%v
 install_success=您好!我们很高兴您选择使用 Gogs,祝您使用愉快,代码从此无 BUG!
 invalid_log_root_path=无效的日志路径:%v
@@ -259,8 +263,7 @@ following=关注中
 follow=关注
 unfollow=取消关注
 
-form.name_reserved=用户名 '%s' 是被保留的。
-form.name_pattern_not_allowed=用户名不允许 '%s' 的格式。
+form.name_not_allowed=禁止使用用户名或模式 %q
 
 [settings]
 profile=个人信息
@@ -374,7 +377,7 @@ delete_token=删除令牌
 access_token_deletion=删除个人操作令牌操作
 access_token_deletion_desc=删除该个人操作令牌将删除所有相关的应用程序的访问权限。是否继续?
 delete_token_success=个人操作令牌删除成功!请更新与该令牌有关的所有应用。
-token_name_exists=Token with same name already exists.
+token_name_exists=已存在具有相同名称的令牌。
 
 orgs.none=您现在还不是任何组织的成员。
 orgs.leave_title=离开组织
@@ -426,8 +429,7 @@ repo_description_helper=请输入仓库描述,最多为 512 个字符
 repo_description_length=剩余字符数
 
 form.reach_limit_of_creation=该用户已经达到允许创建 %d 个仓库的最大上限。
-form.name_reserved=仓库名称 '%s' 是被保留的。
-form.name_pattern_not_allowed=仓库名称不允许 '%s' 的格式。
+form.name_not_allowed=禁止使用仓库名称或模式 %q
 
 need_auth=需要授权验证
 migrate_type=迁移类型
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=此用户被删除后将不再拥有相关
 settings.remove_collaborator_success=被操作的协作者已经被收回权限!
 settings.search_user_placeholder=搜索用户...
 settings.org_not_allowed_to_be_collaborator=组织不允许被添加为仓库协作者!
-settings.add_webhook=添加 Web 钩子
 settings.hooks_desc=Web 钩子允许您设定在 Gogs 上发生指定事件时对指定 URL 发送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文档</a> 获取更多信息。
+settings.webhooks.add_new=添加新的 Web 钩子:
+settings.webhooks.choose_a_type=选择类型...
+settings.add_webhook=添加 Web 钩子
 settings.webhook_deletion=删除 Web 钩子
 settings.webhook_deletion_desc=删除该 Web 钩子将会删除与其有关的信息和推送历史。是否继续?
 settings.webhook_deletion_success=Web 钩子删除成功!
@@ -801,6 +805,8 @@ settings.webhook.response=响应内容
 settings.webhook.headers=头信息
 settings.webhook.payload=推送内容
 settings.webhook.body=响应体
+settings.webhook.err_cannot_parse_payload_url=无法解析推送 URL:%v
+settings.webhook.err_cannot_use_local_addresses=非管理员不允许使用本地地址
 settings.githooks_desc=Git 钩子是由 Git 本身提供的功能,以下为 Gogs 所支持的钩子列表。
 settings.githook_edit_desc=如果钩子未启动,则会显示样例文件中的内容。如果想要删除某个钩子,则提交空白文本即可。
 settings.githook_name=钩子名称
@@ -927,9 +933,8 @@ team_name_helper=您可以使用该名称来通知该组全体成员。
 team_desc_helper=一句话描述这个团队是做什么的。
 team_permission_desc=请选择该团队所具有的权限等级:
 
-form.name_reserved=组织名称 '%s' 是被保留的。
-form.name_pattern_not_allowed=组织名称不允许 '%s' 的格式。
-form.team_name_reserved=团队名称 '%s' 是被保留的。
+form.name_not_allowed=禁止使用组织名称或模式 %q
+form.team_name_not_allowed=禁止使用团队名称或模式 %q
 
 settings=组织设置
 settings.options=基本设置
@@ -1001,18 +1006,20 @@ first_page=首页
 last_page=末页
 total=总计:%d
 
-dashboard.build_info=Build Information
-dashboard.app_ver=Application version
-dashboard.git_version=Git version
-dashboard.go_version=Go version
-dashboard.build_time=Build time
-dashboard.build_commit=Build commit
+dashboard.build_info=构建信息
+dashboard.app_ver=应用程序版本
+dashboard.git_version=Git 版本
+dashboard.go_version=Go 版本
+dashboard.build_time=编译时间
+dashboard.build_commit=构建提交
+
 dashboard.statistic=应用统计数据
 dashboard.operations=管理员操作
 dashboard.system_status=系统监视状态
 dashboard.statistic_info=Gogs 数据库统计:<b>%d</b> 位用户,<b>%d</b> 个组织,<b>%d</b> 个公钥,<b>%d</b> 个仓库,<b>%d</b> 个仓库关注,<b>%d</b> 个赞,<b>%d</b> 次行为,<b>%d</b> 条权限记录,<b>%d</b> 张工单,<b>%d</b> 次评论,<b>%d</b> 个社交帐号,<b>%d</b> 个用户关注,<b>%d</b> 个镜像,<b>%d</b> 个版本发布,<b>%d</b> 个登录源,<b>%d</b> 个 Web 钩子,<b>%d</b> 个里程碑,<b>%d</b> 个标签,<b>%d</b> 个钩子任务,<b>%d</b> 个团队,<b>%d</b> 个更新任务,<b>%d</b> 个附件。
 dashboard.operation_name=操作名称
 dashboard.operation_switch=开关
+dashboard.select_operation_to_run=请选择要运行的操作
 dashboard.operation_run=执行
 dashboard.clean_unbind_oauth=清理未绑定社交帐号
 dashboard.clean_unbind_oauth_success=所有未绑定社交数据清除成功!
@@ -1158,171 +1165,177 @@ auths.delete_auth_desc=该认证将被删除。是否继续?
 auths.still_in_used=此认证仍旧与一些用户有关联,请先删除或者将这些用户转换为其它登录类型。
 auths.deletion_success=授权源删除成功!
 auths.login_source_exist=登录源 '%s' 已存在。
-auths.github_api_endpoint=API Endpoint
+auths.github_api_endpoint=API 终端
 
 config.not_set=(未设置)
 config.server_config=服务器配置
-config.brand_name=Brand name
+config.brand_name=品牌名称
 config.run_user=运行用户
 config.run_mode=运行模式
-config.server.external_url=External URL
-config.server.domain=Domain
-config.server.protocol=Protocol
-config.server.http_addr=HTTP address
-config.server.http_port=HTTP port
-config.server.cert_file=Certificate file
-config.server.key_file=Key file
-config.server.tls_min_version=Minimum TLS version
-config.server.unix_socket_permission=Unix socket permission
-config.server.local_root_url=Local root URL
-config.server.offline_mode=Offline mode
-config.server.disable_router_log=Disable router log
-config.server.enable_gzip=Enable Gzip
-config.server.app_data_path=Application data path
-config.server.load_assets_from_disk=Load assets from disk
-config.server.landing_url=Landing URL
+config.server.external_url=外部网址
+config.server.domain=域名
+config.server.protocol=协议
+config.server.http_addr=HTTP 地址
+config.server.http_port=HTTP 端口
+config.server.cert_file=证书文件
+config.server.key_file=密钥文件
+config.server.tls_min_version=最低 TLS 版本
+config.server.unix_socket_permission=Unix 套接字权限
+config.server.local_root_url=本地根网址
+config.server.offline_mode=离线模式
+config.server.disable_router_log=禁用路由器日志
+config.server.enable_gzip=启用 Gzip
+config.server.app_data_path=应用程序数据路径
+config.server.load_assets_from_disk=从磁盘加载素材
+config.server.landing_url=登陆网址
 
 config.ssh_config=SSH 配置
-config.ssh.enabled=Enabled
-config.ssh.domain=Exposed domain
-config.ssh.port=Exposed port
-config.ssh.root_path=Root path
-config.ssh.keygen_path=Keygen path
-config.ssh.key_test_path=Key test path
-config.ssh.minimum_key_size_check=Minimum key size check
-config.ssh.minimum_key_sizes=Minimum key sizes
-config.ssh.rewrite_authorized_keys_at_start=Rewrite "authorized_keys" at start
-config.ssh.start_builtin_server=Start builtin server
-config.ssh.listen_host=Listen host
-config.ssh.listen_port=Listen port
-config.ssh.server_ciphers=Server ciphers
+config.ssh.enabled=启用
+config.ssh.domain=显示域名
+config.ssh.port=显示端口
+config.ssh.root_path=根目录
+config.ssh.keygen_path=Keygen 路径
+config.ssh.key_test_path=密钥测试路径
+config.ssh.minimum_key_size_check=最小密钥长度检查
+config.ssh.minimum_key_sizes=最短秘钥长度
+config.ssh.rewrite_authorized_keys_at_start=在启动时重写 "authorized_keys" 文件
+config.ssh.start_builtin_server=启动内置服务器
+config.ssh.listen_host=监听主机
+config.ssh.listen_port=监听端口
+config.ssh.server_ciphers=服务端加密套件
 
 config.repo_config=仓库配置
-config.repo.root_path=Root path
-config.repo.script_type=Script type
-config.repo.ansi_chatset=ANSI charset
-config.repo.force_private=Force private
-config.repo.max_creation_limit=Max creation limit
-config.repo.preferred_licenses=Preferred licenses
-config.repo.disable_http_git=Disable HTTP Git
-config.repo.enable_local_path_migration=Enable local path migration
-config.repo.enable_raw_file_render_mode=Enable raw file render mode
-config.repo.commits_fetch_concurrency=Commits fetch concurrency
-config.repo.editor.line_wrap_extensions=Editor line wrap extensions
-config.repo.editor.previewable_file_modes=Editor previewable file modes
-config.repo.upload.enabled=Upload enabled
-config.repo.upload.temp_path=Upload temporary path
-config.repo.upload.allowed_types=Upload allowed types
-config.repo.upload.file_max_size=Upload file size limit
-config.repo.upload.max_files=Upload files limit
+config.repo.root_path=根目录
+config.repo.script_type=脚本类型
+config.repo.ansi_chatset=ANSI 字符集
+config.repo.force_private=强制设为私有
+config.repo.max_creation_limit=最大创建限制
+config.repo.preferred_licenses=推荐的许可证
+config.repo.disable_http_git=禁用 HTTP Git
+config.repo.enable_local_path_migration=启用本地路径迁移
+config.repo.enable_raw_file_render_mode=启用原始文件渲染模式
+config.repo.commits_fetch_concurrency=代码提交拉取并发量
+config.repo.editor.line_wrap_extensions=编辑器行自动换行扩展
+config.repo.editor.previewable_file_modes=编辑器可预览文件模式
+config.repo.upload.enabled=启用上传
+config.repo.upload.temp_path=上传文件临时路径
+config.repo.upload.allowed_types=允许的上传类型
+config.repo.upload.file_max_size=上传文件大小限制
+config.repo.upload.max_files=上传文件数量限制
 
 config.db_config=数据库配置
-config.db.type=Type
-config.db.host=Host
-config.db.name=Name
-config.db.user=User
-config.db.ssl_mode=SSL mode
-config.db.ssl_mode_helper=(for "postgres" only)
-config.db.path=Path
-config.db.path_helper=(for "sqlite3"only)
-
-config.security_config=Security configuration
-config.security.login_remember_days=Login remember days
-config.security.cookie_remember_name=Remember cookie
-config.security.cookie_username=Username cookie
-config.security.cookie_secure=Enable secure cookie
-config.security.reverse_proxy_auth_user=Reverse proxy authentication header
-config.security.enable_login_status_cookie=Enable login status cookie
-config.security.login_status_cookie_name=Login status cookie
-
-config.email_config=Email configuration
-config.email.enabled=Enabled
-config.email.subject_prefix=Subject prefix
-config.email.host=Host
-config.email.from=From
-config.email.user=User
-config.email.disable_helo=Disable HELO
-config.email.helo_hostname=HELO hostname
-config.email.skip_verify=Skip certificate verify
-config.email.use_certificate=Use custom certificate
-config.email.cert_file=Certificate file
-config.email.key_file=Key file
-config.email.use_plain_text=Use plain text
-config.email.add_plain_text_alt=Add plain text alternative
-config.email.send_test_mail=Send test email
-config.email.test_mail_failed=Failed to send test email to '%s': %v
-config.email.test_mail_sent=Test email has been sent to '%s'.
-
-config.auth_config=Authentication configuration
-config.auth.activate_code_lives=Activate code lives
-config.auth.reset_password_code_lives=Reset password code lives
-config.auth.require_email_confirm=Require email confirmation
-config.auth.require_sign_in_view=Require sign in view
-config.auth.disable_registration=Disable registration
-config.auth.enable_registration_captcha=Enable registration captcha
-config.auth.enable_reverse_proxy_authentication=Enable reverse proxy authentication
-config.auth.enable_reverse_proxy_auto_registration=Enable reverse proxy auto registration
-config.auth.reverse_proxy_authentication_header=Reverse proxy authentication header
-
-config.user_config=User configuration
-config.user.enable_email_notify=Enable email notification
+config.db.type=类型
+config.db.host=主机
+config.db.name=名称
+config.db.user=用户
+config.db.ssl_mode=SSL 模式
+config.db.ssl_mode_helper=(仅限 "postgres" 使用)
+config.db.path=数据库路径
+config.db.path_helper=(仅限 "sqlite3" 使用)
+config.db.max_open_conns=最大打开连接数
+config.db.max_idle_conns=最大空闲连接数
+
+config.security_config=安全配置
+config.security.login_remember_days=记住登录的天数
+config.security.cookie_remember_name=记住登录 Cookie
+config.security.cookie_username=用户名 Cookie
+config.security.cookie_secure=启用安全的 Cookie
+config.security.reverse_proxy_auth_user=反向代理认证 Header
+config.security.enable_login_status_cookie=启用登录状态 Cookie
+config.security.login_status_cookie_name=登录状态 Cookie
+
+config.email_config=邮件配置
+config.email.enabled=启用
+config.email.subject_prefix=主题前缀
+config.email.host=主机
+config.email.from=来自
+config.email.user=用户
+config.email.disable_helo=禁用 HELO
+config.email.helo_hostname=HELO 主机名
+config.email.skip_verify=忽略证书验证
+config.email.use_certificate=使用自定义证书
+config.email.cert_file=证书文件
+config.email.key_file=密钥文件
+config.email.use_plain_text=使用纯文本
+config.email.add_plain_text_alt=添加纯文本选项
+config.email.send_test_mail=发送测试邮件
+config.email.test_mail_failed=发送测试邮件至 '%s' 时失败:%v
+config.email.test_mail_sent=测试邮件已经发送至 '%s'。
+
+config.auth_config=认证配置
+config.auth.activate_code_lives=激活用户链接有效期
+config.auth.reset_password_code_lives=重置密码链接有效期
+config.auth.require_email_confirm=注册邮件确认
+config.auth.require_sign_in_view=需要登录后浏览
+config.auth.disable_registration=关闭注册功能
+config.auth.enable_registration_captcha=启用注册验证码
+config.auth.enable_reverse_proxy_authentication=启用反向代理认证
+config.auth.enable_reverse_proxy_auto_registration=启用反向代理自动注册
+config.auth.reverse_proxy_authentication_header=反向代理认证 Header
+
+config.user_config=用户配置
+config.user.enable_email_notify=启用电子邮件通知
 
 config.session_config=Session 配置
-config.session.provider=Provider
-config.session.provider_config=Provider config
+config.session.provider=提供者
+config.session.provider_config=提供者配置
 config.session.cookie_name=Cookie
-config.session.https_only=HTTPS only
-config.session.gc_interval=GC interval
-config.session.max_life_time=Max life time
-config.session.csrf_cookie_name=CSRF cookie
+config.session.https_only=仅限 HTTPS
+config.session.gc_interval=GC 间隔
+config.session.max_life_time=最大生命周期
+config.session.csrf_cookie_name=CSRF Cookie
 
 config.cache_config=Cache 配置
-config.cache.adapter=Adapter
-config.cache.interval=GC interval
-config.cache.host=Host
+config.cache.adapter=适配器
+config.cache.interval=GC 间隔
+config.cache.host=主机
 
 config.http_config=HTTP 配置
-config.http.access_control_allow_origin=Access control allow origin
+config.http.access_control_allow_origin=允许访问来源控制
 
-config.attachment_config=Attachment configuration
-config.attachment.enabled=Enabled
-config.attachment.path=Path
-config.attachment.allowed_types=Allowed types
-config.attachment.max_size=Size limit
-config.attachment.max_files=Files limit
+config.attachment_config=附件配置
+config.attachment.enabled=启用
+config.attachment.path=路径
+config.attachment.allowed_types=允许的类型
+config.attachment.max_size=大小限制
+config.attachment.max_files=文件数量限制
 
-config.release_config=Release configuration
-config.release.attachment.enabled=Attachment enabled
-config.release.attachment.allowed_types=Attachment allowed types
-config.release.attachment.max_size=Attachment size limit
-config.release.attachment.max_files=Attachment files limit
+config.release_config=发布配置
+config.release.attachment.enabled=启用附件
+config.release.attachment.allowed_types=允许的附件类型
+config.release.attachment.max_size=附件大小限制
+config.release.attachment.max_files=附件文件数量限制
 
 config.picture_config=图片配置
-config.picture.avatar_upload_path=User avatar upload path
-config.picture.repo_avatar_upload_path=Repository avatar upload path
-config.picture.gravatar_source=Gravatar source
-config.picture.disable_gravatar=Disable Gravatar
-config.picture.enable_federated_avatar=Enable federated avatars
+config.picture.avatar_upload_path=用户头像上传路径
+config.picture.repo_avatar_upload_path=仓库头像上传路径
+config.picture.gravatar_source=Gravatar 
+config.picture.disable_gravatar=禁用 Gravatar 头像
+config.picture.enable_federated_avatar=启用 Federated 头像
 
-config.mirror_config=Mirror configuration
-config.mirror.default_interval=Default interval
+config.mirror_config=镜像配置
+config.mirror.default_interval=默认同步间隔
 
 config.webhook_config=Web 钩子配置
-config.webhook.types=Types
-config.webhook.deliver_timeout=Deliver timeout
-config.webhook.skip_tls_verify=Skip TLS verify
+config.webhook.types=类型
+config.webhook.deliver_timeout=推送超时
+config.webhook.skip_tls_verify=忽略 TLS 验证
 
 config.git_config=Git 配置
-config.git.disable_diff_highlight=Disable diff syntax highlight
-config.git.max_diff_lines=Diff lines limit (for a single file)
-config.git.max_diff_line_characters=Diff characters limit (for a single line)
-config.git.max_diff_files=Diff files limit (for a single diff)
-config.git.gc_args=GC arguments
-config.git.migrate_timeout=Migration timeout
-config.git.mirror_timeout=Mirror fetch timeout
-config.git.clone_timeout=Clone timeout
-config.git.pull_timeout=Pull timeout
-config.git.gc_timeout=GC timeout
+config.git.disable_diff_highlight=禁用差异对比语法高亮
+config.git.max_diff_lines=差异行限制(单个文件)
+config.git.max_diff_line_characters=差异字符限制(单行)
+config.git.max_diff_files=差异文件数量限制(单次提交)
+config.git.gc_args=GC 参数
+config.git.migrate_timeout=迁移超时
+config.git.mirror_timeout=镜像拉取超时
+config.git.clone_timeout=克隆超时
+config.git.pull_timeout=拉取超时
+config.git.gc_timeout=GC 超时
+
+config.lfs_config=LFS 配置
+config.lfs.storage=存储方式
+config.lfs.objects_path=对象路径
 
 config.log_config=日志配置
 config.log_file_root_path=日志文件根目录
@@ -1397,7 +1410,7 @@ months=%d 月%s
 years=%d 年%s
 raw_seconds=秒
 raw_minutes=分钟
-raw_hours=hours
+raw_hours=小时
 
 [dropzone]
 default_message=拖曳文件到此处或单击上传

+ 20 - 8
conf/locale/locale_zh-HK.ini

@@ -43,6 +43,10 @@ issues=問題
 
 cancel=取消
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=安裝頁面
 title=首次安裝步驟
@@ -259,8 +263,7 @@ following=關注中
 follow=關注
 unfollow=取消關注
 
-form.name_reserved=用戶名 '%s' 是被保留的。
-form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=個人信息
@@ -426,8 +429,7 @@ repo_description_helper=Description of repository. Maximum 512 characters length
 repo_description_length=Available characters
 
 form.reach_limit_of_creation=擁有者已達到儲存庫最大的新增上限 %d。
-form.name_reserved=倉庫名稱 '%s' 是被保留的。
-form.name_pattern_not_allowed=倉庫名稱不允許 '%s' 的格式。
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=需要授權驗證
 migrate_type=遷移類型
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=This user will no longer have collaboration
 settings.remove_collaborator_success=被操作的協作者已經被收回權限!
 settings.search_user_placeholder=搜索用戶...
 settings.org_not_allowed_to_be_collaborator=Organization is not allowed to be added as a collaborator.
-settings.add_webhook=添加 Web 鉤子
 settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
+settings.add_webhook=添加 Web 鉤子
 settings.webhook_deletion=刪除 Web 鉤子
 settings.webhook_deletion_desc=刪除該 Web 鉤子將會刪除與其有關的信息和推送歷史。是否繼續?
 settings.webhook_deletion_success=Web 鉤子刪除成功!
@@ -801,6 +805,8 @@ settings.webhook.response=響應內容
 settings.webhook.headers=標題
 settings.webhook.payload=推送內容
 settings.webhook.body=響應內容
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
 settings.githooks_desc=Git 鉤子是由 Git 本身提供的功能,以下為 Gogs 所支持的鉤子列表。
 settings.githook_edit_desc=如果鉤子未啟動,則會顯示樣例文件中的內容。如果想要刪除某個鉤子,則提交空白文本即可。
 settings.githook_name=鉤子名稱
@@ -927,9 +933,8 @@ team_name_helper=您可以使用該名稱來通知改組全體成員。
 team_desc_helper=一句話描述這個團隊是做什麼的。
 team_permission_desc=請選擇該團隊所具有的權限等級:
 
-form.name_reserved=組織名稱 '%s' 是被保留的。
-form.name_pattern_not_allowed=組織名稱不允許 '%s' 的格式。
-form.team_name_reserved=Team name '%s' is reserved.
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=組織設置
 settings.options=基本設置
@@ -1013,6 +1018,7 @@ dashboard.system_status=系統監視狀態
 dashboard.statistic_info=Gogs 數據庫統計:<b>%d</b> 位用戶,<b>%d</b> 個組織,<b>%d</b> 個公鑰,<b>%d</b> 個倉庫,<b>%d</b> 個倉庫關注,<b>%d</b> 個贊,<b>%d</b> 次行為,<b>%d</b> 條權限記錄,<b>%d</b> 個問題,<b>%d</b> 次評論,<b>%d</b> 個社交帳號,<b>%d</b> 個用戶關注,<b>%d</b> 個鏡像,<b>%d</b> 個版本發佈,<b>%d</b> 個登錄源,<b>%d</b> 個 Web 鉤子,<b>%d</b> 個里程碑,<b>%d</b> 個標籤,<b>%d</b> 個鉤子任務,<b>%d</b> 個團隊,<b>%d</b> 個更新任務,<b>%d</b> 個附件。
 dashboard.operation_name=操作名稱
 dashboard.operation_switch=開關
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=執行
 dashboard.clean_unbind_oauth=清理未綁定社交帳號
 dashboard.clean_unbind_oauth_success=所有未綁定社交數據清除成功!
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=日誌配置
 config.log_file_root_path=日志文件根目錄
 config.log_mode=Mode

+ 21 - 9
conf/locale/locale_zh-TW.ini

@@ -43,6 +43,10 @@ issues=問題
 
 cancel=取消
 
+[status]
+page_not_found=Page Not Found
+internal_server_error=Internal Server Error
+
 [install]
 install=安裝頁面
 title=首次安裝步驟
@@ -259,8 +263,7 @@ following=關注中
 follow=關注
 unfollow=取消關注
 
-form.name_reserved=用戶名 '%s' 是被保留的。
-form.name_pattern_not_allowed=用戶名不允許 '%s' 的格式。
+form.name_not_allowed=User name or pattern %q is not allowed.
 
 [settings]
 profile=個人資訊
@@ -426,8 +429,7 @@ repo_description_helper=儲存庫的說明文字。最長 512 個字元。
 repo_description_length=可用字元
 
 form.reach_limit_of_creation=擁有者已達到儲存庫最大的新增上限 %d。
-form.name_reserved=倉庫名稱 '%s' 是被保留的。
-form.name_pattern_not_allowed=倉庫名稱不允許 '%s' 的格式。
+form.name_not_allowed=Repository name or pattern %q is not allowed.
 
 need_auth=需要授權驗證
 migrate_type=遷移類型
@@ -786,8 +788,10 @@ settings.collaborator_deletion_desc=刪除後此使用者將不再有協同者
 settings.remove_collaborator_success=被操作的協作者已經被收回權限!
 settings.search_user_placeholder=搜索用戶...
 settings.org_not_allowed_to_be_collaborator=組織不允許被加為協同者。
+settings.hooks_desc=Web 鉤子允許您設定在 Gogs 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
+settings.webhooks.add_new=Add a new webhook:
+settings.webhooks.choose_a_type=Choose a type...
 settings.add_webhook=添加 Web 鉤子
-settings.hooks_desc=Web 鉤子允許您設定在 GIN 上發生指定事件時對指定 URL 發送 POST 通知。查看 <a target="_blank" href="%s">Webhooks 文檔</a> 獲取更多信息。
 settings.webhook_deletion=刪除 Web 鉤子
 settings.webhook_deletion_desc=刪除該 Web 鉤子將會刪除與其有關的信息和推送歷史。是否繼續?
 settings.webhook_deletion_success=Web 鉤子刪除成功!
@@ -801,7 +805,9 @@ settings.webhook.response=響應內容
 settings.webhook.headers=標題
 settings.webhook.payload=推送內容
 settings.webhook.body=響應內容
-settings.githooks_desc=Git 鉤子是由 Git 本身提供的功能,以下為 GIN 所支持的鉤子列表。
+settings.webhook.err_cannot_parse_payload_url=Cannot parse payload URL: %v
+settings.webhook.err_cannot_use_local_addresses=Non admins are not allowed to use local addresses.
+settings.githooks_desc=Git 鉤子是由 Git 本身提供的功能,以下為 Gogs 所支持的鉤子列表。
 settings.githook_edit_desc=如果鉤子未啟動,則會顯示樣例文件中的內容。如果想要刪除某個鉤子,則提交空白文本即可。
 settings.githook_name=鉤子名稱
 settings.githook_content=鉤子文本
@@ -927,9 +933,8 @@ team_name_helper=您可以使用該名稱來通知改組全體成員。
 team_desc_helper=一句話描述這個團隊是做什麼的。
 team_permission_desc=請選擇該團隊所具有的權限等級:
 
-form.name_reserved=組織名稱 '%s' 是被保留的。
-form.name_pattern_not_allowed=組織名稱不允許 '%s' 的格式。
-form.team_name_reserved=團隊名稱 '%s' 已被保留。
+form.name_not_allowed=Organization name or pattern %q is not allowed.
+form.team_name_not_allowed=Team name or pattern %q is not allowed.
 
 settings=組織設置
 settings.options=基本設置
@@ -1013,6 +1018,7 @@ dashboard.system_status=系統監視狀態
 dashboard.statistic_info=GIN 資料庫統計:<b>%d</b> 位用戶,<b>%d</b> 個組織,<b>%d</b> 個公鑰,<b>%d</b> 個倉庫,<b>%d</b> 個倉庫關注,<b>%d</b> 個讚,<b>%d</b> 次行為,<b>%d</b> 條權限記錄,<b>%d</b> 個問題,<b>%d</b> 次評論,<b>%d</b> 個社交帳號,<b>%d</b> 個用戶關注,<b>%d</b> 個鏡像,<b>%d</b> 個版本發佈,<b>%d</b> 個登錄來源,<b>%d</b> 個 Web 鉤子,<b>%d</b> 個里程碑,<b>%d</b> 個標籤,<b>%d</b> 個鉤子任務,<b>%d</b> 個團隊,<b>%d</b> 個更新任務,<b>%d</b> 個附件。
 dashboard.operation_name=操作名稱
 dashboard.operation_switch=開關
+dashboard.select_operation_to_run=Please select operation to run
 dashboard.operation_run=執行
 dashboard.clean_unbind_oauth=清理未綁定社交帳號
 dashboard.clean_unbind_oauth_success=所有未綁定社交數據清除成功!
@@ -1225,6 +1231,8 @@ config.db.ssl_mode=SSL mode
 config.db.ssl_mode_helper=(for "postgres" only)
 config.db.path=Path
 config.db.path_helper=(for "sqlite3"only)
+config.db.max_open_conns=Maximum open connections
+config.db.max_idle_conns=Maximum idle connections
 
 config.security_config=Security configuration
 config.security.login_remember_days=Login remember days
@@ -1324,6 +1332,10 @@ config.git.clone_timeout=Clone timeout
 config.git.pull_timeout=Pull timeout
 config.git.gc_timeout=GC timeout
 
+config.lfs_config=LFS configuration
+config.lfs.storage=Storage
+config.lfs.objects_path=Objects path
+
 config.log_config=日誌配置
 config.log_file_root_path=日志文件根目錄
 config.log_mode=模式

+ 44 - 0
docker/Dockerfile.aarch64

@@ -0,0 +1,44 @@
+FROM arm64v8/golang:1.14-alpine3.11 AS binarybuilder
+RUN apk --no-cache --no-progress add --virtual \
+  build-deps \
+  build-base \
+  git \
+  linux-pam-dev
+
+WORKDIR /gogs.io/gogs
+COPY . .
+RUN make build-no-gen TAGS="cert pam"
+
+FROM arm64v8/alpine:3.11
+ADD https://github.com/tianon/gosu/releases/download/1.11/gosu-arm64 /usr/sbin/gosu
+RUN chmod +x /usr/sbin/gosu \
+  && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
+  && apk --no-cache --no-progress add \
+  bash \
+  ca-certificates \
+  curl \
+  git \
+  linux-pam \
+  openssh \
+  s6 \
+  shadow \
+  socat \
+  tzdata \
+  rsync
+
+ENV GOGS_CUSTOM /data/gogs
+
+# Configure LibC Name Service
+COPY docker/nsswitch.conf /etc/nsswitch.conf
+
+WORKDIR /app/gogs
+COPY docker ./docker
+COPY --from=binarybuilder /gogs.io/gogs/gogs .
+
+RUN ./docker/finalize.sh
+
+# Configure Docker Container
+VOLUME ["/data", "/backup"]
+EXPOSE 22 3000
+ENTRYPOINT ["/app/gogs/docker/start.sh"]
+CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

+ 44 - 0
docker/Dockerfile.rpi

@@ -0,0 +1,44 @@
+FROM arm32v7/golang:1.14-alpine3.11 AS binarybuilder
+RUN apk --no-cache --no-progress add --virtual \
+  build-deps \
+  build-base \
+  git \
+  linux-pam-dev
+
+WORKDIR /gogs.io/gogs
+COPY . .
+RUN make build-no-gen TAGS="cert pam"
+
+FROM arm32v7/alpine:3.11
+ADD https://github.com/tianon/gosu/releases/download/1.12/gosu-armhf /usr/sbin/gosu
+RUN chmod +x /usr/sbin/gosu \
+  && echo http://dl-2.alpinelinux.org/alpine/edge/community/ >> /etc/apk/repositories \
+  && apk --no-cache --no-progress add \
+  bash \
+  ca-certificates \
+  curl \
+  git \
+  linux-pam \
+  openssh \
+  s6 \
+  shadow \
+  socat \
+  tzdata \
+  rsync
+
+ENV GOGS_CUSTOM /data/gogs
+
+# Configure LibC Name Service
+COPY docker/nsswitch.conf /etc/nsswitch.conf
+
+WORKDIR /app/gogs
+COPY docker ./docker
+COPY --from=binarybuilder /gogs.io/gogs/gogs .
+
+RUN ./docker/finalize.sh
+
+# Configure Docker Container
+VOLUME ["/data", "/backup"]
+EXPOSE 22 3000
+ENTRYPOINT ["/app/gogs/docker/start.sh"]
+CMD ["/bin/s6-svscan", "/app/gogs/docker/s6/"]

+ 40 - 2
docker/README.md

@@ -73,13 +73,13 @@ $ 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 `build.sh` already setup a user with name `git`.
+- **Run User**: keep it as default value `git` because `finalize.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.
 - **Application URL**: Use combination of **Domain** and **exposed HTTP Port** values (e.g. `http://192.168.99.100:10080/`).
 
-Full documentation of application settings can be found [here](https://gogs.io/docs/advanced/configuration_cheat_sheet.html).
+Full documentation of application settings can be found [here](https://github.com/gogs/gogs/blob/master/conf/app.ini).
 
 ### Container Options
 
@@ -102,6 +102,44 @@ This container have some options available via environment variables, these opti
       `false`
   - <u>Action:</u>
       Request crond to be run inside the container. Its default configuration will periodically run all scripts from `/etc/periodic/${period}` but custom crontabs can be added to `/var/spool/cron/crontabs/`.
+- **BACKUP_INTERVAL**:
+  - <u>Possible value:</u>
+      `3h`, `7d`, `3M`
+  - <u>Default:</u>
+      `null`
+  - <u>Action:</u>
+      In combination with `RUN_CROND` set to `true`, enables backup system.\
+      See: [Backup System](#backup-system)
+- **BACKUP_RETENTION**:
+  - <u>Possible value:</u>
+      `360m`, `7d`, `...m/d`
+  - <u>Default:</u>
+      `7d`
+  - <u>Action:</u>
+      Used by backup system. Backups older than specified in expression are deleted periodically.\
+      See: [Backup System](#backup-system)
+- **BACKUP_ARG_CONFIG**:
+  - <u>Possible value:</u>
+      `/app/gogs/example/custom/config`
+  - <u>Default:</u>
+      `null`
+  - <u>Action:</u>
+      Used by backup system. If defined, supplies `--config` argument to `gogs backup`.\
+      See: [Backup System](#backup-system)
+- **BACKUP_ARG_EXCLUDE_REPOS**:
+  - <u>Possible value:</u>
+      `test-repo1`, `test-repo2`
+  - <u>Default:</u>
+      `null`
+  - <u>Action:</u>
+      Used by backup system. If defined, supplies `--exclude-repos` argument to `gogs backup`.\
+      See: [Backup System](#backup-system)
+
+## Backup System
+Automated backups with retention policy:
+
+- `BACKUP_INTERVAL` controls how often the backup job runs and supports interval in hours (h), days (d), and months (M), eg. `3h`, `7d`, `3M`. The lowest possible value is one hour (`1h`).
+- `BACKUP_RETENTION` supports expressions in minutes (m) and days (d), eg. `360m`, `2d`. The lowest possible value is 60 minutes (`60m`).
 
 ## Upgrade
 

+ 0 - 3
docker/aarch64/build.sh

@@ -1,3 +0,0 @@
-#!/bin/bash
-
-go build -ldflags "-w -s" resin-xbuild.go

二进制
docker/aarch64/qemu-aarch64-static


二进制
docker/aarch64/resin-xbuild


+ 0 - 66
docker/aarch64/resin-xbuild.go

@@ -1,66 +0,0 @@
-package main
-
-import (
-	"log"
-	"os"
-	"os/exec"
-	"syscall"
-)
-
-func crossBuildStart() {
-	err := os.Remove("/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-	err = os.Link("/usr/bin/resin-xbuild", "/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-func crossBuildEnd() {
-	err := os.Remove("/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-	err = os.Link("/bin/sh.real", "/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-func runShell() error {
-	cmd := exec.Command("/usr/bin/qemu-aarch64-static", append([]string{"-0", "/bin/sh", "/bin/sh"}, os.Args[1:]...)...)
-	cmd.Stdin = os.Stdin
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	return cmd.Run()
-}
-
-func main() {
-	switch os.Args[0] {
-	case "cross-build-start":
-		crossBuildStart()
-	case "cross-build-end":
-		crossBuildEnd()
-	case "/bin/sh":
-		code := 0
-		crossBuildEnd()
-
-		if err := runShell(); err != nil {
-			code = 1
-			if exiterr, ok := err.(*exec.ExitError); ok {
-				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
-					code = status.ExitStatus()
-				}
-			}
-		}
-
-		crossBuildStart()
-
-		// Hack to bypass apk issues with triggering
-		code = 0
-
-		os.Exit(code)
-	}
-}

+ 0 - 3
docker/armhf/build.sh

@@ -1,3 +0,0 @@
-#!/bin/bash
-
-go build -ldflags "-w -s" resin-xbuild.go

二进制
docker/armhf/qemu-arm-static


二进制
docker/armhf/resin-xbuild


+ 0 - 66
docker/armhf/resin-xbuild.go

@@ -1,66 +0,0 @@
-package main
-
-import (
-	"log"
-	"os"
-	"os/exec"
-	"syscall"
-)
-
-func crossBuildStart() {
-	err := os.Remove("/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-	err = os.Link("/usr/bin/resin-xbuild", "/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-func crossBuildEnd() {
-	err := os.Remove("/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-	err = os.Link("/bin/sh.real", "/bin/sh")
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-func runShell() error {
-	cmd := exec.Command("/usr/bin/qemu-arm-static", append([]string{"-0", "/bin/sh", "/bin/sh"}, os.Args[1:]...)...)
-	cmd.Stdin = os.Stdin
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	return cmd.Run()
-}
-
-func main() {
-	switch os.Args[0] {
-	case "cross-build-start":
-		crossBuildStart()
-	case "cross-build-end":
-		crossBuildEnd()
-	case "/bin/sh":
-		code := 0
-		crossBuildEnd()
-
-		if err := runShell(); err != nil {
-			code = 1
-			if exiterr, ok := err.(*exec.ExitError); ok {
-				if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
-					code = status.ExitStatus()
-				}
-			}
-		}
-
-		crossBuildStart()
-
-		// Hack to bypass apk issues with triggering
-		code = 0
-
-		os.Exit(code)
-	}
-}

+ 0 - 32
docker/build-go.sh

@@ -1,32 +0,0 @@
-#!/bin/sh
-# Build GO version as specified in Dockerfile
-
-set -x
-set -e
-
-# Components versions
-export GOLANG_VERSION="1.8"
-export GOLANG_SRC_URL="https://golang.org/dl/go$GOLANG_VERSION.src.tar.gz"
-export GOLANG_SRC_SHA256="406865f587b44be7092f206d73fc1de252600b79b3cacc587b74b5ef5c623596"
-
-
-# Install build tools
-apk add --no-cache --no-progress --virtual build-deps-go gcc musl-dev openssl go
-
-export GOROOT_BOOTSTRAP="$(go env GOROOT)"
-
-# Download Go
-wget -q "$GOLANG_SRC_URL" -O golang.tar.gz
-echo "$GOLANG_SRC_SHA256  golang.tar.gz" | sha256sum -c -
-tar -C /usr/local -xzf golang.tar.gz
-rm golang.tar.gz
-
-# Build
-cd /usr/local/go/src
-# see https://golang.org/issue/14851
-patch -p2 -i /app/gogs/build/docker/no-pic.patch
-./make.bash
-
-# Clean
-rm /app/gogs/build/docker/*.patch
-apk del build-deps-go

+ 0 - 31
docker/build.sh

@@ -1,31 +0,0 @@
-#!/bin/sh
-set -x
-set -e
-
-# Set temp environment vars
-export GOPATH=/tmp/go
-export PATH=/usr/local/go/bin:${PATH}:${GOPATH}/bin
-
-# Install build deps
-apk --no-cache --no-progress add --virtual build-deps build-base linux-pam-dev
-
-# Build Gogs
-mkdir -p ${GOPATH}/src/github.com/gogs/
-ln -s /app/gogs/build ${GOPATH}/src/github.com/gogs/gogs
-cd ${GOPATH}/src/github.com/gogs/gogs
-# Needed since git 2.9.3 or 2.9.4
-git config --global http.https://gopkg.in.followRedirects true
-make build TAGS="sqlite cert pam"
-
-# Cleanup GOPATH
-rm -r $GOPATH
-
-# Remove build deps
-apk --no-progress del build-deps
-
-# Move to final place
-mv /app/gogs/build/gogs /app/gogs/
-
-# Cleanup go
-rm -rf /tmp/go
-rm -rf /usr/local/go

+ 0 - 2
docker/finalize.sh

@@ -11,8 +11,6 @@ echo "export GOGS_CUSTOM=${GOGS_CUSTOM}" >> /etc/profile
 
 # Final cleaning
 rm -rf /app/gogs/build
-rm /app/gogs/docker/build.sh
-rm /app/gogs/docker/build-go.sh
 rm /app/gogs/docker/finalize.sh
 rm /app/gogs/docker/nsswitch.conf
 rm /app/gogs/docker/README.md

+ 0 - 16
docker/no-pic.patch

@@ -1,16 +0,0 @@
-diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
-index 14f4fa9..5599307 100644
---- a/src/cmd/link/internal/ld/lib.go
-+++ b/src/cmd/link/internal/ld/lib.go
-@@ -1272,6 +1272,11 @@ func hostlink() {
- 		argv = append(argv, peimporteddlls()...)
- 	}
- 
-+	// The Go linker does not currently support building PIE
-+	// executables when using the external linker. See:
-+	// https://github.com/golang/go/issues/6940
-+	argv = append(argv, "-fno-PIC")
-+
- 	if l.Debugvlog != 0 {
- 		l.Logf("%5.2f host link:", obj.Cputime())
- 		for _, v := range argv {

+ 140 - 0
docker/runtime/backup-init.sh

@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+set -e
+
+BACKUP_PATH="/backup"
+
+# Make sure that required directories exist
+mkdir -p "${BACKUP_PATH}"
+mkdir -p "/etc/crontabs"
+chown git:git /backup
+chmod 2770 /backup
+
+# [string] BACKUP_INTERVAL   Period expression
+# [string] BACKUP_RETENTION  Period expression
+if [ -z "${BACKUP_INTERVAL}" ]; then
+	echo "Backup disabled: BACKUP_INTERVAL has not been found" 1>&2
+	exit 1
+fi
+
+if [ -z "${BACKUP_RETENTION}" ]; then
+	echo "Backup retention period is not defined, default to 7 days" 1>&2
+	BACKUP_RETENTION='7d'
+fi
+
+# Parse BACKUP_INTERVAL environment variable and generate appropriate cron expression. Backup cron task will be run as scheduled.
+# Expected format: nu (n - number, u - unit) (eg. 3d means 3 days)
+# Supported units: h - hours, d - days, M - months
+parse_generate_cron_expression() {
+	CRON_EXPR_MINUTES="*"
+	CRON_EXPR_HOURS="*"
+	CRON_EXPR_DAYS="*"
+	CRON_EXPR_MONTHS="*"
+
+	TIME_INTERVAL=$(echo "${BACKUP_INTERVAL}" | sed -e 's/[hdM]$//')
+	TIME_UNIT=$(echo "${BACKUP_INTERVAL}" | sed -e 's/^[0-9]\+//')
+
+	if [ "${TIME_UNIT}" = "h" ]; then
+		if [ ! "${TIME_INTERVAL}" -le 23 ]; then
+			echo "Parse error: Time unit 'h' (hour) cannot be greater than 23" 1>&2
+			exit 1
+		fi
+
+		CRON_EXPR_MINUTES=0
+		CRON_EXPR_HOURS="*/${TIME_INTERVAL}"
+	elif [ "${TIME_UNIT}" = "d" ]; then
+		if [ ! "${TIME_INTERVAL}" -le 30 ]; then
+			echo "Parse error: Time unit 'd' (day) cannot be greater than 30" 1>&2
+			exit 1
+		fi
+
+		CRON_EXPR_MINUTES=0
+		CRON_EXPR_HOURS=0
+		CRON_EXPR_DAYS="*/${TIME_INTERVAL}"
+	elif [ "${TIME_UNIT}" = "M" ]; then
+		if [ ! "${TIME_INTERVAL}" -le 12 ]; then
+			echo "Parse error: Time unit 'M' (month) cannot be greater than 12" 1>&2
+			exit 1
+		fi
+
+		CRON_EXPR_MINUTES=0
+		CRON_EXPR_HOURS=0
+		CRON_EXPR_DAYS="1"
+		CRON_EXPR_MONTHS="*/${TIME_INTERVAL}"
+	else
+		echo "Parse error: BACKUP_INTERVAL expression is invalid" 1>&2
+		exit 1
+	fi
+
+	echo "${CRON_EXPR_MINUTES} ${CRON_EXPR_HOURS} ${CRON_EXPR_DAYS} ${CRON_EXPR_MONTHS} *"
+}
+
+# Parse BACKUP_RETENTION environment variable and generate appropriate find command expression.
+# Expected format: nu (n - number, u - unit) (eg. 3d means 3 days)
+# Supported units: m - minutes, d - days
+parse_generate_retention_expression() {
+	FIND_TIME_EXPR='mtime'
+
+	TIME_INTERVAL=$(echo "${BACKUP_RETENTION}" | sed -e 's/[mhdM]$//')
+	TIME_UNIT=$(echo "${BACKUP_RETENTION}" | sed -e 's/^[0-9]\+//')
+
+	if [ "${TIME_UNIT}" = "m" ]; then
+		if [ "${TIME_INTERVAL}" -le 59 ]; then
+			echo "Warning: Minimal retention is 60m. Value set to 60m" 1>&2
+			TIME_INTERVAL=60
+		fi
+
+		FIND_TIME_EXPR="mmin"
+	elif [ "${TIME_UNIT}" = "h" ]; then
+		echo "Error: Unsupported expression - Try: eg. 120m for 2 hours." 1>&2
+		exit 1
+	elif [ "${TIME_UNIT}" = "d" ]; then
+		FIND_TIME_EXPR="mtime"
+	elif [ "${TIME_UNIT}" = "M" ]; then
+		echo "Error: Unsupported expression - Try: eg. 60d for 2 months." 1>&2
+		exit 1
+	else
+		echo "Parse error: BACKUP_RETENTION expression is invalid" 1>&2
+		exit 1
+	fi
+
+	echo "${FIND_TIME_EXPR} +${TIME_INTERVAL:-7}"
+}
+
+add_backup_cronjob() {
+	CRONTAB_USER="${1:-git}"
+	CRONTAB_FILE="/etc/crontabs/${CRONTAB_USER}"
+	CRONJOB_EXPRESSION="${2:-}"
+	CRONJOB_EXECUTOR="${3:-}"
+	CRONJOB_EXECUTOR_ARGUMENTS="${4:-}"
+  CRONJOB_TASK="${CRONJOB_EXPRESSION} /bin/sh ${CRONJOB_EXECUTOR} ${CRONJOB_EXECUTOR_ARGUMENTS}"
+
+	if [ -f "${CRONTAB_FILE}" ]; then
+		CRONJOB_EXECUTOR_COUNT=$(grep -c "${CRONJOB_EXECUTOR}" "${CRONTAB_FILE}" || exit 0)
+		if [ "${CRONJOB_EXECUTOR_COUNT}" != "0" ]; then
+			echo "Cron job already exists for ${CRONJOB_EXECUTOR}. Updating existing." 1>&2
+			CRONJOB_TASK=$(echo "{CRONJOB_TASK}" | sed 's/\//\\\//g' )
+			CRONJOB_EXECUTOR=$(echo "{CRONJOB_EXECUTOR}" | sed 's/\//\\\//g' )
+			sed -i "/${CRONJOB_EXECUTOR}/c\\${CRONJOB_TASK}" "${CRONTAB_FILE}"
+			return 0
+		fi
+	fi
+
+	# Finally append new line with cron task expression
+	echo "${CRONJOB_TASK}" >>"${CRONTAB_FILE}"
+}
+
+CRONTAB_USER=$(awk -v val="${PUID}" -F ":" '$3==val{print $1}' /etc/passwd)
+
+# Up to this point, it was desirable that interpreter handles the command errors and halts execution upon any error.
+# From now, we handle the errors our self.
+set +e
+RETENTION_EXPRESSION="$(parse_generate_retention_expression)"
+
+if [ -z "${RETENTION_EXPRESSION}" ]; then
+	echo "Couldn't generate backup retention expression. Aborting backup setup" 1>&2
+	exit 1
+fi
+
+# Backup rotator cron will run every 5 minutes
+add_backup_cronjob "${CRONTAB_USER}" "*/5 * * * *" "/app/gogs/docker/runtime/backup-rotator.sh" "'${BACKUP_PATH}' '${RETENTION_EXPRESSION}'"
+add_backup_cronjob "${CRONTAB_USER}" "$(parse_generate_cron_expression)" "/app/gogs/docker/runtime/backup-job.sh" "'${BACKUP_PATH}'"

+ 33 - 0
docker/runtime/backup-job.sh

@@ -0,0 +1,33 @@
+#!/usr/bin/env sh
+
+execute_backup_job() {
+	BACKUP_ARG_PATH="${1:-}"
+	BACKUP_ARG_CONFIG="${BACKUP_ARG_CONFIG:-}"
+	BACKUP_ARG_EXCLUDE_REPOS="${BACKUP_ARG_EXCLUDE_REPOS:-}"
+	cd "/app/gogs" || exit 1
+
+	BACKUP_ARGS="--target=${BACKUP_ARG_PATH}"
+
+	if [ -n "${BACKUP_ARG_CONFIG}" ]; then
+		BACKUP_ARGS="${BACKUP_ARGS} --config=${BACKUP_ARG_CONFIG}"
+	fi
+
+	if [ -n "${BACKUP_ARG_EXCLUDE_REPOS}" ]; then
+		BACKUP_ARGS="${BACKUP_ARGS} --exclude-repos=${BACKUP_ARG_EXCLUDE_REPOS}"
+	fi
+
+	./gogs backup "${BACKUP_ARGS}" || echo "Error: Backup job returned non-successful code." && exit 1
+}
+
+main() {
+	BACKUP_PATH="${1:-}"
+
+	if [ -z "${BACKUP_PATH}" ]; then
+		echo "Required argument missing BACKUP_PATH" 1>&2
+		exit 1
+	fi
+
+	execute_backup_job "${BACKUP_PATH}"
+}
+
+main "$@"

+ 27 - 0
docker/runtime/backup-rotator.sh

@@ -0,0 +1,27 @@
+#!/usr/bin/env sh
+
+# This is very simple, yet effective backup rotation script.
+# Using find command, all files that are older than BACKUP_RETENTION_DAYS are accumulated and deleted using rm.
+main() {
+	BACKUP_PATH="${1:-}"
+	FIND_EXPRESSION="${2:-mtime +7}"
+
+	if [ -z "${BACKUP_PATH}" ]; then
+		echo "Error: Required argument missing BACKUP_PATH" 1>&2
+		exit 1
+	fi
+
+	if [ "$(realpath "${BACKUP_PATH}")" = "/" ]; then
+		echo "Error: Dangerous BACKUP_PATH: /" 1>&2
+		exit 1
+	fi
+
+	if [ ! -d "${BACKUP_PATH}" ]; then
+	  echo "Error: BACKUP_PATH does't exist or is not a directory" 1>&2
+		exit 1
+	fi
+
+	find "${BACKUP_PATH}/" -type f -name "gogs-backup-*.zip" -${FIND_EXPRESSION} -print -exec rm "{}" +
+}
+
+main "$@"

+ 0 - 1
docker/s6/gogs/run

@@ -4,5 +4,4 @@ if test -f ./setup; then
     source ./setup
 fi
 
-export USER=git
 exec gosu $USER /app/gogs/gogs web

+ 2 - 13
docker/s6/gogs/setup

@@ -1,12 +1,12 @@
 #!/bin/sh
 
 if ! test -d ~git/.ssh; then
-    mkdir -p ~git/.ssh
+    gosu $USER mkdir -p ~git/.ssh
     chmod 700 ~git/.ssh
 fi
 
 if ! test -f ~git/.ssh/environment; then
-    echo "GOGS_CUSTOM=${GOGS_CUSTOM}" > ~git/.ssh/environment
+    gosu $USER echo "GOGS_CUSTOM=${GOGS_CUSTOM}" > ~git/.ssh/environment
     chmod 600 ~git/.ssh/environment
 fi
 
@@ -19,15 +19,4 @@ ln -sfn /data/gogs/data ./data
 # Backward Compatibility with Gogs Container v0.6.15
 ln -sfn /data/git /home/git
 
-# Only chown for the first time, owner of '/data' is 'git' inside Docker after installation
-if [ $(stat -c '%U' /data) != 'git' ]; then
-    chown -R git:git /data ~git/
-fi
-
-# Check ownership of '/app/gogs' in case the image changed and '/data' is persistent
-if [ $(stat -c '%U' /app/gogs) != 'git' ]; then
-    chown -R git:git /app/gogs
-fi
-
-
 chmod 0755 /data /data/gogs ~git/

+ 8 - 3
docker/start.sh

@@ -30,19 +30,23 @@ cleanup() {
 }
 
 create_volume_subfolder() {
+    # Modify the owner of /data dir, make $USER(git) user have permission to create sub-dir in /data.
+    chown -R $USER:$USER /data
+
     # Create VOLUME subfolder
     for f in /data/gogs/data /data/gogs/conf /data/gogs/log /data/git /data/ssh; do
         if ! test -d $f; then
-            mkdir -p $f
+            gosu $USER mkdir -p $f
         fi
     done
 }
 
 setids() {
+    export USER=git
     PUID=${PUID:-1000}
     PGID=${PGID:-1000}
-    groupmod -o -g "$PGID" git
-    usermod -o -u "$PUID" git
+    groupmod -o -g "$PGID" $USER
+    usermod -o -u "$PUID" $USER
 }
 
 setids
@@ -60,6 +64,7 @@ CROND=$(echo "$RUN_CROND" | tr '[:upper:]' '[:lower:]')
 if [ "$CROND" = "true" -o "$CROND" = "1" ]; then
     echo "init:crond  | Cron Daemon (crond) will be run as requested by s6" 1>&2
     rm -f /app/gogs/docker/s6/crond/down
+    /bin/sh /app/gogs/docker/runtime/backup-init.sh "${PUID}"
 else
     # Tell s6 not to run the crond service
     touch /app/gogs/docker/s6/crond/down

+ 21 - 0
docs/admin/lfs.md

@@ -0,0 +1,21 @@
+# Configuring Git Large File Storage (LFS)
+
+> NOTE: Git LFS is supported in Gogs starting with version 0.12.
+
+Git LFS works out of box with default configuration for any supported versions.
+
+## Known limitations
+
+- Only local storage is supported (i.e. all LFS objects are stored on the same server where Gogs runs), support of Object Storage Service like Amazon S3 is being tracked in [#6065](https://github.com/gogs/gogs/issues/6065).
+
+## Configuration
+
+All configuration options for Git LFS are located in [`[lfs]` section](https://github.com/gogs/gogs/blob/44ea9604ed7440c2cf1105d965c2429ee225e8f6/conf/app.ini#L266-L270):
+
+```ini
+[lfs]
+; The storage backend for uploading new objects.
+STORAGE = local
+; The root path to store LFS objects on local file system.
+OBJECTS_PATH = data/lfs-objects
+```

+ 2 - 2
docs/local_development.md → docs/dev/local_development.md

@@ -23,14 +23,13 @@ Gogs is built and runs as a single binary and meant to be cross platform. Theref
 Gogs has the following dependencies:
 
 - [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) (v1.8.3 or higher)
-- [Go](https://golang.org/doc/install) (v1.13 or higher)
+- [Go](https://golang.org/doc/install) (v1.14 or higher)
 - [Less.js](http://lesscss.org/usage/#command-line-usage-installing)
 - [GNU Make](https://www.gnu.org/software/make/)
 - Database upon your choice (pick one, we choose PostgreSQL in this document):
     - [PostgreSQL](https://wiki.postgresql.org/wiki/Detailed_installation_guides) (v9.6 or higher)
     - [MySQL](https://dev.mysql.com/downloads/mysql/) with `ENGINE=InnoDB` (v5.7 or higher)
     - [SQLite3](https://www.sqlite.org/index.html)
-    - [MSSQL](https://en.wikipedia.org/wiki/Microsoft_SQL_Server) (SQL Server 2005 or newer)
     - [TiDB](https://github.com/pingcap/tidb)
 
 ### macOS
@@ -41,6 +40,7 @@ Gogs has the following dependencies:
     ```bash
     brew install go postgresql git go-bindata npm
     npm install -g less
+    npm install -g less-plugin-clean-css
     ```
 
 1. Configure PostgreSQL to start automatically:

+ 28 - 0
docs/user/lfs.md

@@ -0,0 +1,28 @@
+# Git Large File Storage (LFS)
+
+> This document is driven from https://docs.gitlab.com/ee/topics/git/lfs/.
+
+Managing large binaries in Git repositories is challenging, that is why Git LFS was developed for, to manage large files.
+
+## How it works
+
+Git LFS client talks with the Gogs server over HTTP/HTTPS. It uses HTTP Basic Authentication to authorize client requests. Once the request is authorized, Git LFS client receives instructions from where to fetch or where to push the large file.
+
+## Server configuration
+
+Please refer to [Configuring Git Large File Storage (LFS)](../admin/lfs.md).
+
+## Requirements
+
+- Git LFS is supported in Gogs starting with version 0.12.
+- [Git LFS client](https://git-lfs.github.com/) version 1.0.1 and up.
+
+## Known limitations
+
+- When SSH is set as a remote, Git LFS objects still go through HTTP/HTTPS.
+- Any Git LFS request will ask for HTTP/HTTPS credentials to be provided so a good Git credentials store is recommended.
+- File locking is not supported, and is being tracked in [#6064](https://github.com/gogs/gogs/issues/6064).
+
+## Using Git LFS
+
+Git LFS endpoints in a Gogs server can be automatically discovered by the Git LFS client, therefore you do not need to configure anything upfront for using it. Please walk through official [Git LFS Tutorial](https://github.com/git-lfs/git-lfs/wiki/Tutorial) to get started.

+ 10 - 12
go.mod

@@ -1,13 +1,13 @@
 module github.com/G-Node/gogs
 
-go 1.12
+go 1.14
 
 require (
 	github.com/G-Node/git-module v0.8.4-gnode
 	github.com/G-Node/libgin v0.3.2
+	github.com/Masterminds/semver/v3 v3.1.0
 	github.com/bgentry/speakeasy v0.1.0 // indirect
-	github.com/blang/semver v3.5.1+incompatible // indirect
-	github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e
+	github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e // indirect
 	github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0
 	github.com/editorconfig/editorconfig-core-go/v2 v2.3.2
 	github.com/fatih/color v1.9.0 // indirect
@@ -19,26 +19,25 @@ require (
 	github.com/go-macaron/i18n v0.5.0
 	github.com/go-macaron/session v0.0.0-20190805070824-1a3cdc6f5659
 	github.com/go-macaron/toolbox v0.0.0-20190813233741-94defb8383c6
-	github.com/go-sql-driver/mysql v1.5.0
+	github.com/go-sql-driver/mysql v1.5.0 // indirect
 	github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561
 	github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
 	github.com/gogs/git-module v1.1.2
 	github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4
 	github.com/gogs/go-libravatar v0.0.0-20191106065024-33a75213d0a0
 	github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a
-	github.com/google/go-cmp v0.4.0
 	github.com/google/go-github v17.0.0+incompatible
 	github.com/google/go-querystring v1.0.0 // indirect
 	github.com/issue9/identicon v1.0.1
 	github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43
+	github.com/jinzhu/gorm v1.9.12
 	github.com/json-iterator/go v1.1.10
 	github.com/klauspost/compress v1.8.6 // indirect
 	github.com/klauspost/cpuid v1.2.1 // indirect
-	github.com/lib/pq v1.3.0
+	github.com/lib/pq v1.3.0 // indirect
 	github.com/mattn/go-isatty v0.0.12 // indirect
 	github.com/mattn/go-runewidth v0.0.4 // indirect
-	github.com/mattn/go-sqlite3 v2.0.3+incompatible
-	github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2
+	github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
 	github.com/microcosm-cc/bluemonday v1.0.4
 	github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9
 	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
@@ -51,15 +50,14 @@ require (
 	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
 	github.com/satori/go.uuid v1.2.0
 	github.com/sergi/go-diff v1.1.0
-	github.com/smartystreets/goconvey v1.6.4
 	github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
 	github.com/stretchr/testify v1.6.1
-	github.com/unknwon/cae v1.0.0
+	github.com/t-tiger/gorm-bulk-insert v1.3.0
+	github.com/unknwon/cae v1.0.2
 	github.com/unknwon/com v1.0.1
 	github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6
 	github.com/unknwon/paginater v0.0.0-20170405233947-45e5d631308e
 	github.com/urfave/cli v1.22.4
-	gogs.io/gogs v0.12.1
 	golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975
 	golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582
 	golang.org/x/text v0.3.3
@@ -77,5 +75,5 @@ require (
 	xorm.io/xorm v0.8.0
 )
 
-// +heroku goVersion go1.13
+// +heroku goVersion go1.14
 // +heroku install ./

+ 14 - 67
go.sum

@@ -27,14 +27,10 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
 github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
 github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
-github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
-github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
 github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668 h1:U/lr3Dgy4WK+hNk4tyD+nuGjpVLPEHuJSFXMw11/HPA=
 github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
-github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
-github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
 github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/chris-ramon/douceur v0.2.0 h1:IDMEdxlEUUBYBKE4z/mJnFyVXox+MjuEVDJNN27glkU=
@@ -51,8 +47,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
 github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
-github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0 h1:epsH3lb7KVbXHYk7LYGN5EiE0MxcevHU85CKITJ0wUY=
-github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE=
 github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
@@ -62,15 +56,11 @@ github.com/dustinkirkland/golang-petname v0.0.0-20191129215211-8e5a1ed0cff0/go.m
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/editorconfig/editorconfig-core-go/v2 v2.2.1 h1:jY5PCRQf4V0oqpim/Ympl6MwHcb9+nBHEnHOPXqNZ/A=
-github.com/editorconfig/editorconfig-core-go/v2 v2.2.1/go.mod h1:6XDmqAZsQu8ikS+onLRJfLZvTP3RWTVT8ROX6qcdkio=
-github.com/editorconfig/editorconfig-core-go/v2 v2.3.0 h1:QD1YB/rbntMEQIKM42kQOaqGdS13UvGsl9c8m/nFNWY=
-github.com/editorconfig/editorconfig-core-go/v2 v2.3.0/go.mod h1:RNdPfKd9PliYEUZ3r+GxbDsSHNnEluC1wdkQJc3jD4k=
 github.com/editorconfig/editorconfig-core-go/v2 v2.3.2 h1:j9GLz0kWF9+1T3IX0MOhhvzLtqhFOvIKLhZFxtY95Qc=
 github.com/editorconfig/editorconfig-core-go/v2 v2.3.2/go.mod h1:+u4rFiKVvlbukHyJM76GYXqQcnHScxvQCuKpMLRtJVw=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
 github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
-github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
 github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
@@ -79,14 +69,10 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-macaron/binding v1.0.1 h1:4LASxd4EKsESZ6ZMyzNVX+TM4Yuex4bTHYyz/PQjsRA=
-github.com/go-macaron/binding v1.0.1/go.mod h1:AG8Z6qkQM8s47aUDJOco/SNwJ8Czif2hMm7rc0abDog=
 github.com/go-macaron/binding v1.1.0 h1:A5jpr5UdHr81Hfmb6QUAMTHyvniudOMcgtEg13TJ1ig=
 github.com/go-macaron/binding v1.1.0/go.mod h1:dJU/AtPKG0gUiFra1K5TTGduFGMNxMvfJzV/zmXwyGM=
 github.com/go-macaron/cache v0.0.0-20190810181446-10f7c57e2196 h1:fqWZxyMLF6RVGmjvsZ9FijiU9UlAjuE6nu9RfNBZ+iE=
 github.com/go-macaron/cache v0.0.0-20190810181446-10f7c57e2196/go.mod h1:O6fSdaYZbGh4clVMGMGO5k2KbMO0Cz8YdBnPrD0I8dM=
-github.com/go-macaron/captcha v0.0.0-20190813234938-24f40749f36d h1:aSJXLVjEjbLeHo8aCTDcD3/gMWizaRjMBb3VCsEWEHs=
-github.com/go-macaron/captcha v0.0.0-20190813234938-24f40749f36d/go.mod h1:lmhlZnu9cTRGNQEkSh1qZi2IK3HJH4Z1MXkg6ARQKZA=
 github.com/go-macaron/captcha v0.2.0 h1:d38eYDDF8tdqoM0hJbk+Jb7WQGWlwYNnQwRqLRmSk1Y=
 github.com/go-macaron/captcha v0.2.0/go.mod h1:lmhlZnu9cTRGNQEkSh1qZi2IK3HJH4Z1MXkg6ARQKZA=
 github.com/go-macaron/csrf v0.0.0-20190812063352-946f6d303a4c h1:kFFz1OpaH3+efG7RA33z+D0piwpA/a3x/Zn2d8z9rfw=
@@ -101,7 +87,6 @@ github.com/go-macaron/session v0.0.0-20190805070824-1a3cdc6f5659 h1:YXDFNK98PgKe
 github.com/go-macaron/session v0.0.0-20190805070824-1a3cdc6f5659/go.mod h1:tLd0QEudXocQckwcpCq5pCuTCuYc24I0bRJDuRe9OuQ=
 github.com/go-macaron/toolbox v0.0.0-20190813233741-94defb8383c6 h1:x/v1iUWlqXTKVg17ulB0qCgcM2s+eysAbr/dseKLLss=
 github.com/go-macaron/toolbox v0.0.0-20190813233741-94defb8383c6/go.mod h1:YFNJ/JT4yLnpuIXTFef30SZkxGHUczjGZGFaZpPcdn0=
-github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -114,12 +99,6 @@ github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561 h1:aBzukfDxQlCTVS0NBU
 github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561/go.mod h1:Pcatq5tYkCW2Q6yrR2VRHlbHpZ/R4/7qyL1TCF7vl14=
 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 h1:yXtpJr/LV6PFu4nTLgfjQdcMdzjbqqXMEnHfq0Or6p8=
 github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14/go.mod h1:jPoNZLWDAqA5N3G5amEoiNbhVrmM+ZQEcnQvNQ2KaZk=
-github.com/gogs/git-module v0.8.3 h1:9f8oxSs9OACWrGBYMVnnQNzyTcVN+zzcBM7CXnbmezw=
-github.com/gogs/git-module v0.8.3/go.mod h1:aj4tcm7DxaszJWpZLZIRL6gfPXyguAHiE1PDfAAPrCw=
-github.com/gogs/git-module v1.0.0-beta.4 h1:5CyCvTfrb2n5LRpHcNIaFnywHDkM/NxSZVP6t4tpTXI=
-github.com/gogs/git-module v1.0.0-beta.4/go.mod h1:oN37FFStFjdnTJXsSbhIHKJXh2YeDsEcXPATVz/oeuQ=
-github.com/gogs/git-module v1.0.0 h1:iOlCZ5kPc3RjnWRxdziL5hjCaosYyZw/Lf2odzR/kjw=
-github.com/gogs/git-module v1.0.0/go.mod h1:oN37FFStFjdnTJXsSbhIHKJXh2YeDsEcXPATVz/oeuQ=
 github.com/gogs/git-module v1.1.2 h1:30jO+rKEmCDk/O6Mnl7MVrw6rI1qLDByXpkRB+bpYwM=
 github.com/gogs/git-module v1.1.2/go.mod h1:oN37FFStFjdnTJXsSbhIHKJXh2YeDsEcXPATVz/oeuQ=
 github.com/gogs/go-gogs-client v0.0.0-20200128182646-c69cb7680fd4 h1:C7NryI/RQhsIWwC2bHN601P1wJKeuQ6U/UCOYTn3Cic=
@@ -135,7 +114,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
 github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
 github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -147,9 +125,9 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
 github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
@@ -176,12 +154,13 @@ github.com/issue9/identicon v1.0.1/go.mod h1:UKNVkUFI68RPz/RlLhsAr1aX6bBSaYEWRHV
 github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43 h1:jTkyeF7NZ5oIr0ESmcrpiDgAfoidCBF4F5kJhjtaRwE=
 github.com/jaytaylor/html2text v0.0.0-20190408195923-01ec452cbe43/go.mod h1:CVKlgaMiht+LXvHG173ujK6JUhZXKb2u/BQtjPDIvyk=
 github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw=
+github.com/jinzhu/gorm v1.9.12 h1:Drgk1clyWT9t9ERbzHza6Mj/8FY/CqMyVzOiHviMo6Q=
 github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
 github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
-github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
 github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -204,7 +183,6 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
 github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
 github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -213,7 +191,6 @@ github.com/lunny/nodb v0.0.0-20160621015157-fc1ef06ad4af/go.mod h1:Cqz6pqow14VOb
 github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
-github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
 github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
 github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -221,17 +198,15 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
 github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y=
 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
 github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
 github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 h1:YocNLcTBdEdvY3iDK6jfWXvEaM5OCKkjxPKoJRdB3Gg=
 github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo=
-github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
 github.com/microcosm-cc/bluemonday v1.0.4 h1:p0L+CTpo/PLFdkoPcJemLXG+fpMD7pYOoDEq1axMbGg=
 github.com/microcosm-cc/bluemonday v1.0.4/go.mod h1:8iwZnFn2CDDNZ0r6UXhF4xawGvzaqzCRa1n3/lO3W2w=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -245,8 +220,6 @@ github.com/msteinert/pam v0.0.0-20190215180659-f29b9f28d6f9/go.mod h1:np1wUFZ6ty
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
-github.com/niklasfasching/go-org v0.1.6 h1:F521WcqRNl8OJumlgAnekZgERaTA2HpfOYYfVEKOeI8=
-github.com/niklasfasching/go-org v0.1.6/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
 github.com/niklasfasching/go-org v0.1.9 h1:Toz8WMIt+qJb52uYEk1YD/muLuOOmRt1CfkV+bKVMkI=
 github.com/niklasfasching/go-org v0.1.9/go.mod h1:AsLD6X7djzRIz4/RFZu8vwRL0VGjUvGZCCH1Nz0VdrU=
 github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
@@ -260,7 +233,6 @@ github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJ
 github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
 github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -271,28 +243,20 @@ github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
-github.com/prometheus/client_golang v1.2.1 h1:JnMpQc6ppsNgw9QPAGF6Dod479itz7lvlsMzzNayLOI=
-github.com/prometheus/client_golang v1.2.1/go.mod h1:XMU6Z2MjaRKVu/dC1qupJI9SiNkDYzz3xecMgSW/F+U=
 github.com/prometheus/client_golang v1.6.0 h1:YVPodQOcK15POxhgARIvnDRVpLcuK8mglnMrWfyrw6A=
 github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83AXG6ro35rLTxvnIl4=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY=
-github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
 github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
 github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
 github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8=
-github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ=
 github.com/prometheus/procfs v0.0.11 h1:DhHlBtkHWPYi8O2y31JkK0TF+DGM+51OopZjH/Ia5qI=
 github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@@ -304,8 +268,6 @@ github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca h1:NugYot0LIVPxT
 github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
 github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
 github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
 github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
@@ -322,7 +284,6 @@ github.com/smartystreets/assertions v1.0.1 h1:voD4ITNjPL5jjBfgR/r8fPIIBrliWrWHei
 github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
 github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
 github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
-github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 h1:WN9BUFbdyOsSH/XohnWpXOlq9NBD5sGAB2FciQMUEe8=
 github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
 github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@@ -332,13 +293,14 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
+github.com/t-tiger/gorm-bulk-insert v1.3.0 h1:9k7BaVEhw/3fsvh6GTOBwJ2RXk3asc5xs5m6hwozq20=
 github.com/t-tiger/gorm-bulk-insert v1.3.0/go.mod h1:ruDlk8xDl+8sX4bA7PQuYly9YEb3pbp1eP2LCyeRrFY=
-github.com/unknwon/cae v1.0.0 h1:i39lOFaBXZxhGjQOy/RNbi8uzettCs6OQxpR0xXohGU=
-github.com/unknwon/cae v1.0.0/go.mod h1:QaSeRctcea9fK6piJpAMCCPKxzJ01+xFcr2k1m3WRPU=
+github.com/unknwon/cae v1.0.2 h1:3L8/RCN1ARvD5quyNjU30EdvYkFbxBfnRcIBXugpHlg=
+github.com/unknwon/cae v1.0.2/go.mod h1:HqpmD2fVq9G1oGEXrXzbgIp51uJ29Hshv41n9ljm+AA=
 github.com/unknwon/com v0.0.0-20190804042917-757f69c95f3e/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
 github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs=
 github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM=
@@ -346,15 +308,11 @@ github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6 h1:sRrkJEHtNoaSvyXMbR
 github.com/unknwon/i18n v0.0.0-20190805065654-5c6446a380b6/go.mod h1:+5rDk6sDGpl3azws3O+f+GpFSyN9GVr0K8cvQLQM2ZQ=
 github.com/unknwon/paginater v0.0.0-20170405233947-45e5d631308e h1:Qf3QQl/zmEbWDajFEiisbKN83hLY+eq2MhbA0I1/two=
 github.com/unknwon/paginater v0.0.0-20170405233947-45e5d631308e/go.mod h1:TBwoao3Q4Eb/cp+dHbXDfRTrZSsj/k7kLr2j1oWRWC0=
-github.com/urfave/cli v1.22.1 h1:+mkCCcOFKPnCmVYVcURKps1Xe+3zP90gSYGNfRkjoIY=
-github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
 github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
 github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
 go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-gogs.io/gogs v0.12.1 h1:TmCr+FgRjzOvr8s/tX8X9uOTAZ3eNEvfon8F9oN3R/4=
-gogs.io/gogs v0.12.1/go.mod h1:FwcFYxh13Lw+BdOuVs+caeNNnfNFc1amnyLkwIV4kjk=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -393,6 +351,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -406,18 +365,13 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
-golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c h1:jceGD5YNJGgGMkJz79agzOln1K9TaZUjv5ird16qniQ=
-golang.org/x/sys v0.0.0-20200219091948-cb0a6d8edb6c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f h1:gWF768j/LaZugp8dyS4UwsslYCYz9XgFxvlgsn0n9H8=
 golang.org/x/sys v0.0.0-20200420163511-1957bb5e6d1f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -434,12 +388,12 @@ golang.org/x/tools v0.0.0-20190805222050-c5a2fd39b72a/go.mod h1:jcCCGcm9btYwXyDq
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.6.1 h1:QzqyMA1tlu6CgqCDUtU9V+ZKhLFT2dkJuANu5QaxI3I=
 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
 google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
 google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -460,27 +414,20 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy
 gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e h1:wGA78yza6bu/mWcc4QfBuIEHEtc06xdiU0X8sY36yUU=
 gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e/go.mod h1:xsQCaysVCudhrYTfzYWe577fCe7Ceci+6qjO2Rdc0Z4=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/clog.v1 v1.2.0 h1:BHfwHRNQy497iBNsRBassPixSAxRbn2z5KVkdBFbwxc=
 gopkg.in/clog.v1 v1.2.0/go.mod h1:L6fgdpdhFgKX4eGuDvt+N6X2GwZE160NRrIHzvaF8ZM=
 gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
-gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4=
-gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.53.0 h1:c7ruDvTQi0MUTFuNpDRXLSjs7xT4TerM1icIg4uKWRg=
-gopkg.in/ini.v1 v1.53.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.56.0 h1:DPMeDvGTM54DXbPkVIZsp19fp/I2K7zwA/itHYHKo8Y=
 gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
 gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
-gopkg.in/macaron.v1 v1.3.4 h1:HvIscOwxhFhx3swWM/979wh2QMYyuXrNmrF9l+j3HZs=
 gopkg.in/macaron.v1 v1.3.4/go.mod h1:/RoHTdC8ALpyJ3+QR36mKjwnT1F1dyYtsGM9Ate6ZFI=
 gopkg.in/macaron.v1 v1.3.5/go.mod h1:uMZCFccv9yr5TipIalVOyAyZQuOH3OkmXvgcWwhJuP4=
 gopkg.in/macaron.v1 v1.3.9 h1:Dw+DDRYdXgQyEsPlfAfKz+UA5qVUrH3KPD7JhmZ9MFc=
@@ -489,12 +436,12 @@ gopkg.in/redis.v2 v2.3.2 h1:GPVIIB/JnL1wvfULefy3qXmPu1nfNu2d0yA09FHgwfs=
 gopkg.in/redis.v2 v2.3.2/go.mod h1:4wl9PJ/CqzeHk3LVq1hNLHH8krm3+AXEgut4jVc++LU=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
 gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 2 - 2
gogs.go

@@ -1,4 +1,4 @@
-// +build go1.13
+// +build go1.14
 
 // Copyright 2014 The Gogs Authors. All rights reserved.
 // Use of this source code is governed by a MIT-style
@@ -18,7 +18,7 @@ import (
 )
 
 func init() {
-	conf.App.Version = "0.12.0+dev"
+	conf.App.Version = "0.12.3"
 }
 
 func main() {

+ 34 - 0
internal/app/api.go

@@ -0,0 +1,34 @@
+// Copyright 2020 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 app
+
+import (
+	"net/http"
+
+	"github.com/microcosm-cc/bluemonday"
+	"gopkg.in/macaron.v1"
+)
+
+func ipynbSanitizer() *bluemonday.Policy {
+	p := bluemonday.UGCPolicy()
+	p.AllowAttrs("class", "data-prompt-number").OnElements("div")
+	p.AllowAttrs("class").OnElements("img")
+	p.AllowURLSchemes("data")
+	return p
+}
+
+func SanitizeIpynb() macaron.Handler {
+	p := ipynbSanitizer()
+
+	return func(c *macaron.Context) {
+		html, err := c.Req.Body().String()
+		if err != nil {
+			c.Error(http.StatusInternalServerError, "read body")
+			return
+		}
+
+		c.PlainText(http.StatusOK, []byte(p.Sanitize(html)))
+	}
+}

+ 95 - 0
internal/app/api_test.go

@@ -0,0 +1,95 @@
+// Copyright 2020 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 app
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func Test_ipynbSanitizer(t *testing.T) {
+	p := ipynbSanitizer()
+
+	tests := []struct {
+		name  string
+		input string
+		want  string
+	}{
+		{
+			name: "allow 'class' and 'data-prompt-number' attributes",
+			input: `
+<div class="nb-notebook">
+    <div class="nb-worksheet">
+        <div class="nb-cell nb-markdown-cell">Hello world</div>
+        <div class="nb-cell nb-code-cell">
+            <div class="nb-input" data-prompt-number="4">
+            </div>
+        </div>
+    </div>
+</div>
+`,
+			want: `
+<div class="nb-notebook">
+    <div class="nb-worksheet">
+        <div class="nb-cell nb-markdown-cell">Hello world</div>
+        <div class="nb-cell nb-code-cell">
+            <div class="nb-input" data-prompt-number="4">
+            </div>
+        </div>
+    </div>
+</div>
+`,
+		},
+		{
+			name: "allow base64 encoded images",
+			input: `
+<div class="nb-output" data-prompt-number="4">
+    <img class="nb-image-output" src="data:image/png;base64,iVBORw0KGgoA"/>
+</div>
+`,
+			want: `
+<div class="nb-output" data-prompt-number="4">
+    <img class="nb-image-output" src="data:image/png;base64,iVBORw0KGgoA"/>
+</div>
+`,
+		},
+		{
+			name: "prevent XSS",
+			input: `
+<div class="nb-output" data-prompt-number="10">
+<div class="nb-html-output">
+<style>
+.output {
+align-items: center;
+background: #00ff00;
+}
+</style>
+<script>
+function test() {
+alert("test");
+}
+
+$(document).ready(test);
+</script>
+</div>
+</div>
+`,
+			want: `
+<div class="nb-output" data-prompt-number="10">
+<div class="nb-html-output">
+
+
+</div>
+</div>
+`,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			assert.Equal(t, test.want, p.Sanitize(test.input))
+		})
+	}
+}

+ 33 - 0
internal/app/metrics.go

@@ -0,0 +1,33 @@
+// Copyright 2020 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 app
+
+import (
+	"net/http"
+
+	"gopkg.in/macaron.v1"
+
+	"github.com/G-Node/gogs/internal/authutil"
+	"github.com/G-Node/gogs/internal/conf"
+)
+
+func MetricsFilter() macaron.Handler {
+	return func(w http.ResponseWriter, r *http.Request) {
+		if !conf.Prometheus.Enabled {
+			w.WriteHeader(http.StatusNotFound)
+			return
+		}
+
+		if !conf.Prometheus.EnableBasicAuth {
+			return
+		}
+
+		username, password := authutil.DecodeBasic(r.Header)
+		if username != conf.Prometheus.BasicAuthUsername || password != conf.Prometheus.BasicAuthPassword {
+			w.WriteHeader(http.StatusForbidden)
+			return
+		}
+	}
+}

文件差异内容过多而无法显示
+ 31 - 31
internal/assets/conf/conf_gen.go


文件差异内容过多而无法显示
+ 24 - 25
internal/assets/public/public_gen.go


文件差异内容过多而无法显示
+ 17 - 17
internal/assets/templates/templates_gen.go


+ 13 - 16
internal/auth/auth.go

@@ -6,7 +6,6 @@ package auth
 
 import (
 	"strings"
-	"time"
 
 	"github.com/go-macaron/session"
 	gouuid "github.com/satori/go.uuid"
@@ -15,7 +14,6 @@ import (
 
 	"github.com/G-Node/gogs/internal/conf"
 	"github.com/G-Node/gogs/internal/db"
-	"github.com/G-Node/gogs/internal/db/errors"
 	"github.com/G-Node/gogs/internal/tool"
 )
 
@@ -49,18 +47,17 @@ func SignedInID(c *macaron.Context, sess session.Store) (_ int64, isTokenAuth bo
 
 		// Let's see if token is valid.
 		if len(tokenSHA) > 0 {
-			t, err := db.GetAccessTokenBySHA(tokenSHA)
+			t, err := db.AccessTokens.GetBySHA(tokenSHA)
 			if err != nil {
-				if !db.IsErrAccessTokenNotExist(err) && !db.IsErrAccessTokenEmpty(err) {
+				if !db.IsErrAccessTokenNotExist(err) {
 					log.Error("GetAccessTokenBySHA: %v", err)
 				}
 				return 0, false
 			}
-			t.Updated = time.Now()
-			if err = db.UpdateAccessToken(t); err != nil {
+			if err = db.AccessTokens.Save(t); err != nil {
 				log.Error("UpdateAccessToken: %v", err)
 			}
-			return t.UID, true
+			return t.UserID, true
 		}
 	}
 
@@ -70,8 +67,8 @@ func SignedInID(c *macaron.Context, sess session.Store) (_ int64, isTokenAuth bo
 	}
 	if id, ok := uid.(int64); ok {
 		if _, err := db.GetUserByID(id); err != nil {
-			if !errors.IsUserNotExist(err) {
-				log.Error("GetUserByID: %v", err)
+			if !db.IsErrUserNotExist(err) {
+				log.Error("Failed to get user by ID: %v", err)
 			}
 			return 0, false
 		}
@@ -91,12 +88,12 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (_ *db.User, isBasic
 
 	if uid <= 0 {
 		if conf.Auth.EnableReverseProxyAuthentication {
-			webAuthUser := ctx.Req.Header.Get(conf.Security.ReverseProxyAuthenticationUser)
+			webAuthUser := ctx.Req.Header.Get(conf.Auth.ReverseProxyAuthenticationHeader)
 			if len(webAuthUser) > 0 {
 				u, err := db.GetUserByName(webAuthUser)
 				if err != nil {
-					if !errors.IsUserNotExist(err) {
-						log.Error("GetUserByName: %v", err)
+					if !db.IsErrUserNotExist(err) {
+						log.Error("Failed to get user by name: %v", err)
 						return nil, false, false
 					}
 
@@ -110,7 +107,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (_ *db.User, isBasic
 						}
 						if err = db.CreateUser(u); err != nil {
 							// FIXME: should I create a system notice?
-							log.Error("CreateUser: %v", err)
+							log.Error("Failed to create user: %v", err)
 							return nil, false, false
 						} else {
 							return u, false, false
@@ -128,10 +125,10 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (_ *db.User, isBasic
 			if len(auths) == 2 && auths[0] == "Basic" {
 				uname, passwd, _ := tool.BasicAuthDecode(auths[1])
 
-				u, err := db.UserLogin(uname, passwd, -1)
+				u, err := db.Users.Authenticate(uname, passwd, -1)
 				if err != nil {
-					if !errors.IsUserNotExist(err) {
-						log.Error("UserLogin: %v", err)
+					if !db.IsErrUserNotExist(err) {
+						log.Error("Failed to authenticate user: %v", err)
 					}
 					return nil, false, false
 				}

+ 5 - 5
internal/auth/ldap/ldap.go

@@ -19,9 +19,9 @@ type SecurityProtocol int
 
 // Note: new type must be added at the end of list to maintain compatibility.
 const (
-	SECURITY_PROTOCOL_UNENCRYPTED SecurityProtocol = iota
-	SECURITY_PROTOCOL_LDAPS
-	SECURITY_PROTOCOL_START_TLS
+	SecurityProtocolUnencrypted SecurityProtocol = iota
+	SecurityProtocolLDAPS
+	SecurityProtocolStartTLS
 )
 
 // Basic LDAP authentication service
@@ -144,7 +144,7 @@ func dial(ls *Source) (*ldap.Conn, error) {
 		ServerName:         ls.Host,
 		InsecureSkipVerify: ls.SkipVerify,
 	}
-	if ls.SecurityProtocol == SECURITY_PROTOCOL_LDAPS {
+	if ls.SecurityProtocol == SecurityProtocolLDAPS {
 		return ldap.DialTLS("tcp", fmt.Sprintf("%s:%d", ls.Host, ls.Port), tlsCfg)
 	}
 
@@ -153,7 +153,7 @@ func dial(ls *Source) (*ldap.Conn, error) {
 		return nil, fmt.Errorf("Dial: %v", err)
 	}
 
-	if ls.SecurityProtocol == SECURITY_PROTOCOL_START_TLS {
+	if ls.SecurityProtocol == SecurityProtocolStartTLS {
 		if err = conn.StartTLS(tlsCfg); err != nil {
 			conn.Close()
 			return nil, fmt.Errorf("StartTLS: %v", err)

+ 35 - 0
internal/authutil/basic.go

@@ -0,0 +1,35 @@
+// Copyright 2020 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 authutil
+
+import (
+	"encoding/base64"
+	"net/http"
+	"strings"
+)
+
+// DecodeBasic extracts username and password from given header using HTTP Basic Auth.
+// It returns empty strings if values are not presented or not valid.
+func DecodeBasic(header http.Header) (username, password string) {
+	if len(header) == 0 {
+		return "", ""
+	}
+
+	fields := strings.Fields(header.Get("Authorization"))
+	if len(fields) != 2 || fields[0] != "Basic" {
+		return "", ""
+	}
+
+	p, err := base64.StdEncoding.DecodeString(fields[1])
+	if err != nil {
+		return "", ""
+	}
+
+	creds := strings.SplitN(string(p), ":", 2)
+	if len(creds) == 1 {
+		return creds[0], ""
+	}
+	return creds[0], creds[1]
+}

+ 72 - 0
internal/authutil/basic_test.go

@@ -0,0 +1,72 @@
+// Copyright 2020 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 authutil
+
+import (
+	"net/http"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDecodeBasic(t *testing.T) {
+	tests := []struct {
+		name        string
+		header      http.Header
+		expUsername string
+		expPassword string
+	}{
+		{
+			name: "no header",
+		},
+		{
+			name: "no authorization",
+			header: http.Header{
+				"Content-Type": []string{"text/plain"},
+			},
+		},
+		{
+			name: "malformed value",
+			header: http.Header{
+				"Authorization": []string{"Basic"},
+			},
+		},
+		{
+			name: "not basic",
+			header: http.Header{
+				"Authorization": []string{"Digest dummy"},
+			},
+		},
+		{
+			name: "bad encoding",
+			header: http.Header{
+				"Authorization": []string{"Basic not_base64"},
+			},
+		},
+
+		{
+			name: "only has username",
+			header: http.Header{
+				"Authorization": []string{"Basic dXNlcm5hbWU="},
+			},
+			expUsername: "username",
+		},
+		{
+			name: "has username and password",
+			header: http.Header{
+				"Authorization": []string{"Basic dXNlcm5hbWU6cGFzc3dvcmQ="},
+			},
+			expUsername: "username",
+			expPassword: "password",
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			username, password := DecodeBasic(test.header)
+			assert.Equal(t, test.expUsername, username)
+			assert.Equal(t, test.expPassword, password)
+		})
+	}
+}

+ 7 - 9
internal/avatar/avatar_test.go

@@ -7,17 +7,15 @@ package avatar
 import (
 	"testing"
 
-	. "github.com/smartystreets/goconvey/convey"
+	"github.com/stretchr/testify/assert"
 )
 
 func Test_RandomImage(t *testing.T) {
-	Convey("Generate a random avatar from email", t, func() {
-		_, err := RandomImage([]byte("gogs@local"))
-		So(err, ShouldBeNil)
+	_, err := RandomImage([]byte("gogs@local"))
+	if err != nil {
+		t.Fatal(err)
+	}
 
-		Convey("Try to generate an image with size zero", func() {
-			_, err := RandomImageSize(0, []byte("gogs@local"))
-			So(err, ShouldNotBeNil)
-		})
-	})
+	_, err = RandomImageSize(0, []byte("gogs@local"))
+	assert.Error(t, err)
 }

+ 8 - 2
internal/cmd/admin.go

@@ -146,8 +146,11 @@ func runCreateUser(c *cli.Context) error {
 	if err != nil {
 		return errors.Wrap(err, "init configuration")
 	}
+	conf.InitLogging(true)
 
-	db.SetEngine()
+	if _, err = db.SetEngine(); err != nil {
+		return errors.Wrap(err, "set engine")
+	}
 
 	if err := db.CreateUser(&db.User{
 		Name:     c.String("name"),
@@ -169,8 +172,11 @@ func adminDashboardOperation(operation func() error, successMessage string) func
 		if err != nil {
 			return errors.Wrap(err, "init configuration")
 		}
+		conf.InitLogging(true)
 
-		db.SetEngine()
+		if _, err = db.SetEngine(); err != nil {
+			return errors.Wrap(err, "set engine")
+		}
 
 		if err := operation(); err != nil {
 			functionName := runtime.FuncForPC(reflect.ValueOf(operation).Pointer()).Name()

+ 40 - 14
internal/cmd/backup.go

@@ -37,12 +37,13 @@ portable among all supported database engines.`,
 		stringFlag("target", "./", "Target directory path to save backup archive"),
 		stringFlag("archive-name", fmt.Sprintf("gogs-backup-%s.zip", time.Now().Format("20060102150405")), "Name of backup archive"),
 		boolFlag("database-only", "Only dump database"),
+		boolFlag("exclude-mirror-repos", "Exclude mirror repositories"),
 		boolFlag("exclude-repos", "Exclude repositories"),
 	},
 }
 
-const _CURRENT_BACKUP_FORMAT_VERSION = 1
-const _ARCHIVE_ROOT_DIR = "gogs-backup"
+const currentBackupFormatVersion = 1
+const archiveRootDir = "gogs-backup"
 
 func runBackup(c *cli.Context) error {
 	zip.Verbose = c.Bool("verbose")
@@ -51,8 +52,12 @@ func runBackup(c *cli.Context) error {
 	if err != nil {
 		return errors.Wrap(err, "init configuration")
 	}
+	conf.InitLogging(true)
 
-	db.SetEngine()
+	conn, err := db.SetEngine()
+	if err != nil {
+		return errors.Wrap(err, "set engine")
+	}
 
 	tmpDir := c.String("tempdir")
 	if !com.IsExist(tmpDir) {
@@ -67,7 +72,7 @@ func runBackup(c *cli.Context) error {
 	// Metadata
 	metaFile := path.Join(rootDir, "metadata.ini")
 	metadata := ini.Empty()
-	metadata.Section("").Key("VERSION").SetValue(com.ToStr(_CURRENT_BACKUP_FORMAT_VERSION))
+	metadata.Section("").Key("VERSION").SetValue(com.ToStr(currentBackupFormatVersion))
 	metadata.Section("").Key("DATE_TIME").SetValue(time.Now().String())
 	metadata.Section("").Key("GOGS_VERSION").SetValue(conf.App.Version)
 	if err = metadata.SaveTo(metaFile); err != nil {
@@ -81,22 +86,22 @@ func runBackup(c *cli.Context) error {
 	if err != nil {
 		log.Fatal("Failed to create backup archive '%s': %v", archiveName, err)
 	}
-	if err = z.AddFile(_ARCHIVE_ROOT_DIR+"/metadata.ini", metaFile); err != nil {
+	if err = z.AddFile(archiveRootDir+"/metadata.ini", metaFile); err != nil {
 		log.Fatal("Failed to include 'metadata.ini': %v", err)
 	}
 
 	// Database
 	dbDir := filepath.Join(rootDir, "db")
-	if err = db.DumpDatabase(dbDir); err != nil {
+	if err = db.DumpDatabase(conn, dbDir, c.Bool("verbose")); err != nil {
 		log.Fatal("Failed to dump database: %v", err)
 	}
-	if err = z.AddDir(_ARCHIVE_ROOT_DIR+"/db", dbDir); err != nil {
+	if err = z.AddDir(archiveRootDir+"/db", dbDir); err != nil {
 		log.Fatal("Failed to include 'db': %v", err)
 	}
 
 	// Custom files
 	if !c.Bool("database-only") {
-		if err = z.AddDir(_ARCHIVE_ROOT_DIR+"/custom", conf.CustomDir()); err != nil {
+		if err = z.AddDir(archiveRootDir+"/custom", conf.CustomDir()); err != nil {
 			log.Fatal("Failed to include 'custom': %v", err)
 		}
 	}
@@ -109,7 +114,7 @@ func runBackup(c *cli.Context) error {
 				continue
 			}
 
-			if err = z.AddDir(path.Join(_ARCHIVE_ROOT_DIR+"/data", dir), dirPath); err != nil {
+			if err = z.AddDir(path.Join(archiveRootDir+"/data", dir), dirPath); err != nil {
 				log.Fatal("Failed to include 'data': %v", err)
 			}
 		}
@@ -119,13 +124,34 @@ func runBackup(c *cli.Context) error {
 	if !c.Bool("exclude-repos") && !c.Bool("database-only") {
 		reposDump := filepath.Join(rootDir, "repositories.zip")
 		log.Info("Dumping repositories in %q", conf.Repository.Root)
-		if err = zip.PackTo(conf.Repository.Root, reposDump, true); err != nil {
-			log.Fatal("Failed to dump repositories: %v", err)
+		if c.Bool("exclude-mirror-repos") {
+			repos, err := db.GetNonMirrorRepositories()
+			if err != nil {
+				log.Fatal("Failed to get non-mirror repositories: %v", err)
+			}
+			reposZip, err := zip.Create(reposDump)
+			if err != nil {
+				log.Fatal("Failed to create %q: %v", reposDump, err)
+			}
+			baseDir := filepath.Base(conf.Repository.Root)
+			for _, r := range repos {
+				name := r.FullName() + ".git"
+				if err := reposZip.AddDir(filepath.Join(baseDir, name), filepath.Join(conf.Repository.Root, name)); err != nil {
+					log.Fatal("Failed to add %q: %v", name, err)
+				}
+			}
+			if err = reposZip.Close(); err != nil {
+				log.Fatal("Failed to save %q: %v", reposDump, err)
+			}
+		} else {
+			if err = zip.PackTo(conf.Repository.Root, reposDump, true); err != nil {
+				log.Fatal("Failed 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("Failed to include 'repositories.zip': %v", err)
+		if err = z.AddFile(archiveRootDir+"/repositories.zip", reposDump); err != nil {
+			log.Fatal("Failed to include %q: %v", reposDump, err)
 		}
 	}
 
@@ -133,7 +159,7 @@ func runBackup(c *cli.Context) error {
 		log.Fatal("Failed to save backup archive '%s': %v", archiveName, err)
 	}
 
-	os.RemoveAll(rootDir)
+	_ = os.RemoveAll(rootDir)
 	log.Info("Backup succeed! Archive is located at: %s", archiveName)
 	log.Stop()
 	return nil

+ 2 - 2
internal/cmd/cmd.go

@@ -25,7 +25,7 @@ func boolFlag(name, usage string) cli.BoolFlag {
 	}
 }
 
-//nolint:deadcode
+//nolint:deadcode,unused
 func intFlag(name string, value int, usage string) cli.IntFlag {
 	return cli.IntFlag{
 		Name:  name,
@@ -34,7 +34,7 @@ func intFlag(name string, value int, usage string) cli.IntFlag {
 	}
 }
 
-//nolint:deadcode
+//nolint:deadcode,unused
 func durationFlag(name string, value time.Duration, usage string) cli.DurationFlag {
 	return cli.DurationFlag{
 		Name:  name,

+ 8 - 8
internal/cmd/hook.go

@@ -23,7 +23,6 @@ import (
 
 	"github.com/G-Node/gogs/internal/conf"
 	"github.com/G-Node/gogs/internal/db"
-	"github.com/G-Node/gogs/internal/db/errors"
 	"github.com/G-Node/gogs/internal/email"
 	"github.com/G-Node/gogs/internal/httplib"
 )
@@ -67,7 +66,7 @@ func runHookPreReceive(c *cli.Context) error {
 	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
 		return nil
 	}
-	setup(c, "hooks/pre-receive.log", true)
+	setup(c, "pre-receive.log", true)
 
 	isWiki := strings.Contains(os.Getenv(db.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")
 
@@ -93,7 +92,7 @@ func runHookPreReceive(c *cli.Context) error {
 		repoID := com.StrTo(os.Getenv(db.ENV_REPO_ID)).MustInt64()
 		protectBranch, err := db.GetProtectBranchOfRepoByName(repoID, branchName)
 		if err != nil {
-			if errors.IsErrBranchNotExist(err) {
+			if db.IsErrBranchNotExist(err) {
 				continue
 			}
 			fail("Internal error", "GetProtectBranchOfRepoByName [repo_id: %d, branch: %s]: %v", repoID, branchName, err)
@@ -160,7 +159,7 @@ func runHookUpdate(c *cli.Context) error {
 	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
 		return nil
 	}
-	setup(c, "hooks/update.log", false)
+	setup(c, "update.log", false)
 
 	args := c.Args()
 	if len(args) != 3 {
@@ -194,7 +193,7 @@ func runHookPostReceive(c *cli.Context) error {
 	if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
 		return nil
 	}
-	setup(c, "hooks/post-receive.log", true)
+	setup(c, "post-receive.log", true)
 
 	// Post-receive hook does more than just gather Git information,
 	// so we need to setup additional services for email notifications.
@@ -239,9 +238,10 @@ func runHookPostReceive(c *cli.Context) error {
 		reqURL := fmt.Sprintf("%s%s/%s/tasks/trigger?%s", conf.Server.LocalRootURL, options.RepoUserName, options.RepoName, q.Encode())
 		log.Trace("Trigger task: %s", reqURL)
 
-		resp, err := httplib.Head(reqURL).SetTLSClientConfig(&tls.Config{
-			InsecureSkipVerify: true,
-		}).Response()
+		resp, err := httplib.Get(reqURL).
+			SetTLSClientConfig(&tls.Config{
+				InsecureSkipVerify: true,
+			}).Response()
 		if err == nil {
 			_ = resp.Body.Close()
 			if resp.StatusCode/100 != 2 {

+ 6 - 6
internal/cmd/import.go

@@ -61,7 +61,7 @@ func runImportLocale(c *cli.Context) error {
 
 	now := time.Now()
 
-	line := make([]byte, 0, 100)
+	var line []byte
 	badChars := []byte(`="`)
 	escapedQuotes := []byte(`\"`)
 	regularQuotes := []byte(`"`)
@@ -97,15 +97,15 @@ func runImportLocale(c *cli.Context) error {
 				line = append(line[:idx+1], line[idx+2:len(line)-1]...)
 				line = bytes.Replace(line, escapedQuotes, regularQuotes, -1)
 			}
-			tw.Write(line)
-			tw.WriteString("\n")
+			_, _ = tw.Write(line)
+			_, _ = tw.WriteString("\n")
 		}
-		sr.Close()
-		tw.Close()
+		_ = sr.Close()
+		_ = tw.Close()
 
 		// Modification time of files from Crowdin often ahead of current,
 		// so we need to set back to current.
-		os.Chtimes(target, now, now)
+		_ = os.Chtimes(target, now, now)
 	}
 
 	fmt.Println("Locale files has been successfully imported!")

+ 12 - 8
internal/cmd/restore.go

@@ -9,7 +9,6 @@ import (
 	"path"
 	"path/filepath"
 
-	"github.com/mcuadros/go-version"
 	"github.com/pkg/errors"
 	"github.com/unknwon/cae/zip"
 	"github.com/unknwon/com"
@@ -19,6 +18,7 @@ import (
 
 	"github.com/G-Node/gogs/internal/conf"
 	"github.com/G-Node/gogs/internal/db"
+	"github.com/G-Node/gogs/internal/semverutil"
 )
 
 var Restore = cli.Command{
@@ -57,8 +57,8 @@ func runRestore(c *cli.Context) error {
 	if err := zip.ExtractTo(c.String("from"), tmpDir); err != nil {
 		log.Fatal("Failed to extract backup archive: %v", err)
 	}
-	archivePath := path.Join(tmpDir, _ARCHIVE_ROOT_DIR)
-	defer os.RemoveAll(archivePath)
+	archivePath := path.Join(tmpDir, archiveRootDir)
+	defer func() { _ = os.RemoveAll(archivePath) }()
 
 	// Check backup version
 	metaFile := filepath.Join(archivePath, "metadata.ini")
@@ -70,16 +70,16 @@ func runRestore(c *cli.Context) error {
 		log.Fatal("Failed to load metadata '%s': %v", metaFile, err)
 	}
 	backupVersion := metadata.Section("").Key("GOGS_VERSION").MustString("999.0")
-	if version.Compare(conf.App.Version, backupVersion, "<") {
+	if semverutil.Compare(conf.App.Version, "<", backupVersion) {
 		log.Fatal("Current Gogs version is lower than backup version: %s < %s", conf.App.Version, backupVersion)
 	}
 	formatVersion := metadata.Section("").Key("VERSION").MustInt()
 	if formatVersion == 0 {
 		log.Fatal("Failed to determine the backup format version from metadata '%s': %s", metaFile, "VERSION is not presented")
 	}
-	if formatVersion != _CURRENT_BACKUP_FORMAT_VERSION {
+	if formatVersion != currentBackupFormatVersion {
 		log.Fatal("Backup format version found is %d but this binary only supports %d\nThe last known version that is able to import your backup is %s",
-			formatVersion, _CURRENT_BACKUP_FORMAT_VERSION, lastSupportedVersionOfFormat[formatVersion])
+			formatVersion, currentBackupFormatVersion, lastSupportedVersionOfFormat[formatVersion])
 	}
 
 	// If config file is not present in backup, user must set this file via flag.
@@ -98,12 +98,16 @@ func runRestore(c *cli.Context) error {
 	if err != nil {
 		return errors.Wrap(err, "init configuration")
 	}
+	conf.InitLogging(true)
 
-	db.SetEngine()
+	conn, err := db.SetEngine()
+	if err != nil {
+		return errors.Wrap(err, "set engine")
+	}
 
 	// Database
 	dbDir := path.Join(archivePath, "db")
-	if err = db.ImportDatabase(dbDir, c.Bool("verbose")); err != nil {
+	if err = db.ImportDatabase(conn, dbDir, c.Bool("verbose")); err != nil {
 		log.Fatal("Failed to import database: %v", err)
 	}
 

+ 23 - 21
internal/cmd/serv.go

@@ -18,7 +18,6 @@ import (
 
 	"github.com/G-Node/gogs/internal/conf"
 	"github.com/G-Node/gogs/internal/db"
-	"github.com/G-Node/gogs/internal/db/errors"
 )
 
 const (
@@ -39,7 +38,7 @@ var Serv = cli.Command{
 // logs error message on the server side. When not in "prod" mode,
 // error message is also printed to the client for easier debugging.
 func fail(userMessage, errMessage string, args ...interface{}) {
-	fmt.Fprintln(os.Stderr, "GIN:", userMessage)
+	_, _ = fmt.Fprintln(os.Stderr, "GIN:", userMessage)
 
 	if len(errMessage) > 0 {
 		if !conf.IsProdMode() {
@@ -48,10 +47,11 @@ func fail(userMessage, errMessage string, args ...interface{}) {
 		log.Error(errMessage, args...)
 	}
 
+	log.Stop()
 	os.Exit(1)
 }
 
-func setup(c *cli.Context, logPath string, connectDB bool) {
+func setup(c *cli.Context, logFile string, connectDB bool) {
 	conf.HookMode = true
 
 	var customConf string
@@ -74,7 +74,7 @@ func setup(c *cli.Context, logPath string, connectDB bool) {
 
 	err = log.NewFile(log.FileConfig{
 		Level:    level,
-		Filename: filepath.Join(conf.Log.RootPath, logPath),
+		Filename: filepath.Join(conf.Log.RootPath, "hooks", logFile),
 		FileRotationConfig: log.FileRotationConfig{
 			Rotate:  true,
 			Daily:   true,
@@ -94,7 +94,7 @@ func setup(c *cli.Context, logPath string, connectDB bool) {
 		_ = os.Chdir(conf.WorkDir())
 	}
 
-	if err := db.SetEngine(); err != nil {
+	if _, err := db.SetEngine(); err != nil {
 		fail("Internal error", "Failed to set database engine: %v", err)
 	}
 }
@@ -135,10 +135,10 @@ func checkDeployKey(key *db.PublicKey, repo *db.Repository) {
 
 var (
 	allowedCommands = map[string]db.AccessMode{
-		"git-upload-pack":    db.ACCESS_MODE_READ,
-		"git-upload-archive": db.ACCESS_MODE_READ,
-		"git-receive-pack":   db.ACCESS_MODE_WRITE,
-		"git-annex-shell":    db.ACCESS_MODE_READ,
+		"git-upload-pack":    db.AccessModeRead,
+		"git-upload-archive": db.AccessModeRead,
+		"git-receive-pack":   db.AccessModeWrite,
+		"git-annex-shell":    db.AccessModeRead,
 	}
 )
 
@@ -173,7 +173,7 @@ func runServ(c *cli.Context) error {
 
 	owner, err := db.GetUserByName(ownerName)
 	if err != nil {
-		if errors.IsUserNotExist(err) {
+		if db.IsErrUserNotExist(err) {
 			fail("Repository owner does not exist", "Unregistered owner: %s", ownerName)
 		}
 		fail("Internal error", "Failed to get repository owner '%s': %v", ownerName, err)
@@ -181,7 +181,7 @@ func runServ(c *cli.Context) error {
 
 	repo, err := db.GetRepositoryByName(owner.ID, repoName)
 	if err != nil {
-		if errors.IsRepoNotExist(err) {
+		if db.IsErrRepoNotExist(err) {
 			fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", owner.Name, repoName)
 		}
 		fail("Internal error", "Failed to get repository: %v", err)
@@ -194,7 +194,7 @@ func runServ(c *cli.Context) error {
 	}
 
 	// Prohibit push to mirror repositories.
-	if requestMode > db.ACCESS_MODE_READ && repo.IsMirror {
+	if requestMode > db.AccessModeRead && repo.IsMirror {
 		fail("Mirror repository is read-only", "")
 	}
 
@@ -206,13 +206,14 @@ func runServ(c *cli.Context) error {
 		fail("Invalid key ID", "Invalid key ID '%s': %v", c.Args()[0], err)
 	}
 
+	// GIN specific code
 	if us, err := db.GetUserByKeyID(key.ID); err == nil {
 		user = us
 	} else {
 		fail("Key Error", "Cannot find key %v", err)
 	}
 
-	if requestMode == db.ACCESS_MODE_WRITE || repo.IsPrivate {
+	if requestMode == db.AccessModeWrite || repo.IsPrivate {
 		// Check deploy key or user key.
 		if key.IsDeployKey() {
 			if key.Mode < requestMode {
@@ -232,7 +233,7 @@ func runServ(c *cli.Context) error {
 
 			if mode < requestMode {
 				clientMessage := _ACCESS_DENIED_MESSAGE
-				if mode >= db.ACCESS_MODE_READ {
+				if mode >= db.AccessModeRead {
 					clientMessage = "You do not have sufficient authorization for this action"
 				}
 				fail(clientMessage,
@@ -264,7 +265,7 @@ func runServ(c *cli.Context) error {
 	}
 
 	// Special handle for Windows.
-	// Todo will break with annex
+	// GIN specific: this code alteration also breaks Windows compatibility
 	if conf.IsWindowsRuntime() {
 		verb = strings.Replace(verb, "-", " ", 1)
 	}
@@ -284,18 +285,18 @@ func runServ(c *cli.Context) error {
 		cmd = []string{verb, repoFullName}
 	}
 	runGit(cmd, requestMode, user, owner, repo)
-	if requestMode == db.ACCESS_MODE_WRITE {
+	if requestMode == db.AccessModeWrite {
 		db.StartIndexing(*repo)
 	}
 	return nil
-
 }
 
+// GIN specific: code altered from upstream, this function requires a review
 func runGit(cmd []string, requestMode db.AccessMode, user *db.User, owner *db.User,
 	repo *db.Repository) error {
 	log.Info("Running %q", cmd)
 	gitCmd := exec.Command(cmd[0], cmd[1:]...)
-	if requestMode == db.ACCESS_MODE_WRITE {
+	if requestMode == db.AccessModeWrite {
 		gitCmd.Env = append(os.Environ(), db.ComposeHookEnvs(db.ComposeHookEnvsOptions{
 			AuthUser:  user,
 			OwnerName: owner.Name,
@@ -316,7 +317,8 @@ func runGit(cmd []string, requestMode db.AccessMode, user *db.User, owner *db.Us
 	return nil
 }
 
-// Make sure git-annex-shell does not make "bad" changes (refectored from repo)
+// Make sure git-annex-shell does not make "bad" changes (refactored from repo)
+// GIN specific code
 func secureGitAnnex(path string, user *db.User, repo *db.Repository) error {
 	// "If set, disallows running git-shell to handle unknown commands."
 	err := os.Setenv("GIT_ANNEX_SHELL_LIMITED", "True")
@@ -329,14 +331,14 @@ func secureGitAnnex(path string, user *db.User, repo *db.Repository) error {
 	if err != nil {
 		return fmt.Errorf("ERROR: Could set annex shell directory.")
 	}
-	mode := db.ACCESS_MODE_NONE
+	mode := db.AccessModeNone
 	if user != nil {
 		mode, err = db.UserAccessMode(user.ID, repo)
 		if err != nil {
 			fail("Internal error", "Fail to check access: %v", err)
 		}
 	}
-	if mode < db.ACCESS_MODE_WRITE {
+	if mode < db.AccessModeWrite {
 		err = os.Setenv("GIT_ANNEX_SHELL_READONLY", "True")
 		if err != nil {
 			return fmt.Errorf("ERROR: Could set annex shell to read only.")

+ 485 - 479
internal/cmd/web.go

@@ -29,6 +29,7 @@ import (
 	"gopkg.in/macaron.v1"
 	log "unknwon.dev/clog/v2"
 
+	"github.com/G-Node/gogs/internal/app"
 	"github.com/G-Node/gogs/internal/assets/public"
 	"github.com/G-Node/gogs/internal/assets/templates"
 	"github.com/G-Node/gogs/internal/conf"
@@ -41,6 +42,7 @@ import (
 	"github.com/G-Node/gogs/internal/route/admin"
 	apiv1 "github.com/G-Node/gogs/internal/route/api/v1"
 	"github.com/G-Node/gogs/internal/route/dev"
+	"github.com/G-Node/gogs/internal/route/lfs"
 	"github.com/G-Node/gogs/internal/route/org"
 	"github.com/G-Node/gogs/internal/route/repo"
 	"github.com/G-Node/gogs/internal/route/user"
@@ -144,22 +146,6 @@ func newMacaron() *macaron.Macaron {
 	m.Use(captcha.Captchaer(captcha.Options{
 		SubURL: conf.Server.Subpath,
 	}))
-	m.Use(session.Sessioner(session.Options{
-		Provider:       conf.Session.Provider,
-		ProviderConfig: conf.Session.ProviderConfig,
-		CookieName:     conf.Session.CookieName,
-		CookiePath:     conf.Server.Subpath,
-		Gclifetime:     conf.Session.GCInterval,
-		Maxlifetime:    conf.Session.MaxLifeTime,
-		Secure:         conf.Session.CookieSecure,
-	}))
-	m.Use(csrf.Csrfer(csrf.Options{
-		Secret:     conf.Security.SecretKey,
-		Cookie:     conf.Session.CSRFCookieName,
-		SetCookie:  true,
-		Header:     "X-Csrf-Token",
-		CookiePath: conf.Server.Subpath,
-	}))
 	m.Use(toolbox.Toolboxer(m, toolbox.Options{
 		HealthCheckFuncs: []*toolbox.HealthCheckFuncDesc{
 			{
@@ -168,11 +154,12 @@ func newMacaron() *macaron.Macaron {
 			},
 		},
 	}))
-	m.Use(context.Contexter())
-	// Webdav handler todo: implement
+
+	// GIN specifc code: Webdav handler todo: implement
 	h := &webdav.Handler{FileSystem: &dav.GinFS{BasePath: conf.Repository.Root}, LockSystem: webdav.NewMemLS(),
 		Logger: dav.Logger}
 	m.Map(h)
+
 	return m
 }
 
@@ -186,530 +173,549 @@ func runWeb(c *cli.Context) error {
 
 	reqSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: true})
 	ignSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: conf.Auth.RequireSigninView})
-	ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true})
 	reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true})
 
 	bindIgnErr := binding.BindIgnErr
 
 	m.SetAutoHead(true)
 
-	// FIXME: not all route need go through same middlewares.
-	// Especially some AJAX requests, we can reduce middleware number to improve performance.
-	// Routers.
-	m.Get("/", ignSignIn, route.Home)
-	m.Group("/explore", func() {
-		m.Get("", func(c *context.Context) {
-			c.Redirect(conf.Server.Subpath + "/explore/repos")
-		})
-		m.Get("/data", route.ExploreData)
-		m.Get("/commits", route.ExploreCommits)
-		m.Get("/repos", route.ExploreRepos)
-		m.Get("/users", route.ExploreUsers)
-		m.Get("/organizations", route.ExploreOrganizations)
-		m.Get("/_suggest/:keywords", route.ExploreSuggest)
-	}, ignSignIn)
-	m.Combo("/install", route.InstallInit).Get(route.Install).
-		Post(bindIgnErr(form.Install{}), route.InstallPost)
-	m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
-
-	// ***** START: User *****
-	m.Group("/user", func() {
-		m.Group("/login", func() {
-			m.Combo("").Get(user.Login).
-				Post(bindIgnErr(form.SignIn{}), user.LoginPost)
-			m.Combo("/two_factor").Get(user.LoginTwoFactor).Post(user.LoginTwoFactorPost)
-			m.Combo("/two_factor_recovery_code").Get(user.LoginTwoFactorRecoveryCode).Post(user.LoginTwoFactorRecoveryCodePost)
-		})
+	m.Group("", func() {
+		m.Get("/", ignSignIn, route.Home)
+		m.Group("/explore", func() {
+			m.Get("", func(c *context.Context) {
+				c.Redirect(conf.Server.Subpath + "/explore/repos")
+			})
+			m.Get("/data", route.ExploreData) // GIN specific code
+			m.Get("/commits", route.ExploreCommits) // GIN specific code
+			m.Get("/repos", route.ExploreRepos)
+			m.Get("/users", route.ExploreUsers)
+			m.Get("/organizations", route.ExploreOrganizations)
+			m.Get("/_suggest/:keywords", route.ExploreSuggest) // GIN specific code
+			}, ignSignIn)
+		m.Combo("/install", route.InstallInit).Get(route.Install).
+			Post(bindIgnErr(form.Install{}), route.InstallPost)
+		m.Get("/^:type(issues|pulls)$", reqSignIn, user.Issues)
+
+		// ***** START: User *****
+		m.Group("/user", func() {
+			m.Group("/login", func() {
+				m.Combo("").Get(user.Login).
+					Post(bindIgnErr(form.SignIn{}), user.LoginPost)
+				m.Combo("/two_factor").Get(user.LoginTwoFactor).Post(user.LoginTwoFactorPost)
+				m.Combo("/two_factor_recovery_code").Get(user.LoginTwoFactorRecoveryCode).Post(user.LoginTwoFactorRecoveryCodePost)
+			})
 
-		m.Get("/sign_up", user.SignUp)
-		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(form.UpdateProfile{}), user.SettingsPost)
-		m.Combo("/avatar").Get(user.SettingsAvatar).
-			Post(binding.MultipartForm(form.Avatar{}), user.SettingsAvatarPost)
-		m.Post("/avatar/delete", user.SettingsDeleteAvatar)
-		m.Combo("/email").Get(user.SettingsEmails).
-			Post(bindIgnErr(form.AddEmail{}), user.SettingsEmailPost)
-		m.Post("/email/delete", user.DeleteEmail)
-		m.Get("/password", user.SettingsPassword)
-		m.Post("/password", bindIgnErr(form.ChangePassword{}), user.SettingsPasswordPost)
-		m.Combo("/ssh").Get(user.SettingsSSHKeys).
-			Post(bindIgnErr(form.AddSSHKey{}), user.SettingsSSHKeysPost)
-		m.Post("/ssh/delete", user.DeleteSSHKey)
-		m.Group("/security", func() {
-			m.Get("", user.SettingsSecurity)
-			m.Combo("/two_factor_enable").Get(user.SettingsTwoFactorEnable).
-				Post(user.SettingsTwoFactorEnablePost)
-			m.Combo("/two_factor_recovery_codes").Get(user.SettingsTwoFactorRecoveryCodes).
-				Post(user.SettingsTwoFactorRecoveryCodesPost)
-			m.Post("/two_factor_disable", user.SettingsTwoFactorDisable)
-		})
-		m.Group("/repositories", func() {
-			m.Get("", user.SettingsRepos)
-			m.Post("/leave", user.SettingsLeaveRepo)
-		})
-		m.Group("/organizations", func() {
-			m.Get("", user.SettingsOrganizations)
-			m.Post("/leave", user.SettingsLeaveOrganization)
+			m.Get("/sign_up", user.SignUp)
+			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(form.UpdateProfile{}), user.SettingsPost)
+			m.Combo("/avatar").Get(user.SettingsAvatar).
+				Post(binding.MultipartForm(form.Avatar{}), user.SettingsAvatarPost)
+			m.Post("/avatar/delete", user.SettingsDeleteAvatar)
+			m.Combo("/email").Get(user.SettingsEmails).
+				Post(bindIgnErr(form.AddEmail{}), user.SettingsEmailPost)
+			m.Post("/email/delete", user.DeleteEmail)
+			m.Get("/password", user.SettingsPassword)
+			m.Post("/password", bindIgnErr(form.ChangePassword{}), user.SettingsPasswordPost)
+			m.Combo("/ssh").Get(user.SettingsSSHKeys).
+				Post(bindIgnErr(form.AddSSHKey{}), user.SettingsSSHKeysPost)
+			m.Post("/ssh/delete", user.DeleteSSHKey)
+			m.Group("/security", func() {
+				m.Get("", user.SettingsSecurity)
+				m.Combo("/two_factor_enable").Get(user.SettingsTwoFactorEnable).
+					Post(user.SettingsTwoFactorEnablePost)
+				m.Combo("/two_factor_recovery_codes").Get(user.SettingsTwoFactorRecoveryCodes).
+					Post(user.SettingsTwoFactorRecoveryCodesPost)
+				m.Post("/two_factor_disable", user.SettingsTwoFactorDisable)
+			})
+			m.Group("/repositories", func() {
+				m.Get("", user.SettingsRepos)
+				m.Post("/leave", user.SettingsLeaveRepo)
+			})
+			m.Group("/organizations", func() {
+				m.Get("", user.SettingsOrganizations)
+				m.Post("/leave", user.SettingsLeaveOrganization)
+			})
+			m.Combo("/applications").Get(user.SettingsApplications).
+				Post(bindIgnErr(form.NewAccessToken{}), user.SettingsApplicationsPost)
+			m.Post("/applications/delete", user.SettingsDeleteApplication)
+			m.Route("/delete", "GET,POST", user.SettingsDelete)
+		}, reqSignIn, func(c *context.Context) {
+			c.Data["PageIsUserSettings"] = true
 		})
-		m.Combo("/applications").Get(user.SettingsApplications).
-			Post(bindIgnErr(form.NewAccessToken{}), user.SettingsApplicationsPost)
-		m.Post("/applications/delete", user.SettingsDeleteApplication)
-		m.Route("/delete", "GET,POST", user.SettingsDelete)
-	}, reqSignIn, func(c *context.Context) {
-		c.Data["PageIsUserSettings"] = true
-	})
 
-	m.Group("/user", func() {
-		m.Any("/activate", user.Activate)
-		m.Any("/activate_email", user.ActivateEmail)
-		m.Get("/email2user", user.Email2User)
-		m.Get("/forget_password", user.ForgotPasswd)
-		m.Post("/forget_password", user.ForgotPasswdPost)
-		m.Post("/logout", user.SignOut)
-	})
-	// ***** END: User *****
-
-	reqAdmin := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})
-
-	// ***** START: Admin *****
-	m.Group("/admin", func() {
-		m.Get("", admin.Dashboard)
-		m.Get("/config", admin.Config)
-		m.Post("/config/test_mail", admin.SendTestMail)
-		m.Get("/monitor", admin.Monitor)
-
-		m.Group("/users", func() {
-			m.Get("", admin.Users)
-			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)
+		m.Group("/user", func() {
+			m.Any("/activate", user.Activate)
+			m.Any("/activate_email", user.ActivateEmail)
+			m.Get("/email2user", user.Email2User)
+			m.Get("/forget_password", user.ForgotPasswd)
+			m.Post("/forget_password", user.ForgotPasswdPost)
+			m.Post("/logout", user.SignOut)
 		})
+		// ***** END: User *****
+
+		reqAdmin := context.Toggle(&context.ToggleOptions{SignInRequired: true, AdminRequired: true})
+
+		// ***** START: Admin *****
+		m.Group("/admin", func() {
+			m.Combo("").Get(admin.Dashboard).Post(admin.Operation) // "/admin"
+			m.Get("/config", admin.Config)
+			m.Post("/config/test_mail", admin.SendTestMail)
+			m.Get("/monitor", admin.Monitor)
+
+			m.Group("/users", func() {
+				m.Get("", admin.Users)
+				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)
+			})
 
-		m.Group("/orgs", func() {
-			m.Get("", admin.Organizations)
-		})
+			m.Group("/orgs", func() {
+				m.Get("", admin.Organizations)
+			})
 
-		m.Group("/repos", func() {
-			m.Get("", admin.Repos)
-			m.Post("/delete", admin.DeleteRepo)
-		})
+			m.Group("/repos", func() {
+				m.Get("", admin.Repos)
+				m.Post("/delete", admin.DeleteRepo)
+			})
 
-		m.Group("/auths", func() {
-			m.Get("", admin.Authentications)
-			m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(form.Authentication{}), admin.NewAuthSourcePost)
-			m.Combo("/:authid").Get(admin.EditAuthSource).
-				Post(bindIgnErr(form.Authentication{}), admin.EditAuthSourcePost)
-			m.Post("/:authid/delete", admin.DeleteAuthSource)
-		})
+			m.Group("/auths", func() {
+				m.Get("", admin.Authentications)
+				m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(form.Authentication{}), admin.NewAuthSourcePost)
+				m.Combo("/:authid").Get(admin.EditAuthSource).
+					Post(bindIgnErr(form.Authentication{}), admin.EditAuthSourcePost)
+				m.Post("/:authid/delete", admin.DeleteAuthSource)
+			})
 
-		m.Group("/notices", func() {
-			m.Get("", admin.Notices)
-			m.Post("/delete", admin.DeleteNotices)
-			m.Get("/empty", admin.EmptyNotices)
-		})
-	}, reqAdmin)
-	// ***** END: Admin *****
+			m.Group("/notices", func() {
+				m.Get("", admin.Notices)
+				m.Post("/delete", admin.DeleteNotices)
+				m.Get("/empty", admin.EmptyNotices)
+			})
+		}, reqAdmin)
+		// ***** END: Admin *****
 
-	m.Group("", func() {
-		m.Group("/:username", func() {
-			m.Get("", user.Profile)
-			m.Get("/followers", user.Followers)
-			m.Get("/following", user.Following)
-			m.Get("/stars", user.Stars)
-		}, context.InjectParamsUser())
-
-		m.Get("/attachments/:uuid", func(c *context.Context) {
-			attach, err := db.GetAttachmentByUUID(c.Params(":uuid"))
-			if err != nil {
-				c.NotFoundOrServerError("GetAttachmentByUUID", db.IsErrAttachmentNotExist, err)
-				return
-			} else if !com.IsFile(attach.LocalPath()) {
-				c.NotFound()
-				return
-			}
+		m.Group("", func() {
+			m.Group("/:username", func() {
+				m.Get("", user.Profile)
+				m.Get("/followers", user.Followers)
+				m.Get("/following", user.Following)
+				m.Get("/stars", user.Stars)
+			}, context.InjectParamsUser())
+
+			m.Get("/attachments/:uuid", func(c *context.Context) {
+				attach, err := db.GetAttachmentByUUID(c.Params(":uuid"))
+				if err != nil {
+					c.NotFoundOrError(err, "get attachment by UUID")
+					return
+				} else if !com.IsFile(attach.LocalPath()) {
+					c.NotFound()
+					return
+				}
 
-			fr, err := os.Open(attach.LocalPath())
-			if err != nil {
-				c.ServerError("open attachment file", err)
-				return
-			}
-			defer fr.Close()
+				fr, err := os.Open(attach.LocalPath())
+				if err != nil {
+					c.Error(err, "open attachment file")
+					return
+				}
+				defer fr.Close()
 
-			c.Header().Set("Cache-Control", "public,max-age=86400")
-			c.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, attach.Name))
-			if _, err = io.Copy(c.Resp, fr); err != nil {
-				c.ServerError("copy from file to response", err)
-				return
-			}
-		})
-		m.Post("/issues/attachments", repo.UploadIssueAttachment)
-		m.Post("/releases/attachments", repo.UploadReleaseAttachment)
-	}, ignSignIn)
+				c.Header().Set("Cache-Control", "public,max-age=86400")
+				c.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, attach.Name))
 
-	m.Group("/:username", func() {
-		m.Post("/action/:action", user.Action)
-	}, reqSignIn, context.InjectParamsUser())
+				if _, err = io.Copy(c.Resp, fr); err != nil {
+					c.Error(err, "copy from file to response")
+					return
+				}
+			})
+			m.Post("/issues/attachments", repo.UploadIssueAttachment)
+			m.Post("/releases/attachments", repo.UploadReleaseAttachment)
+		}, ignSignIn)
 
-	if macaron.Env == macaron.DEV {
-		m.Get("/template/*", dev.TemplatePreview)
-	}
+		m.Group("/:username", func() {
+			m.Post("/action/:action", user.Action)
+		}, reqSignIn, context.InjectParamsUser())
 
-	reqRepoAdmin := context.RequireRepoAdmin()
-	reqRepoWriter := context.RequireRepoWriter()
+		if macaron.Env == macaron.DEV {
+			m.Get("/template/*", dev.TemplatePreview)
+		}
 
-	// ***** START: Organization *****
-	m.Group("/org", func() {
-		m.Group("", func() {
-			m.Get("/create", org.Create)
-			m.Post("/create", bindIgnErr(form.CreateOrg{}), org.CreatePost)
-		}, func(c *context.Context) {
-			if !c.User.CanCreateOrganization() {
-				c.NotFound()
-			}
-		})
+		reqRepoAdmin := context.RequireRepoAdmin()
+		reqRepoWriter := context.RequireRepoWriter()
+
+		webhookRoutes := func() {
+			m.Group("", func() {
+				m.Get("", repo.Webhooks)
+				m.Post("/delete", repo.DeleteWebhook)
+				m.Get("/:type/new", repo.WebhooksNew)
+				m.Post("/gogs/new", bindIgnErr(form.NewWebhook{}), repo.WebhooksNewPost)
+				m.Post("/slack/new", bindIgnErr(form.NewSlackHook{}), repo.WebhooksSlackNewPost)
+				m.Post("/discord/new", bindIgnErr(form.NewDiscordHook{}), repo.WebhooksDiscordNewPost)
+				m.Post("/dingtalk/new", bindIgnErr(form.NewDingtalkHook{}), repo.WebhooksDingtalkNewPost)
+				m.Get("/:id", repo.WebhooksEdit)
+				m.Post("/gogs/:id", bindIgnErr(form.NewWebhook{}), repo.WebhooksEditPost)
+				m.Post("/slack/:id", bindIgnErr(form.NewSlackHook{}), repo.WebhooksSlackEditPost)
+				m.Post("/discord/:id", bindIgnErr(form.NewDiscordHook{}), repo.WebhooksDiscordEditPost)
+				m.Post("/dingtalk/:id", bindIgnErr(form.NewDingtalkHook{}), repo.WebhooksDingtalkEditPost)
+			}, repo.InjectOrgRepoContext())
+		}
+
+		// ***** START: Organization *****
+		m.Group("/org", func() {
+			m.Group("", func() {
+				m.Get("/create", org.Create)
+				m.Post("/create", bindIgnErr(form.CreateOrg{}), org.CreatePost)
+			}, func(c *context.Context) {
+				if !c.User.CanCreateOrganization() {
+					c.NotFound()
+				}
+			})
 
-		m.Group("/:org", func() {
-			m.Get("/dashboard", user.Dashboard)
-			m.Get("/^:type(issues|pulls)$", user.Issues)
-			m.Get("/members", org.Members)
-			m.Get("/members/action/:action", org.MembersAction)
-
-			m.Get("/teams", org.Teams)
-		}, context.OrgAssignment(true))
-
-		m.Group("/:org", func() {
-			m.Get("/teams/:team", org.TeamMembers)
-			m.Get("/teams/:team/repositories", org.TeamRepositories)
-			m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction)
-			m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction)
-		}, context.OrgAssignment(true, false, true))
-
-		m.Group("/:org", func() {
-			m.Get("/teams/new", org.NewTeam)
-			m.Post("/teams/new", bindIgnErr(form.CreateTeam{}), org.NewTeamPost)
-			m.Get("/teams/:team/edit", org.EditTeam)
-			m.Post("/teams/:team/edit", bindIgnErr(form.CreateTeam{}), org.EditTeamPost)
-			m.Post("/teams/:team/delete", org.DeleteTeam)
+			m.Group("/:org", func() {
+				m.Get("/dashboard", user.Dashboard)
+				m.Get("/^:type(issues|pulls)$", user.Issues)
+				m.Get("/members", org.Members)
+				m.Get("/members/action/:action", org.MembersAction)
+
+				m.Get("/teams", org.Teams)
+			}, context.OrgAssignment(true))
+
+			m.Group("/:org", func() {
+				m.Get("/teams/:team", org.TeamMembers)
+				m.Get("/teams/:team/repositories", org.TeamRepositories)
+				m.Route("/teams/:team/action/:action", "GET,POST", org.TeamsAction)
+				m.Route("/teams/:team/action/repo/:action", "GET,POST", org.TeamsRepoAction)
+			}, context.OrgAssignment(true, false, true))
+
+			m.Group("/:org", func() {
+				m.Get("/teams/new", org.NewTeam)
+				m.Post("/teams/new", bindIgnErr(form.CreateTeam{}), org.NewTeamPost)
+				m.Get("/teams/:team/edit", org.EditTeam)
+				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(form.UpdateOrgSetting{}), org.SettingsPost)
+					m.Post("/avatar", binding.MultipartForm(form.Avatar{}), org.SettingsAvatar)
+					m.Post("/avatar/delete", org.SettingsDeleteAvatar)
+					m.Group("/hooks", webhookRoutes)
+					m.Route("/delete", "GET,POST", org.SettingsDelete)
+				})
 
+				m.Route("/invitations/new", "GET,POST", org.Invitation)
+			}, context.OrgAssignment(true, true))
+		}, reqSignIn)
+		// ***** END: Organization *****
+
+		// ***** START: Repository *****
+		m.Group("/repo", func() {
+			m.Get("/create", repo.Create)
+			m.Post("/create", bindIgnErr(form.CreateRepo{}), repo.CreatePost)
+			m.Get("/migrate", repo.Migrate)
+			m.Post("/migrate", bindIgnErr(form.MigrateRepo{}), repo.MigratePost)
+			m.Combo("/fork/:repoid").Get(repo.Fork).
+				Post(bindIgnErr(form.CreateRepo{}), repo.ForkPost)
+		}, reqSignIn)
+		m.Any("/:username/:reponame/_dav/*", dav.DavMiddle(), dav.Dav) // GIN specific code
+		m.Any("/:username/:reponame/_dav", dav.DavMiddle(), dav.Dav) // GIN specific code
+
+		m.Group("/:username/:reponame", func() {
 			m.Group("/settings", func() {
-				m.Combo("").Get(org.Settings).
-					Post(bindIgnErr(form.UpdateOrgSetting{}), org.SettingsPost)
-				m.Post("/avatar", binding.MultipartForm(form.Avatar{}), org.SettingsAvatar)
-				m.Post("/avatar/delete", org.SettingsDeleteAvatar)
+				m.Combo("").Get(repo.Settings).
+					Post(bindIgnErr(form.RepoSetting{}), repo.SettingsPost)
+				m.Combo("/avatar").Get(repo.SettingsAvatar).
+					Post(binding.MultipartForm(form.Avatar{}), repo.SettingsAvatarPost)
+				m.Post("/avatar/delete", repo.SettingsDeleteAvatar)
+				m.Group("/collaboration", func() {
+					m.Combo("").Get(repo.SettingsCollaboration).Post(repo.SettingsCollaborationPost)
+					m.Post("/access_mode", repo.ChangeCollaborationAccessMode)
+					m.Post("/delete", repo.DeleteCollaboration)
+				})
+				m.Group("/branches", func() {
+					m.Get("", repo.SettingsBranches)
+					m.Post("/default_branch", repo.UpdateDefaultBranch)
+					m.Combo("/*").Get(repo.SettingsProtectedBranch).
+						Post(bindIgnErr(form.ProtectBranch{}), repo.SettingsProtectedBranchPost)
+				}, func(c *context.Context) {
+					if c.Repo.Repository.IsMirror {
+						c.NotFound()
+						return
+					}
+				})
 
 				m.Group("/hooks", func() {
-					m.Get("", org.Webhooks)
-					m.Post("/delete", org.DeleteWebhook)
-					m.Get("/:type/new", repo.WebhooksNew)
-					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.Post("/dingtalk/new", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksNewPost)
-					m.Get("/:id", repo.WebHooksEdit)
-					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.Post("/dingtalk/:id", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksEditPost)
+					webhookRoutes()
+
+					m.Group("/:id", func() {
+						m.Post("/test", repo.TestWebhook)
+						m.Post("/redelivery", repo.RedeliveryWebhook)
+					})
+
+					m.Group("/git", func() {
+						m.Get("", repo.SettingsGitHooks)
+						m.Combo("/:name").Get(repo.SettingsGitHooksEdit).
+							Post(repo.SettingsGitHooksEditPost)
+					}, context.GitHookService())
 				})
 
-				m.Route("/delete", "GET,POST", org.SettingsDelete)
-			})
-
-			m.Route("/invitations/new", "GET,POST", org.Invitation)
-		}, context.OrgAssignment(true, true))
-	}, reqSignIn)
-	// ***** END: Organization *****
-
-	// ***** START: Repository *****
-	m.Group("/repo", func() {
-		m.Get("/create", repo.Create)
-		m.Post("/create", bindIgnErr(form.CreateRepo{}), repo.CreatePost)
-		m.Get("/migrate", repo.Migrate)
-		m.Post("/migrate", bindIgnErr(form.MigrateRepo{}), repo.MigratePost)
-		m.Combo("/fork/:repoid").Get(repo.Fork).
-			Post(bindIgnErr(form.CreateRepo{}), repo.ForkPost)
-	}, reqSignIn)
-	m.Any("/:username/:reponame/_dav/*", dav.DavMiddle(), dav.Dav)
-	m.Any("/:username/:reponame/_dav", dav.DavMiddle(), dav.Dav)
+				m.Group("/keys", func() {
+					m.Combo("").Get(repo.SettingsDeployKeys).
+						Post(bindIgnErr(form.AddSSHKey{}), repo.SettingsDeployKeysPost)
+					m.Post("/delete", repo.DeleteDeployKey)
+				})
 
-	m.Group("/:username/:reponame", func() {
-		m.Group("/settings", func() {
-			m.Combo("").Get(repo.Settings).
-				Post(bindIgnErr(form.RepoSetting{}), repo.SettingsPost)
-			m.Combo("/avatar").Get(repo.SettingsAvatar).
-				Post(binding.MultipartForm(form.Avatar{}), repo.SettingsAvatarPost)
-			m.Post("/avatar/delete", repo.SettingsDeleteAvatar)
-			m.Group("/collaboration", func() {
-				m.Combo("").Get(repo.SettingsCollaboration).Post(repo.SettingsCollaborationPost)
-				m.Post("/access_mode", repo.ChangeCollaborationAccessMode)
-				m.Post("/delete", repo.DeleteCollaboration)
-			})
-			m.Group("/branches", func() {
-				m.Get("", repo.SettingsBranches)
-				m.Post("/default_branch", repo.UpdateDefaultBranch)
-				m.Combo("/*").Get(repo.SettingsProtectedBranch).
-					Post(bindIgnErr(form.ProtectBranch{}), repo.SettingsProtectedBranchPost)
 			}, func(c *context.Context) {
-				if c.Repo.Repository.IsMirror {
-					c.NotFound()
-					return
-				}
+				c.Data["PageIsSettings"] = true
 			})
-
-			m.Group("/hooks", func() {
-				m.Get("", repo.Webhooks)
-				m.Post("/delete", repo.DeleteWebhook)
-				m.Get("/:type/new", repo.WebhooksNew)
-				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.Post("/dingtalk/new", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksNewPost)
-				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.Post("/dingtalk/:id", bindIgnErr(form.NewDingtalkHook{}), repo.DingtalkHooksEditPost)
-
-				m.Group("/:id", func() {
-					m.Get("", repo.WebHooksEdit)
-					m.Post("/test", repo.TestWebhook)
-					m.Post("/redelivery", repo.RedeliveryWebhook)
+		}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
+
+		m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
+		m.Group("/:username/:reponame", func() {
+			m.Get("/issues", repo.RetrieveLabels, repo.Issues)
+			m.Get("/issues/:index", repo.ViewIssue)
+			m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
+			m.Get("/milestones", repo.Milestones)
+			m.Get("/doi", route.RequestDOI) // GIN specific code
+		}, ignSignIn, context.RepoAssignment(true))
+		m.Group("/:username/:reponame", func() {
+			// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
+			// 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(form.NewIssue{}), repo.NewIssuePost)
+
+				m.Group("/:index", func() {
+					m.Post("/title", repo.UpdateIssueTitle)
+					m.Post("/content", repo.UpdateIssueContent)
+					m.Combo("/comments").Post(bindIgnErr(form.CreateComment{}), repo.NewComment)
 				})
-
-				m.Group("/git", func() {
-					m.Get("", repo.SettingsGitHooks)
-					m.Combo("/:name").Get(repo.SettingsGitHooksEdit).
-						Post(repo.SettingsGitHooksEditPost)
-				}, context.GitHookService())
 			})
-
-			m.Group("/keys", func() {
-				m.Combo("").Get(repo.SettingsDeployKeys).
-					Post(bindIgnErr(form.AddSSHKey{}), repo.SettingsDeployKeysPost)
-				m.Post("/delete", repo.DeleteDeployKey)
+			m.Group("/comments/:id", func() {
+				m.Post("", repo.UpdateCommentContent)
+				m.Post("/delete", repo.DeleteComment)
 			})
-
-		}, func(c *context.Context) {
-			c.Data["PageIsSettings"] = true
-		})
-	}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
-
-	m.Post("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
-	m.Group("/:username/:reponame", func() {
-		m.Get("/issues", repo.RetrieveLabels, repo.Issues)
-		m.Get("/issues/:index", repo.ViewIssue)
-		m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
-		m.Get("/milestones", repo.Milestones)
-		m.Get("/doi", route.RequestDOI)
-	}, ignSignIn, context.RepoAssignment(true))
-	m.Group("/:username/:reponame", func() {
-		// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
-		// 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(form.NewIssue{}), repo.NewIssuePost)
-
-			m.Group("/:index", func() {
-				m.Post("/title", repo.UpdateIssueTitle)
-				m.Post("/content", repo.UpdateIssueContent)
-				m.Combo("/comments").Post(bindIgnErr(form.CreateComment{}), repo.NewComment)
+		}, reqSignIn, context.RepoAssignment(true))
+		m.Group("/:username/:reponame", func() {
+			m.Group("/wiki", func() {
+				m.Get("/?:page", repo.Wiki)
+				m.Get("/_pages", repo.WikiPages)
+			}, repo.MustEnableWiki, context.RepoRef())
+		}, ignSignIn, context.RepoAssignment(false, true))
+
+		m.Group("/:username/:reponame", func() {
+			// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
+			// So they can apply their own enable/disable logic on routers.
+			m.Group("/issues", func() {
+				m.Group("/:index", func() {
+					m.Post("/label", repo.UpdateIssueLabel)
+					m.Post("/milestone", repo.UpdateIssueMilestone)
+					m.Post("/assignee", repo.UpdateIssueAssignee)
+				}, reqRepoWriter)
+			})
+			m.Group("/labels", func() {
+				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(form.InitializeLabels{}), repo.InitializeLabels)
+			}, reqRepoWriter, context.RepoRef())
+			m.Group("/milestones", func() {
+				m.Combo("/new").Get(repo.NewMilestone).
+					Post(bindIgnErr(form.CreateMilestone{}), repo.NewMilestonePost)
+				m.Get("/:id/edit", repo.EditMilestone)
+				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(form.NewRelease{}), repo.NewReleasePost)
+				m.Post("/delete", repo.DeleteRelease)
+				m.Get("/edit/*", repo.EditRelease)
+				m.Post("/edit/*", bindIgnErr(form.EditRelease{}), repo.EditReleasePost)
+			}, repo.MustBeNotBare, reqRepoWriter, func(c *context.Context) {
+				c.Data["PageIsViewFiles"] = true
 			})
-		})
-		m.Group("/comments/:id", func() {
-			m.Post("", repo.UpdateCommentContent)
-			m.Post("/delete", repo.DeleteComment)
-		})
-	}, reqSignIn, context.RepoAssignment(true))
-	m.Group("/:username/:reponame", func() {
-		m.Group("/wiki", func() {
-			m.Get("/?:page", repo.Wiki)
-			m.Get("/_pages", repo.WikiPages)
-		}, repo.MustEnableWiki, context.RepoRef())
-	}, ignSignIn, context.RepoAssignment(false, true))
 
-	m.Group("/:username/:reponame", func() {
-		// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
-		// So they can apply their own enable/disable logic on routers.
-		m.Group("/issues", func() {
-			m.Group("/:index", func() {
-				m.Post("/label", repo.UpdateIssueLabel)
-				m.Post("/milestone", repo.UpdateIssueMilestone)
-				m.Post("/assignee", repo.UpdateIssueAssignee)
-			}, reqRepoWriter)
-		})
-		m.Group("/labels", func() {
-			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(form.InitializeLabels{}), repo.InitializeLabels)
-		}, reqRepoWriter, context.RepoRef())
-		m.Group("/milestones", func() {
-			m.Combo("/new").Get(repo.NewMilestone).
-				Post(bindIgnErr(form.CreateMilestone{}), repo.NewMilestonePost)
-			m.Get("/:id/edit", repo.EditMilestone)
-			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(form.NewRelease{}), repo.NewReleasePost)
-			m.Post("/delete", repo.DeleteRelease)
-			m.Get("/edit/*", repo.EditRelease)
-			m.Post("/edit/*", bindIgnErr(form.EditRelease{}), repo.EditReleasePost)
-		}, repo.MustBeNotBare, reqRepoWriter, func(c *context.Context) {
-			c.Data["PageIsViewFiles"] = true
-		})
+			// FIXME: Should use c.Repo.PullRequest to unify template, currently we have inconsistent URL
+			// for PR in same repository. After select branch on the page, the URL contains redundant head user name.
+			// e.g. /org1/test-repo/compare/master...org1:develop
+			// which should be /org1/test-repo/compare/master...develop
+			m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
+				Post(bindIgnErr(form.NewIssue{}), repo.CompareAndPullRequestPost)
 
-		// FIXME: Should use c.Repo.PullRequest to unify template, currently we have inconsistent URL
-		// for PR in same repository. After select branch on the page, the URL contains redundant head user name.
-		// e.g. /org1/test-repo/compare/master...org1:develop
-		// which should be /org1/test-repo/compare/master...develop
-		m.Combo("/compare/*", repo.MustAllowPulls).Get(repo.CompareAndPullRequest).
-			Post(bindIgnErr(form.NewIssue{}), repo.CompareAndPullRequestPost)
+			// GIN specific code
+			if _, err := conf.Asset("conf/datacite/datacite.yml"); err != nil {
+				log.Fatal("%v", err)
+			}
 
-		if _, err := conf.Asset("conf/datacite/datacite.yml"); err != nil {
-			log.Fatal("%v", err)
-		}
-		m.Group("", func() {
-			m.Combo("/_edit/*").Get(repo.EditFile).
-				Post(bindIgnErr(form.EditRepoFile{}), repo.EditFilePost)
-			m.Combo("/_new/*").Get(repo.NewFile).
-				Post(bindIgnErr(form.EditRepoFile{}), repo.NewFilePost)
-			m.Post("/_preview/*", bindIgnErr(form.EditPreviewDiff{}), repo.DiffPreviewPost)
-			m.Combo("/_delete/*").Get(repo.DeleteFile).
-				Post(bindIgnErr(form.DeleteRepoFile{}), repo.DeleteFilePost)
-			// GIN: Add datacite.yml file through the repo web interface
-
-			m.Combo("/_add/*").Get(repo.CreateDatacite).Post(bindIgnErr(form.EditRepoFile{}), repo.NewFilePost)
 			m.Group("", func() {
-				m.Combo("/_upload/*").Get(repo.UploadFile).
-					Post(bindIgnErr(form.UploadRepoFile{}), repo.UploadFilePost)
-				m.Post("/upload-file", repo.UploadFileToServer)
-				m.Post("/upload-remove", bindIgnErr(form.RemoveUploadFile{}), repo.RemoveUploadFileFromServer)
-			}, func(c *context.Context) {
-				if !conf.Repository.Upload.Enabled {
+				m.Combo("/_edit/*").Get(repo.EditFile).
+					Post(bindIgnErr(form.EditRepoFile{}), repo.EditFilePost)
+				m.Combo("/_new/*").Get(repo.NewFile).
+					Post(bindIgnErr(form.EditRepoFile{}), repo.NewFilePost)
+				m.Post("/_preview/*", bindIgnErr(form.EditPreviewDiff{}), repo.DiffPreviewPost)
+				m.Combo("/_delete/*").Get(repo.DeleteFile).
+					Post(bindIgnErr(form.DeleteRepoFile{}), repo.DeleteFilePost)
+				// GIN specific code: Add datacite.yml file through the repo web interface
+				m.Combo("/_add/*").Get(repo.CreateDatacite).Post(bindIgnErr(form.EditRepoFile{}), repo.NewFilePost)
+
+				m.Group("", func() {
+					m.Combo("/_upload/*").Get(repo.UploadFile).
+						Post(bindIgnErr(form.UploadRepoFile{}), repo.UploadFilePost)
+					m.Post("/upload-file", repo.UploadFileToServer)
+					m.Post("/upload-remove", bindIgnErr(form.RemoveUploadFile{}), repo.RemoveUploadFileFromServer)
+				}, func(c *context.Context) {
+					if !conf.Repository.Upload.Enabled {
+						c.NotFound()
+						return
+					}
+				})
+			}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef(), func(c *context.Context) {
+				if !c.Repo.CanEnableEditor() {
 					c.NotFound()
 					return
 				}
+
+				c.Data["PageIsViewFiles"] = true
 			})
-		}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef(), func(c *context.Context) {
-			if !c.Repo.CanEnableEditor() {
-				c.NotFound()
-				return
-			}
+		}, reqSignIn, context.RepoAssignment())
 
-			c.Data["PageIsViewFiles"] = true
-		})
-	}, reqSignIn, context.RepoAssignment())
+		m.Group("/:username/:reponame", func() {
+			m.Group("", func() {
+				m.Get("/releases", repo.MustBeNotBare, repo.Releases)
+				m.Get("/pulls", repo.RetrieveLabels, repo.Pulls)
+				m.Get("/pulls/:index", repo.ViewPull)
+			}, context.RepoRef())
 
-	m.Group("/:username/:reponame", func() {
-		m.Group("", func() {
-			m.Get("/releases", repo.MustBeNotBare, repo.Releases)
-			m.Get("/pulls", repo.RetrieveLabels, repo.Pulls)
-			m.Get("/pulls/:index", repo.ViewPull)
-		}, context.RepoRef())
-
-		m.Group("/branches", func() {
-			m.Get("", repo.Branches)
-			m.Get("/all", repo.AllBranches)
-			m.Post("/delete/*", reqSignIn, reqRepoWriter, repo.DeleteBranchPost)
-		}, repo.MustBeNotBare, func(c *context.Context) {
-			c.Data["PageIsViewFiles"] = true
-		})
+			m.Group("/branches", func() {
+				m.Get("", repo.Branches)
+				m.Get("/all", repo.AllBranches)
+				m.Post("/delete/*", reqSignIn, reqRepoWriter, repo.DeleteBranchPost)
+			}, repo.MustBeNotBare, func(c *context.Context) {
+				c.Data["PageIsViewFiles"] = true
+			})
 
-		m.Group("/wiki", func() {
-			m.Group("", func() {
-				m.Combo("/_new").Get(repo.NewWiki).
-					Post(bindIgnErr(form.NewWiki{}), repo.NewWikiPost)
-				m.Combo("/:page/_edit").Get(repo.EditWiki).
-					Post(bindIgnErr(form.NewWiki{}), repo.EditWikiPost)
-				m.Post("/:page/delete", repo.DeleteWikiPagePost)
-			}, reqSignIn, reqRepoWriter)
-		}, repo.MustEnableWiki, context.RepoRef())
-
-		m.Get("/archive/*", repo.MustBeNotBare, repo.Download)
-
-		m.Group("/pulls/:index", func() {
-			m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
-			m.Get("/files", context.RepoRef(), repo.ViewPullFiles)
-			m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
-		}, repo.MustAllowPulls)
+			m.Group("/wiki", func() {
+				m.Group("", func() {
+					m.Combo("/_new").Get(repo.NewWiki).
+						Post(bindIgnErr(form.NewWiki{}), repo.NewWikiPost)
+					m.Combo("/:page/_edit").Get(repo.EditWiki).
+						Post(bindIgnErr(form.NewWiki{}), repo.EditWikiPost)
+					m.Post("/:page/delete", repo.DeleteWikiPagePost)
+				}, reqSignIn, reqRepoWriter)
+			}, repo.MustEnableWiki, context.RepoRef())
 
-		m.Group("", func() {
-			m.Get("/src/*", repo.Home)
-			m.Get("/raw/*", repo.SingleDownload)
-			m.Get("/commits/*", repo.RefCommits)
-			m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.Diff)
-			m.Get("/forks", repo.Forks)
-		}, repo.MustBeNotBare, context.RepoRef())
-		m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff)
-
-		m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.MustBeNotBare, context.RepoRef(), repo.CompareDiff)
-	}, ignSignIn, context.RepoAssignment())
-	m.Group("/:username/:reponame", func() {
-		m.Get("/stars", repo.Stars)
-		m.Get("/watchers", repo.Watchers)
-	}, ignSignIn, context.RepoAssignment(), context.RepoRef())
+			m.Get("/archive/*", repo.MustBeNotBare, repo.Download)
 
-	m.Group("/:username/:reponame", func() {
-		// GIN mod: Annex over HTTP
-		m.Get("/config", repo.GitConfig)
-		m.Get("/annex/objects/:hashdira/:hashdirb/:key/:keyfile", repo.AnnexGetKey)
-		m.Head("/annex/objects/:hashdira/:hashdirb/:key/:keyfile", repo.AnnexGetKey)
-	}, ignSignInAndCsrf, context.RepoAssignment())
+			m.Group("/pulls/:index", func() {
+				m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
+				m.Get("/files", context.RepoRef(), repo.ViewPullFiles)
+				m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
+			}, repo.MustAllowPulls)
 
-	m.Group("/:username", func() {
-		m.Get("/:reponame", ignSignIn, context.RepoAssignment(), context.RepoRef(), repo.Home)
+			m.Group("", func() {
+				m.Get("/src/*", repo.Home)
+				m.Get("/raw/*", repo.SingleDownload)
+				m.Get("/commits/*", repo.RefCommits)
+				m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.Diff)
+				m.Get("/forks", repo.Forks)
+			}, repo.MustBeNotBare, context.RepoRef())
+			m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff)
+
+			m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.MustBeNotBare, context.RepoRef(), repo.CompareDiff)
+		}, ignSignIn, context.RepoAssignment())
+		m.Group("/:username/:reponame", func() {
+			m.Get("", context.ServeGoGet(), repo.Home)
+			m.Get("/stars", repo.Stars)
+			m.Get("/watchers", repo.Watchers)
+		}, ignSignIn, context.RepoAssignment(), context.RepoRef())
+
+		// GIN specific code
+		// TODO copy /raw/* group context and move to the end of the file for better code separation
+		m.Group("/:username/:reponame", func() {
+			// GIN mod: Annex over HTTP
+			m.Get("/config", repo.GitConfig)
+			m.Get("/annex/objects/:hashdira/:hashdirb/:key/:keyfile", repo.AnnexGetKey)
+			m.Head("/annex/objects/:hashdira/:hashdirb/:key/:keyfile", repo.AnnexGetKey)
+		}, ignSignIn, context.RepoAssignment())
+		// ***** END: Repository *****
+
+		// **********************
+		// ----- API routes -----
+		// **********************
+
+		// TODO: Without session and CSRF
+		m.Group("/api", func() {
+			apiv1.RegisterRoutes(m)
+		}, ignSignIn)
+	},
+		session.Sessioner(session.Options{
+			Provider:       conf.Session.Provider,
+			ProviderConfig: conf.Session.ProviderConfig,
+			CookieName:     conf.Session.CookieName,
+			CookiePath:     conf.Server.Subpath,
+			Gclifetime:     conf.Session.GCInterval,
+			Maxlifetime:    conf.Session.MaxLifeTime,
+			Secure:         conf.Session.CookieSecure,
+		}),
+		csrf.Csrfer(csrf.Options{
+			Secret:         conf.Security.SecretKey,
+			Header:         "X-CSRF-Token",
+			Cookie:         conf.Session.CSRFCookieName,
+			CookieDomain:   conf.Server.URL.Hostname(),
+			CookiePath:     conf.Server.Subpath,
+			CookieHttpOnly: true,
+			SetCookie:      true,
+			Secure:         conf.Server.URL.Scheme == "https",
+		}),
+		context.Contexter(),
+	)
+
+	// ***************************
+	// ----- HTTP Git routes -----
+	// ***************************
 
-		m.Group("/:reponame", func() {
-			m.Head("/tasks/trigger", repo.TriggerTask)
-		})
-		// Use the regexp to match the repository name
-		// Duplicated route 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(), context.RepoRef(), repo.Home)
-			m.Options("/*", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP)
-			m.Route("/*", "GET,POST", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP)
+	m.Group("/:username/:reponame", func() {
+		m.Get("/tasks/trigger", repo.TriggerTask)
+
+		m.Group("/info/lfs", func() {
+			lfs.RegisterRoutes(m.Router)
 		})
-		m.Options("/:reponame/*", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP)
-		m.Route("/:reponame/*", "GET,POST", ignSignInAndCsrf, repo.HTTPContexter(), repo.HTTP)
+
+		m.Route("/*", "GET,POST,OPTIONS", context.ServeGoGet(), repo.HTTPContexter(), repo.HTTP)
 	})
-	// ***** END: Repository *****
 
-	m.Group("/api", func() {
-		apiv1.RegisterRoutes(m)
-	}, ignSignIn)
+	// ***************************
+	// ----- Internal routes -----
+	// ***************************
 
 	m.Group("/-", func() {
-		if conf.Prometheus.Enabled {
-			m.Get("/metrics", func(c *context.Context) {
-				if !conf.Prometheus.EnableBasicAuth {
-					return
-				}
+		m.Get("/metrics", app.MetricsFilter(), promhttp.Handler()) // "/-/metrics"
 
-				c.RequireBasicAuth(conf.Prometheus.BasicAuthUsername, conf.Prometheus.BasicAuthPassword)
-			}, promhttp.Handler())
-		}
+		m.Group("/api", func() {
+			m.Post("/sanitize_ipynb", app.SanitizeIpynb()) // "/-/api/sanitize_ipynb"
+		})
 	})
 
-	// robots.txt
-	m.Get("/robots.txt", func(c *context.Context) {
+	// **********************
+	// ----- robots.txt -----
+	// **********************
+
+	m.Get("/robots.txt", func(w http.ResponseWriter, r *http.Request) {
 		if conf.HasRobotsTxt {
-			c.ServeFileContent(filepath.Join(conf.CustomDir(), "robots.txt"))
+			http.ServeFile(w, r, filepath.Join(conf.CustomDir(), "robots.txt"))
 		} else {
-			c.NotFound()
+			w.WriteHeader(http.StatusNotFound)
 		}
 	})
 
-	// Not found handler.
 	m.NotFound(route.NotFound)
 
 	// Flag for port number in case first time run conflict.

+ 13 - 4
internal/conf/conf.go

@@ -18,13 +18,13 @@ import (
 	_ "github.com/go-macaron/cache/redis"
 	_ "github.com/go-macaron/session/redis"
 	"github.com/gogs/go-libravatar"
-	"github.com/mcuadros/go-version"
 	"github.com/pkg/errors"
 	"gopkg.in/ini.v1"
 	log "unknwon.dev/clog/v2"
 
 	"github.com/G-Node/gogs/internal/assets/conf"
 	"github.com/G-Node/gogs/internal/osutil"
+	"github.com/G-Node/gogs/internal/semverutil"
 )
 
 func init() {
@@ -60,7 +60,7 @@ var File *ini.File
 //
 // NOTE: The order of loading configuration sections matters as one may depend on another.
 //
-// ⚠️ WARNING: Do not print anything in this function other than wanrings.
+// ⚠️ WARNING: Do not print anything in this function other than warnings.
 func Init(customConf string) error {
 	var err error
 	File, err = ini.LoadSources(ini.LoadOptions{
@@ -156,7 +156,7 @@ func Init(customConf string) error {
 				return errors.Wrap(err, "get OpenSSH version")
 			}
 
-			if IsWindowsRuntime() || version.Compare(sshVersion, "5.1", "<") {
+			if IsWindowsRuntime() || semverutil.Compare(sshVersion, "<", "5.1") {
 				log.Warn(`SSH minimum key size check is forced to be disabled because server is not eligible:
 	1. Windows server
 	2. OpenSSH version is lower than 5.1`)
@@ -294,7 +294,7 @@ func Init(customConf string) error {
 		"StampNano":   time.StampNano,
 	}[Time.Format]
 	if Time.FormatLayout == "" {
-		return fmt.Errorf("unrecognized '[time] FORMAT': %s", Time.Format)
+		Time.FormatLayout = time.RFC3339
 	}
 
 	// ****************************
@@ -359,6 +359,15 @@ func Init(customConf string) error {
 	}
 	I18n.dateLangs = File.Section("i18n.datelang").KeysHash()
 
+	// *************************
+	// ----- LFS settings -----
+	// *************************
+
+	if err = File.Section("lfs").MapTo(&LFS); err != nil {
+		return errors.Wrap(err, "mapping [lfs] section")
+	}
+	LFS.ObjectsPath = ensureAbs(LFS.ObjectsPath)
+
 	handleDeprecated()
 
 	if err = File.Section("cache").MapTo(&Cache); err != nil {

+ 0 - 4
internal/conf/conf_test.go

@@ -37,10 +37,6 @@ func TestMustAsset(t *testing.T) {
 }
 
 func TestInit(t *testing.T) {
-	if IsWindowsRuntime() {
-		return
-	}
-
 	ini.PrettyFormat = false
 	defer func() {
 		MustInit("")

部分文件因为文件数量过多而无法显示