mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-17 00:03:04 -04:00
Compare commits
No commits in common. "8446caa813f676398411d3544cc05a42fd708cd1" and "8eac16de217978c1f7034f8e360f54d8d638e95e" have entirely different histories.
8446caa813
...
8eac16de21
@ -17,35 +17,15 @@ menu:
|
|||||||
|
|
||||||
# Reverse Proxies
|
# Reverse Proxies
|
||||||
|
|
||||||
## General configuration
|
|
||||||
|
|
||||||
1. Set `[server] ROOT_URL = https://git.example.com/` in your `app.ini` file.
|
|
||||||
2. Make the reverse-proxy pass `https://git.example.com/foo` to `http://gitea:3000/foo`.
|
|
||||||
3. Make sure the reverse-proxy does not decode the URI. The request `https://git.example.com/a%2Fb` should be passed as `http://gitea:3000/a%2Fb`.
|
|
||||||
4. Make sure `Host` and `X-Fowarded-Proto` headers are correctly passed to Gitea to make Gitea see the real URL being visited.
|
|
||||||
|
|
||||||
### Use a sub-path
|
|
||||||
|
|
||||||
Usually it's **not recommended** to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases.
|
|
||||||
|
|
||||||
To make Gitea work with a sub-path (eg: `https://common.example.com/gitea/`),
|
|
||||||
there are some extra requirements besides the general configuration above:
|
|
||||||
|
|
||||||
1. Use `[server] ROOT_URL = https://common.example.com/gitea/` in your `app.ini` file.
|
|
||||||
2. Make the reverse-proxy pass `https://common.example.com/gitea/foo` to `http://gitea:3000/foo`.
|
|
||||||
3. The container registry requires a fixed sub-path `/v2` at the root level which must be configured:
|
|
||||||
- Make the reverse-proxy pass `https://common.example.com/v2` to `http://gitea:3000/v2`.
|
|
||||||
- Make sure the URI and headers are also correctly passed (see the general configuration above).
|
|
||||||
|
|
||||||
## Nginx
|
## Nginx
|
||||||
|
|
||||||
If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`.
|
If you want Nginx to serve your Gitea instance, add the following `server` section to the `http` section of `nginx.conf`:
|
||||||
|
|
||||||
Make sure `client_max_body_size` is large enough, otherwise there would be "413 Request Entity Too Large" error when uploading large files.
|
```
|
||||||
|
|
||||||
```nginx
|
|
||||||
server {
|
server {
|
||||||
...
|
listen 80;
|
||||||
|
server_name git.example.com;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
client_max_body_size 512M;
|
client_max_body_size 512M;
|
||||||
proxy_pass http://localhost:3000;
|
proxy_pass http://localhost:3000;
|
||||||
@ -59,35 +39,37 @@ server {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Resolving Error: 413 Request Entity Too Large
|
||||||
|
|
||||||
|
This error indicates nginx is configured to restrict the file upload size,
|
||||||
|
it affects attachment uploading, form posting, package uploading and LFS pushing, etc.
|
||||||
|
You can fine tune the `client_max_body_size` option according to [nginx document](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_max_body_size).
|
||||||
|
|
||||||
## Nginx with a sub-path
|
## Nginx with a sub-path
|
||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name,
|
In case you already have a site, and you want Gitea to share the domain name, you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section inside the `http` section of `nginx.conf`:
|
||||||
you can setup Nginx to serve Gitea under a sub-path by adding the following `server` section
|
|
||||||
into the `http` section of `nginx.conf`:
|
|
||||||
|
|
||||||
```nginx
|
```
|
||||||
server {
|
server {
|
||||||
...
|
listen 80;
|
||||||
location ~ ^/(gitea|v2)($|/) {
|
server_name git.example.com;
|
||||||
|
|
||||||
|
# Note: Trailing slash
|
||||||
|
location /gitea/ {
|
||||||
client_max_body_size 512M;
|
client_max_body_size 512M;
|
||||||
|
|
||||||
# make nginx use unescaped URI, keep "%2F" as-is, remove the "/gitea" sub-path prefix, pass "/v2" as-is.
|
# make nginx use unescaped URI, keep "%2F" as is
|
||||||
rewrite ^ $request_uri;
|
rewrite ^ $request_uri;
|
||||||
rewrite ^(/gitea)?(/.*) $2 break;
|
rewrite ^/gitea(/.*) $1 break;
|
||||||
proxy_pass http://127.0.0.1:3000$uri;
|
proxy_pass http://127.0.0.1:3000$uri;
|
||||||
|
|
||||||
# other common HTTP headers, see the "Nginx" config section above
|
# other common HTTP headers, see the "Nginx" config section above
|
||||||
proxy_set_header Connection $http_connection;
|
proxy_set_header ...
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/gitea/` correctly in your configuration.
|
Then you **MUST** set something like `[server] ROOT_URL = http://git.example.com/git/` correctly in your configuration.
|
||||||
|
|
||||||
## Nginx and serve static resources directly
|
## Nginx and serve static resources directly
|
||||||
|
|
||||||
@ -111,7 +93,7 @@ or use a cdn for the static files.
|
|||||||
|
|
||||||
Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration.
|
Set `[server] STATIC_URL_PREFIX = /_/static` in your configuration.
|
||||||
|
|
||||||
```nginx
|
```apacheconf
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name git.example.com;
|
server_name git.example.com;
|
||||||
@ -130,7 +112,7 @@ server {
|
|||||||
|
|
||||||
Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration.
|
Set `[server] STATIC_URL_PREFIX = http://cdn.example.com/gitea` in your configuration.
|
||||||
|
|
||||||
```nginx
|
```apacheconf
|
||||||
# application server running Gitea
|
# application server running Gitea
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
@ -142,7 +124,7 @@ server {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```nginx
|
```apacheconf
|
||||||
# static content delivery server
|
# static content delivery server
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
@ -169,8 +151,6 @@ If you want Apache HTTPD to serve your Gitea instance, you can add the following
|
|||||||
ProxyRequests off
|
ProxyRequests off
|
||||||
AllowEncodedSlashes NoDecode
|
AllowEncodedSlashes NoDecode
|
||||||
ProxyPass / http://localhost:3000/ nocanon
|
ProxyPass / http://localhost:3000/ nocanon
|
||||||
ProxyPreserveHost On
|
|
||||||
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
|
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -192,8 +172,6 @@ In case you already have a site, and you want Gitea to share the domain name, yo
|
|||||||
AllowEncodedSlashes NoDecode
|
AllowEncodedSlashes NoDecode
|
||||||
# Note: no trailing slash after either /git or port
|
# Note: no trailing slash after either /git or port
|
||||||
ProxyPass /git http://localhost:3000 nocanon
|
ProxyPass /git http://localhost:3000 nocanon
|
||||||
ProxyPreserveHost On
|
|
||||||
RequestHeader set "X-Forwarded-Proto" expr=%{REQUEST_SCHEME}
|
|
||||||
</VirtualHost>
|
</VirtualHost>
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -205,7 +183,7 @@ Note: The following Apache HTTPD mods must be enabled: `proxy`, `proxy_http`.
|
|||||||
|
|
||||||
If you want Caddy to serve your Gitea instance, you can add the following server block to your Caddyfile:
|
If you want Caddy to serve your Gitea instance, you can add the following server block to your Caddyfile:
|
||||||
|
|
||||||
```
|
```apacheconf
|
||||||
git.example.com {
|
git.example.com {
|
||||||
reverse_proxy localhost:3000
|
reverse_proxy localhost:3000
|
||||||
}
|
}
|
||||||
@ -215,7 +193,7 @@ git.example.com {
|
|||||||
|
|
||||||
In case you already have a site, and you want Gitea to share the domain name, you can setup Caddy to serve Gitea under a sub-path by adding the following to your server block in your Caddyfile:
|
In case you already have a site, and you want Gitea to share the domain name, you can setup Caddy to serve Gitea under a sub-path by adding the following to your server block in your Caddyfile:
|
||||||
|
|
||||||
```
|
```apacheconf
|
||||||
git.example.com {
|
git.example.com {
|
||||||
route /git/* {
|
route /git/* {
|
||||||
uri strip_prefix /git
|
uri strip_prefix /git
|
||||||
@ -393,3 +371,19 @@ gitea:
|
|||||||
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
This config assumes that you are handling HTTPS on the traefik side and using HTTP between Gitea and traefik.
|
||||||
|
|
||||||
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
Then you **MUST** set something like `[server] ROOT_URL = http://example.com/gitea/` correctly in your configuration.
|
||||||
|
|
||||||
|
## General sub-path configuration
|
||||||
|
|
||||||
|
Usually it's not recommended to put Gitea in a sub-path, it's not widely used and may have some issues in rare cases.
|
||||||
|
|
||||||
|
If you really need to do so, to make Gitea works with sub-path (eg: `http://example.com/gitea/`), here are the requirements:
|
||||||
|
|
||||||
|
1. Set `[server] ROOT_URL = http://example.com/gitea/` in your `app.ini` file.
|
||||||
|
2. Make the reverse-proxy pass `http://example.com/gitea/foo` to `http://gitea-server:3000/foo`.
|
||||||
|
3. Make sure the reverse-proxy not decode the URI, the request `http://example.com/gitea/a%2Fb` should be passed as `http://gitea-server:3000/a%2Fb`.
|
||||||
|
|
||||||
|
## Docker / Container Registry
|
||||||
|
|
||||||
|
The container registry uses a fixed sub-path `/v2` which can't be changed.
|
||||||
|
Even if you deploy Gitea with a different sub-path, `/v2` will be used by the `docker` client.
|
||||||
|
Therefore you may need to add an additional route to your reverse proxy configuration.
|
||||||
|
@ -32,7 +32,7 @@ func IsRelativeURL(s string) bool {
|
|||||||
return err == nil && urlIsRelative(s, u)
|
return err == nil && urlIsRelative(s, u)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRequestScheme(req *http.Request) string {
|
func guessRequestScheme(req *http.Request, def string) string {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto
|
||||||
if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
|
if s := req.Header.Get("X-Forwarded-Proto"); s != "" {
|
||||||
return s
|
return s
|
||||||
@ -49,10 +49,10 @@ func getRequestScheme(req *http.Request) string {
|
|||||||
if s := req.Header.Get("X-Forwarded-Ssl"); s != "" {
|
if s := req.Header.Get("X-Forwarded-Ssl"); s != "" {
|
||||||
return util.Iif(s == "on", "https", "http")
|
return util.Iif(s == "on", "https", "http")
|
||||||
}
|
}
|
||||||
return ""
|
return def
|
||||||
}
|
}
|
||||||
|
|
||||||
func getForwardedHost(req *http.Request) string {
|
func guessForwardedHost(req *http.Request) string {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
|
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host
|
||||||
return req.Header.Get("X-Forwarded-Host")
|
return req.Header.Get("X-Forwarded-Host")
|
||||||
}
|
}
|
||||||
@ -63,25 +63,16 @@ func GuessCurrentAppURL(ctx context.Context) string {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return setting.AppURL
|
return setting.AppURL
|
||||||
}
|
}
|
||||||
// If no scheme provided by reverse proxy, then do not guess the AppURL, use the configured one.
|
if host := guessForwardedHost(req); host != "" {
|
||||||
// At the moment, if site admin doesn't configure the proxy headers correctly, then Gitea would guess wrong.
|
// if it is behind a reverse proxy, use "https" as default scheme in case the site admin forgets to set the correct forwarded-protocol headers
|
||||||
// There are some cases:
|
return guessRequestScheme(req, "https") + "://" + host + setting.AppSubURL + "/"
|
||||||
// 1. The reverse proxy is configured correctly, it passes "X-Forwarded-Proto/Host" headers. Perfect, Gitea can handle it correctly.
|
} else if req.Host != "" {
|
||||||
// 2. The reverse proxy is not configured correctly, doesn't pass "X-Forwarded-Proto/Host" headers, eg: only one "proxy_pass http://gitea:3000" in Nginx.
|
// if it is not behind a reverse proxy, use the scheme from config options, meanwhile use "https" as much as possible
|
||||||
// 3. There is no reverse proxy.
|
defaultScheme := util.Iif(setting.Protocol == "http", "http", "https")
|
||||||
// Without an extra config option, Gitea is impossible to distinguish between case 2 and case 3,
|
return guessRequestScheme(req, defaultScheme) + "://" + req.Host + setting.AppSubURL + "/"
|
||||||
// then case 2 would result in wrong guess like guessed AppURL becomes "http://gitea:3000/", which is not accessible by end users.
|
}
|
||||||
// So in the future maybe it should introduce a new config option, to let site admin decide how to guess the AppURL.
|
|
||||||
reqScheme := getRequestScheme(req)
|
|
||||||
if reqScheme == "" {
|
|
||||||
return setting.AppURL
|
return setting.AppURL
|
||||||
}
|
}
|
||||||
reqHost := getForwardedHost(req)
|
|
||||||
if reqHost == "" {
|
|
||||||
reqHost = req.Host
|
|
||||||
}
|
|
||||||
return reqScheme + "://" + reqHost + setting.AppSubURL + "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
func MakeAbsoluteURL(ctx context.Context, s string) string {
|
func MakeAbsoluteURL(ctx context.Context, s string) string {
|
||||||
if IsRelativeURL(s) {
|
if IsRelativeURL(s) {
|
||||||
|
@ -41,19 +41,19 @@ func TestIsRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
func TestMakeAbsoluteURL(t *testing.T) {
|
func TestMakeAbsoluteURL(t *testing.T) {
|
||||||
defer test.MockVariableValue(&setting.Protocol, "http")()
|
defer test.MockVariableValue(&setting.Protocol, "http")()
|
||||||
defer test.MockVariableValue(&setting.AppURL, "http://cfg-host/sub/")()
|
defer test.MockVariableValue(&setting.AppURL, "http://the-host/sub/")()
|
||||||
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
assert.Equal(t, "http://cfg-host/sub/", MakeAbsoluteURL(ctx, ""))
|
assert.Equal(t, "http://the-host/sub/", MakeAbsoluteURL(ctx, ""))
|
||||||
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "foo"))
|
assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "foo"))
|
||||||
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
assert.Equal(t, "http://the-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo"))
|
assert.Equal(t, "http://other/foo", MakeAbsoluteURL(ctx, "http://other/foo"))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
Host: "user-host",
|
Host: "user-host",
|
||||||
})
|
})
|
||||||
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
assert.Equal(t, "http://user-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
Host: "user-host",
|
Host: "user-host",
|
||||||
@ -61,7 +61,7 @@ func TestMakeAbsoluteURL(t *testing.T) {
|
|||||||
"X-Forwarded-Host": {"forwarded-host"},
|
"X-Forwarded-Host": {"forwarded-host"},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
assert.Equal(t, "http://cfg-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
assert.Equal(t, "https://forwarded-host/sub/foo", MakeAbsoluteURL(ctx, "/foo"))
|
||||||
|
|
||||||
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
ctx = context.WithValue(ctx, RequestContextKey, &http.Request{
|
||||||
Host: "user-host",
|
Host: "user-host",
|
||||||
|
@ -116,8 +116,6 @@ func apiErrorDefined(ctx *context.Context, err *namedError) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func apiUnauthorizedError(ctx *context.Context) {
|
func apiUnauthorizedError(ctx *context.Context) {
|
||||||
// TODO: it doesn't seem quite right but it doesn't really cause problem at the moment.
|
|
||||||
// container registry requires that the "/v2" must be in the root, so the sub-path in AppURL should be removed, ideally.
|
|
||||||
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`)
|
ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+httplib.GuessCurrentAppURL(ctx)+`v2/token",service="container_registry",scope="*"`)
|
||||||
apiErrorDefined(ctx, errUnauthorized)
|
apiErrorDefined(ctx, errUnauthorized)
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,6 @@ func UpdateAvatar(ctx *context.APIContext) {
|
|||||||
err = user_service.UploadAvatar(ctx, ctx.Org.Organization.AsUser(), content)
|
err = user_service.UploadAvatar(ctx, ctx.Org.Organization.AsUser(), content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
@ -73,7 +72,6 @@ func DeleteAvatar(ctx *context.APIContext) {
|
|||||||
err := user_service.DeleteAvatar(ctx, ctx.Org.Organization.AsUser())
|
err := user_service.DeleteAvatar(ctx, ctx.Org.Organization.AsUser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
|
@ -175,7 +175,7 @@ func Migrate(ctx *context.APIContext) {
|
|||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
OriginalURL: form.CloneAddr,
|
OriginalURL: form.CloneAddr,
|
||||||
GitServiceType: gitServiceType,
|
GitServiceType: gitServiceType,
|
||||||
IsPrivate: opts.Private || setting.Repository.ForcePrivate,
|
IsPrivate: opts.Private,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
|
@ -252,7 +252,7 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre
|
|||||||
Gitignores: opt.Gitignores,
|
Gitignores: opt.Gitignores,
|
||||||
License: opt.License,
|
License: opt.License,
|
||||||
Readme: opt.Readme,
|
Readme: opt.Readme,
|
||||||
IsPrivate: opt.Private || setting.Repository.ForcePrivate,
|
IsPrivate: opt.Private,
|
||||||
AutoInit: opt.AutoInit,
|
AutoInit: opt.AutoInit,
|
||||||
DefaultBranch: opt.DefaultBranch,
|
DefaultBranch: opt.DefaultBranch,
|
||||||
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
TrustModel: repo_model.ToTrustModel(opt.TrustModel),
|
||||||
@ -364,7 +364,7 @@ func Generate(ctx *context.APIContext) {
|
|||||||
Name: form.Name,
|
Name: form.Name,
|
||||||
DefaultBranch: form.DefaultBranch,
|
DefaultBranch: form.DefaultBranch,
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
Private: form.Private || setting.Repository.ForcePrivate,
|
Private: form.Private,
|
||||||
GitContent: form.GitContent,
|
GitContent: form.GitContent,
|
||||||
Topics: form.Topics,
|
Topics: form.Topics,
|
||||||
GitHooks: form.GitHooks,
|
GitHooks: form.GitHooks,
|
||||||
|
@ -39,7 +39,6 @@ func UpdateAvatar(ctx *context.APIContext) {
|
|||||||
err = user_service.UploadAvatar(ctx, ctx.Doer, content)
|
err = user_service.UploadAvatar(ctx, ctx.Doer, content)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "UploadAvatar", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
@ -58,7 +57,6 @@ func DeleteAvatar(ctx *context.APIContext) {
|
|||||||
err := user_service.DeleteAvatar(ctx, ctx.Doer)
|
err := user_service.DeleteAvatar(ctx, ctx.Doer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
ctx.Error(http.StatusInternalServerError, "DeleteAvatar", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Status(http.StatusNoContent)
|
ctx.Status(http.StatusNoContent)
|
||||||
|
@ -87,6 +87,6 @@ func TestSelfCheckPost(t *testing.T) {
|
|||||||
err := json.Unmarshal(resp.Body.Bytes(), &data)
|
err := json.Unmarshal(resp.Body.Bytes(), &data)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, []string{
|
assert.Equal(t, []string{
|
||||||
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://config/sub/"),
|
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"),
|
||||||
}, data.Problems)
|
}, data.Problems)
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,7 @@ func CreatePost(ctx *context.Context) {
|
|||||||
opts := repo_service.GenerateRepoOptions{
|
opts := repo_service.GenerateRepoOptions{
|
||||||
Name: form.RepoName,
|
Name: form.RepoName,
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
Private: form.Private || setting.Repository.ForcePrivate,
|
Private: form.Private,
|
||||||
GitContent: form.GitContent,
|
GitContent: form.GitContent,
|
||||||
Topics: form.Topics,
|
Topics: form.Topics,
|
||||||
GitHooks: form.GitHooks,
|
GitHooks: form.GitHooks,
|
||||||
|
@ -107,7 +107,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
|
|||||||
Description: repo.Description,
|
Description: repo.Description,
|
||||||
OriginalURL: repo.OriginalURL,
|
OriginalURL: repo.OriginalURL,
|
||||||
GitServiceType: opts.GitServiceType,
|
GitServiceType: opts.GitServiceType,
|
||||||
IsPrivate: opts.Private || setting.Repository.ForcePrivate,
|
IsPrivate: opts.Private,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
|
@ -85,7 +85,7 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN
|
|||||||
|
|
||||||
repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{
|
repo, err := CreateRepository(ctx, authUser, owner, CreateRepoOptions{
|
||||||
Name: repoName,
|
Name: repoName,
|
||||||
IsPrivate: setting.Repository.DefaultPushCreatePrivate || setting.Repository.ForcePrivate,
|
IsPrivate: setting.Repository.DefaultPushCreatePrivate,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -107,7 +107,7 @@ func CreateMigrateTask(ctx context.Context, doer, u *user_model.User, opts base.
|
|||||||
Description: opts.Description,
|
Description: opts.Description,
|
||||||
OriginalURL: opts.OriginalURL,
|
OriginalURL: opts.OriginalURL,
|
||||||
GitServiceType: opts.GitServiceType,
|
GitServiceType: opts.GitServiceType,
|
||||||
IsPrivate: opts.Private || setting.Repository.ForcePrivate,
|
IsPrivate: opts.Private,
|
||||||
IsMirror: opts.Mirror,
|
IsMirror: opts.Mirror,
|
||||||
Status: repo_model.RepositoryBeingMigrated,
|
Status: repo_model.RepositoryBeingMigrated,
|
||||||
})
|
})
|
||||||
|
@ -5,10 +5,8 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
@ -50,24 +48,16 @@ func UploadAvatar(ctx context.Context, u *user_model.User, data []byte) error {
|
|||||||
func DeleteAvatar(ctx context.Context, u *user_model.User) error {
|
func DeleteAvatar(ctx context.Context, u *user_model.User) error {
|
||||||
aPath := u.CustomAvatarRelativePath()
|
aPath := u.CustomAvatarRelativePath()
|
||||||
log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
|
log.Trace("DeleteAvatar[%d]: %s", u.ID, aPath)
|
||||||
|
if len(u.Avatar) > 0 {
|
||||||
|
if err := storage.Avatars.Delete(aPath); err != nil {
|
||||||
|
return fmt.Errorf("Failed to remove %s: %w", aPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return db.WithTx(ctx, func(ctx context.Context) error {
|
|
||||||
hasAvatar := len(u.Avatar) > 0
|
|
||||||
u.UseCustomAvatar = false
|
u.UseCustomAvatar = false
|
||||||
u.Avatar = ""
|
u.Avatar = ""
|
||||||
if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
|
if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar, use_custom_avatar").Update(u); err != nil {
|
||||||
return fmt.Errorf("DeleteAvatar: %w", err)
|
return fmt.Errorf("DeleteAvatar: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if hasAvatar {
|
|
||||||
if err := storage.Avatars.Delete(aPath); err != nil {
|
|
||||||
if !errors.Is(err, os.ErrNotExist) {
|
|
||||||
return fmt.Errorf("failed to remove %s: %w", aPath, err)
|
|
||||||
}
|
|
||||||
log.Warn("Deleting avatar %s but it doesn't exist", aPath)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -105,7 +105,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -101,7 +101,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -100,7 +100,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}} checked{{end}}>
|
||||||
|
@ -89,7 +89,7 @@
|
|||||||
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
|
||||||
<div class="ui checkbox">
|
<div class="ui checkbox">
|
||||||
{{if .IsForcedPrivate}}
|
{{if .IsForcedPrivate}}
|
||||||
<input name="private" type="checkbox" checked disabled>
|
<input name="private" type="checkbox" checked readonly>
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper_forced"}}</label>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .private}}checked{{end}}>
|
||||||
|
@ -30,8 +30,7 @@
|
|||||||
{{if .IsAdmin}}
|
{{if .IsAdmin}}
|
||||||
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
|
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
|
||||||
{{else}}
|
{{else}}
|
||||||
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} disabled{{end}}>
|
<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}{{if and $.ForcePrivate .Repository.IsPrivate}} readonly{{end}}>
|
||||||
{{if and .Repository.IsPrivate $.ForcePrivate}}<input type="hidden" name="private" value="{{.Repository.IsPrivate}}">{{end}}
|
|
||||||
{{end}}
|
{{end}}
|
||||||
<label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
|
<label>{{ctx.Locale.Tr "repo.visibility_helper"}} {{if .Repository.NumForks}}<span class="text red">{{ctx.Locale.Tr "repo.visibility_fork_helper"}}</span>{{end}}</label>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user