Skip to content

Commit d0f432f

Browse files
committed
fix
1 parent 67c1a07 commit d0f432f

File tree

11 files changed

+93
-19
lines changed

11 files changed

+93
-19
lines changed

options/locale/locale_en-US.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive = Database is using a collation %
33203320
self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems.
33213321
self_check.database_fix_mysql = For MySQL/MariaDB users, you could use the "gitea doctor convert" command to fix the collation problems, or you could also fix the problem by "ALTER ... COLLATE ..." SQLs manually.
33223322
self_check.database_fix_mssql = For MSSQL users, you could only fix the problem by "ALTER ... COLLATE ..." SQLs manually at the moment.
3323+
self_check.location_origin_mismatch = Current URL (%[1]s) doesn't match the URL seen by Gitea (%[2]s). If you are using a reverse proxy, please make sure the "Host" and "X-Forwarded-Proto" headers are set correctly.
33233324

33243325
[action]
33253326
create_repo = created repository <a href="%s">%s</a>

routers/web/admin/admin.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import (
99
"net/http"
1010
"runtime"
1111
"sort"
12+
"strings"
1213
"time"
1314

1415
activities_model "code.gitea.io/gitea/models/activities"
1516
"code.gitea.io/gitea/models/db"
1617
"code.gitea.io/gitea/modules/base"
1718
"code.gitea.io/gitea/modules/graceful"
19+
"code.gitea.io/gitea/modules/httplib"
1820
"code.gitea.io/gitea/modules/json"
1921
"code.gitea.io/gitea/modules/log"
2022
"code.gitea.io/gitea/modules/setting"
@@ -223,6 +225,16 @@ func SelfCheck(ctx *context.Context) {
223225
ctx.HTML(http.StatusOK, tplSelfCheck)
224226
}
225227

228+
func SelfCheckPost(ctx *context.Context) {
229+
var problems []string
230+
frontendAppURL := ctx.FormString("location_origin") + setting.AppSubURL + "/"
231+
ctxAppURL := httplib.GuessCurrentAppURL(ctx)
232+
if !strings.HasPrefix(ctxAppURL, frontendAppURL) {
233+
problems = append(problems, ctx.Locale.TrString("admin.self_check.location_origin_mismatch", frontendAppURL, ctxAppURL))
234+
}
235+
ctx.JSON(http.StatusOK, map[string]any{"problems": problems})
236+
}
237+
226238
func CronTasks(ctx *context.Context) {
227239
ctx.Data["Title"] = ctx.Tr("admin.monitor.cron")
228240
ctx.Data["PageIsAdminMonitorCron"] = true

routers/web/admin/admin_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,14 @@
44
package admin
55

66
import (
7+
"net/http"
78
"testing"
89

10+
"code.gitea.io/gitea/modules/json"
11+
"code.gitea.io/gitea/modules/setting"
12+
"code.gitea.io/gitea/modules/test"
13+
"code.gitea.io/gitea/services/contexttest"
14+
915
"github.com/stretchr/testify/assert"
1016
)
1117

@@ -66,3 +72,21 @@ func TestShadowPassword(t *testing.T) {
6672
assert.EqualValues(t, k.Result, shadowPassword(k.Provider, k.CfgItem))
6773
}
6874
}
75+
76+
func TestSelfCheckPost(t *testing.T) {
77+
defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")()
78+
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
79+
80+
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
81+
SelfCheckPost(ctx)
82+
assert.EqualValues(t, http.StatusOK, resp.Code)
83+
84+
data := struct {
85+
Problems []string `json:"problems"`
86+
}{}
87+
err := json.Unmarshal(resp.Body.Bytes(), &data)
88+
assert.NoError(t, err)
89+
assert.Equal(t, []string{
90+
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"),
91+
}, data.Problems)
92+
}

routers/web/web.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ func registerRoutes(m *web.Route) {
685685
m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
686686

687687
m.Get("/self_check", admin.SelfCheck)
688+
m.Post("/self_check", admin.SelfCheckPost)
688689

689690
m.Group("/config", func() {
690691
m.Get("", admin.Config)

services/context/base.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,8 @@ func NewBaseContext(resp http.ResponseWriter, req *http.Request) (b *Base, close
309309
Locale: middleware.Locale(resp, req),
310310
Data: middleware.GetContextData(req.Context()),
311311
}
312-
b.AppendContextValue(translation.ContextKey, b.Locale)
313312
b.Req = b.Req.WithContext(b)
313+
b.AppendContextValue(translation.ContextKey, b.Locale)
314+
b.AppendContextValue(httplib.RequestContextKey, b.Req)
314315
return b, b.cleanUp
315316
}

services/contexttest/context_tests.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ func mockRequest(t *testing.T, reqPath string) *http.Request {
3939
}
4040
requestURL, err := url.Parse(path)
4141
assert.NoError(t, err)
42-
req := &http.Request{Method: method, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
42+
req := &http.Request{Method: method, Host: requestURL.Host, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
4343
req = req.WithContext(middleware.WithContextData(req.Context()))
4444
return req
4545
}

templates/admin/self_check.tmpl

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
1-
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}
1+
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin")}}
22

33
<div class="admin-setting-content">
44
<h4 class="ui top attached header">
55
{{ctx.Locale.Tr "admin.self_check"}}
66
</h4>
77

88
{{if .StartupProblems}}
9-
<div class="ui attached segment">
9+
<div class="ui attached segment self-check-problem">
1010
<div class="ui warning message">
1111
<div>{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}</div>
1212
<ul class="tw-w-full">{{range .StartupProblems}}<li>{{.}}</li>{{end}}</ul>
1313
</div>
1414
</div>
1515
{{end}}
1616

17+
<div class="ui attached segment tw-hidden self-check-problem self-check-by-frontend"></div>
18+
1719
{{if .DatabaseCheckHasProblems}}
18-
<div class="ui attached segment">
20+
<div class="ui attached segment self-check-problem">
1921
{{if .DatabaseType.IsMySQL}}
2022
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div>
2123
{{else if .DatabaseType.IsMSSQL}}
@@ -29,22 +31,22 @@
2931
{{end}}
3032
{{if .DatabaseCheckInconsistentCollationColumns}}
3133
<div class="ui red message">
32-
{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}
33-
<ul class="tw-w-full">
34-
{{range .DatabaseCheckInconsistentCollationColumns}}
35-
<li>{{.}}</li>
36-
{{end}}
37-
</ul>
34+
<details>
35+
<summary>{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}</summary>
36+
<ul class="tw-w-full">
37+
{{range .DatabaseCheckInconsistentCollationColumns}}
38+
<li>{{.}}</li>
39+
{{end}}
40+
</ul>
41+
</details>
3842
</div>
3943
{{end}}
4044
</div>
4145
{{end}}
42-
43-
{{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}}
44-
<div class="ui attached segment">
46+
{{/* only shown when there is no visible "self-check-problem" */}}
47+
<div class="ui attached segment tw-hidden self-check-no-problem">
4548
{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}
4649
</div>
47-
{{end}}
4850
</div>
4951

5052
{{template "admin/layout_footer" .}}

web_src/js/bootstrap.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,20 @@ function shouldIgnoreError(err) {
1616
return false;
1717
}
1818

19-
export function showGlobalErrorMessage(msg) {
19+
export function showGlobalErrorMessage(msg, msgType = 'error') {
2020
const msgContainer = document.querySelector('.page-content') ?? document.body;
2121
const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages
2222
let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`);
2323
if (!msgDiv) {
2424
const el = document.createElement('div');
25-
el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`;
25+
el.innerHTML = `<div class="ui container js-global-error tw-my-4"><div class="ui ${msgType} message tw-text-center tw-whitespace-pre-line"></div></div>`;
2626
msgDiv = el.childNodes[0];
2727
}
2828
// merge duplicated messages into "the message (count)" format
2929
const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1;
3030
msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact);
3131
msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString());
32-
msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
32+
msgDiv.querySelector('.ui.message').textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
3333
msgContainer.prepend(msgDiv);
3434
}
3535

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import {toggleElem} from '../../utils/dom.js';
2+
import {POST} from '../../modules/fetch.js';
3+
4+
const {appSubUrl} = window.config;
5+
6+
export async function initAdminSelfCheck() {
7+
const elCheckByFrontend = document.querySelector('.page-content.admin .self-check-by-frontend');
8+
if (!elCheckByFrontend) return;
9+
10+
const elContent = document.querySelector('.page-content.admin .admin-setting-content');
11+
12+
// send frontend self-check request
13+
const resp = await POST(`${appSubUrl}/admin/self_check`, {
14+
data: new URLSearchParams({
15+
location_origin: window.location.origin,
16+
now: Date.now(), // TODO: check time difference between server and client
17+
}),
18+
});
19+
const json = await resp.json();
20+
toggleElem(elCheckByFrontend, Boolean(json.problems?.length));
21+
for (const problem of json.problems ?? []) {
22+
const elProblem = document.createElement('div');
23+
elProblem.classList.add('ui', 'warning', 'message');
24+
elProblem.textContent = problem;
25+
elCheckByFrontend.append(elProblem);
26+
}
27+
28+
// only show the "no problem" if there is no visible "self-check-problem"
29+
const hasProblem = Boolean(elContent.querySelectorAll('.self-check-problem:not(.tw-hidden)').length);
30+
toggleElem(elContent.querySelector('.self-check-no-problem'), !hasProblem);
31+
}

web_src/js/features/common-global.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,5 +451,5 @@ export function checkAppUrl() {
451451
return;
452452
}
453453
showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting.
454-
Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`);
454+
Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`, 'warning');
455455
}

web_src/js/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js'
8787
import {initDirAuto} from './modules/dirauto.js';
8888
import {initRepositorySearch} from './features/repo-search.js';
8989
import {initColorPickers} from './features/colorpicker.js';
90+
import {initAdminSelfCheck} from './features/admin/selfcheck.js';
9091

9192
// Init Gitea's Fomantic settings
9293
initGiteaFomantic();
@@ -132,6 +133,7 @@ onDomReady(() => {
132133
initAdminEmails();
133134
initAdminUserListSearchForm();
134135
initAdminConfigs();
136+
initAdminSelfCheck();
135137

136138
initDashboardRepoList();
137139

0 commit comments

Comments
 (0)