mirror of https://github.com/go-gitea/gitea.git
Compare commits
6 Commits
a1fb1deb62
...
d22dc8ac55
Author | SHA1 | Date |
---|---|---|
wxiaoguang | d22dc8ac55 | |
yp05327 | e94723f2de | |
wxiaoguang | ed0fc2729e | |
wxiaoguang | 45022537e5 | |
wxiaoguang | fa64d1be14 | |
wxiaoguang | d0f432f11f |
|
@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive = Database is using a collation %
|
|||
self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems.
|
||||
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.
|
||||
self_check.database_fix_mssql = For MSSQL users, you could only fix the problem by "ALTER ... COLLATE ..." SQLs manually at the moment.
|
||||
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.
|
||||
|
||||
[action]
|
||||
create_repo = created repository <a href="%s">%s</a>
|
||||
|
|
|
@ -9,12 +9,14 @@ import (
|
|||
"net/http"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -223,6 +225,16 @@ func SelfCheck(ctx *context.Context) {
|
|||
ctx.HTML(http.StatusOK, tplSelfCheck)
|
||||
}
|
||||
|
||||
func SelfCheckPost(ctx *context.Context) {
|
||||
var problems []string
|
||||
frontendAppURL := ctx.FormString("location_origin") + setting.AppSubURL + "/"
|
||||
ctxAppURL := httplib.GuessCurrentAppURL(ctx)
|
||||
if !strings.HasPrefix(ctxAppURL, frontendAppURL) {
|
||||
problems = append(problems, ctx.Locale.TrString("admin.self_check.location_origin_mismatch", frontendAppURL, ctxAppURL))
|
||||
}
|
||||
ctx.JSON(http.StatusOK, map[string]any{"problems": problems})
|
||||
}
|
||||
|
||||
func CronTasks(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.monitor.cron")
|
||||
ctx.Data["PageIsAdminMonitorCron"] = true
|
||||
|
|
|
@ -4,8 +4,14 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/services/contexttest"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
@ -66,3 +72,21 @@ func TestShadowPassword(t *testing.T) {
|
|||
assert.EqualValues(t, k.Result, shadowPassword(k.Provider, k.CfgItem))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelfCheckPost(t *testing.T) {
|
||||
defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")()
|
||||
defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
|
||||
|
||||
ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
|
||||
SelfCheckPost(ctx)
|
||||
assert.EqualValues(t, http.StatusOK, resp.Code)
|
||||
|
||||
data := struct {
|
||||
Problems []string `json:"problems"`
|
||||
}{}
|
||||
err := json.Unmarshal(resp.Body.Bytes(), &data)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []string{
|
||||
ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"),
|
||||
}, data.Problems)
|
||||
}
|
||||
|
|
|
@ -686,6 +686,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
|
||||
|
||||
m.Get("/self_check", admin.SelfCheck)
|
||||
m.Post("/self_check", admin.SelfCheckPost)
|
||||
|
||||
m.Group("/config", func() {
|
||||
m.Get("", admin.Config)
|
||||
|
|
|
@ -309,7 +309,8 @@ func NewBaseContext(resp http.ResponseWriter, req *http.Request) (b *Base, close
|
|||
Locale: middleware.Locale(resp, req),
|
||||
Data: middleware.GetContextData(req.Context()),
|
||||
}
|
||||
b.AppendContextValue(translation.ContextKey, b.Locale)
|
||||
b.Req = b.Req.WithContext(b)
|
||||
b.AppendContextValue(translation.ContextKey, b.Locale)
|
||||
b.AppendContextValue(httplib.RequestContextKey, b.Req)
|
||||
return b, b.cleanUp
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func mockRequest(t *testing.T, reqPath string) *http.Request {
|
|||
}
|
||||
requestURL, err := url.Parse(path)
|
||||
assert.NoError(t, err)
|
||||
req := &http.Request{Method: method, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
|
||||
req := &http.Request{Method: method, Host: requestURL.Host, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
|
||||
req = req.WithContext(middleware.WithContextData(req.Context()))
|
||||
return req
|
||||
}
|
||||
|
|
|
@ -36,10 +36,6 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
|
|||
}
|
||||
}
|
||||
|
||||
if len(opts.DefaultBranch) == 0 {
|
||||
opts.DefaultBranch = setting.Repository.DefaultBranch
|
||||
}
|
||||
|
||||
repo := &repo_model.Repository{
|
||||
OwnerID: u.ID,
|
||||
Owner: u,
|
||||
|
@ -81,7 +77,7 @@ func AdoptRepository(ctx context.Context, doer, u *user_model.User, opts CreateR
|
|||
}
|
||||
|
||||
if err := adoptRepository(ctx, repoPath, repo, opts.DefaultBranch); err != nil {
|
||||
return fmt.Errorf("createDelegateHooks: %w", err)
|
||||
return fmt.Errorf("adoptRepository: %w", err)
|
||||
}
|
||||
|
||||
if err := repo_module.CheckDaemonExportOK(ctx, repo); err != nil {
|
||||
|
@ -143,6 +139,21 @@ func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repo
|
|||
}
|
||||
}
|
||||
|
||||
// Don't bother looking this repo in the context it won't be there
|
||||
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("openRepository: %w", err)
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
if _, err = repo_module.SyncRepoBranchesWithRepo(ctx, repo, gitRepo, 0); err != nil {
|
||||
return fmt.Errorf("SyncRepoBranchesWithRepo: %w", err)
|
||||
}
|
||||
|
||||
if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil {
|
||||
return fmt.Errorf("SyncReleasesWithTags: %w", err)
|
||||
}
|
||||
|
||||
branches, _ := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{
|
||||
RepoID: repo.ID,
|
||||
ListOptions: db.ListOptionsAll,
|
||||
|
@ -183,26 +194,10 @@ func adoptRepository(ctx context.Context, repoPath string, repo *repo_model.Repo
|
|||
return fmt.Errorf("setDefaultBranch: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = repo_module.UpdateRepository(ctx, repo, false); err != nil {
|
||||
return fmt.Errorf("updateRepository: %w", err)
|
||||
}
|
||||
|
||||
// Don't bother looking this repo in the context it won't be there
|
||||
gitRepo, err := gitrepo.OpenRepository(ctx, repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("openRepository: %w", err)
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
|
||||
if _, err = repo_module.SyncRepoBranchesWithRepo(ctx, repo, gitRepo, 0); err != nil {
|
||||
return fmt.Errorf("SyncRepoBranches: %w", err)
|
||||
}
|
||||
|
||||
if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil {
|
||||
return fmt.Errorf("SyncReleasesWithTags: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}
|
||||
{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin")}}
|
||||
|
||||
<div class="admin-setting-content">
|
||||
<h4 class="ui top attached header">
|
||||
|
@ -6,7 +6,7 @@
|
|||
</h4>
|
||||
|
||||
{{if .StartupProblems}}
|
||||
<div class="ui attached segment">
|
||||
<div class="ui attached segment self-check-problem">
|
||||
<div class="ui warning message">
|
||||
<div>{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}</div>
|
||||
<ul class="tw-w-full">{{range .StartupProblems}}<li>{{.}}</li>{{end}}</ul>
|
||||
|
@ -14,8 +14,10 @@
|
|||
</div>
|
||||
{{end}}
|
||||
|
||||
<div class="ui attached segment tw-hidden self-check-problem" id="self-check-by-frontend"></div>
|
||||
|
||||
{{if .DatabaseCheckHasProblems}}
|
||||
<div class="ui attached segment">
|
||||
<div class="ui attached segment self-check-problem">
|
||||
{{if .DatabaseType.IsMySQL}}
|
||||
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div>
|
||||
{{else if .DatabaseType.IsMSSQL}}
|
||||
|
@ -29,22 +31,22 @@
|
|||
{{end}}
|
||||
{{if .DatabaseCheckInconsistentCollationColumns}}
|
||||
<div class="ui red message">
|
||||
{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}
|
||||
<ul class="tw-w-full">
|
||||
{{range .DatabaseCheckInconsistentCollationColumns}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
<details>
|
||||
<summary>{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}</summary>
|
||||
<ul class="tw-w-full">
|
||||
{{range .DatabaseCheckInconsistentCollationColumns}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
</details>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}}
|
||||
<div class="ui attached segment">
|
||||
{{/* only shown when there is no visible "self-check-problem" */}}
|
||||
<div class="ui attached segment tw-hidden self-check-no-problem">
|
||||
{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
{{template "admin/layout_footer" .}}
|
||||
|
|
|
@ -358,6 +358,7 @@
|
|||
}
|
||||
|
||||
.ui.vertical.menu .active.item {
|
||||
background: var(--color-active);
|
||||
border-radius: 0;
|
||||
}
|
||||
.ui.vertical.menu > .active.item:first-child {
|
||||
|
|
|
@ -16,20 +16,20 @@ function shouldIgnoreError(err) {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function showGlobalErrorMessage(msg) {
|
||||
export function showGlobalErrorMessage(msg, msgType = 'error') {
|
||||
const msgContainer = document.querySelector('.page-content') ?? document.body;
|
||||
const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages
|
||||
let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`);
|
||||
if (!msgDiv) {
|
||||
const el = document.createElement('div');
|
||||
el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`;
|
||||
el.innerHTML = `<div class="ui container js-global-error tw-my-[--page-spacing]"><div class="ui ${msgType} message tw-text-center tw-whitespace-pre-line"></div></div>`;
|
||||
msgDiv = el.childNodes[0];
|
||||
}
|
||||
// merge duplicated messages into "the message (count)" format
|
||||
const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1;
|
||||
msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact);
|
||||
msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString());
|
||||
msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
|
||||
msgDiv.querySelector('.ui.message').textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
|
||||
msgContainer.prepend(msgDiv);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import {toggleElem} from '../../utils/dom.js';
|
||||
import {POST} from '../../modules/fetch.js';
|
||||
|
||||
const {appSubUrl} = window.config;
|
||||
|
||||
export async function initAdminSelfCheck() {
|
||||
const elCheckByFrontend = document.querySelector('#self-check-by-frontend');
|
||||
if (!elCheckByFrontend) return;
|
||||
|
||||
const elContent = document.querySelector('.page-content.admin .admin-setting-content');
|
||||
|
||||
// send frontend self-check request
|
||||
const resp = await POST(`${appSubUrl}/admin/self_check`, {
|
||||
data: new URLSearchParams({
|
||||
location_origin: window.location.origin,
|
||||
now: Date.now(), // TODO: check time difference between server and client
|
||||
}),
|
||||
});
|
||||
const json = await resp.json();
|
||||
toggleElem(elCheckByFrontend, Boolean(json.problems?.length));
|
||||
for (const problem of json.problems ?? []) {
|
||||
const elProblem = document.createElement('div');
|
||||
elProblem.classList.add('ui', 'warning', 'message');
|
||||
elProblem.textContent = problem;
|
||||
elCheckByFrontend.append(elProblem);
|
||||
}
|
||||
|
||||
// only show the "no problem" if there is no visible "self-check-problem"
|
||||
const hasProblem = Boolean(elContent.querySelectorAll('.self-check-problem:not(.tw-hidden)').length);
|
||||
toggleElem(elContent.querySelector('.self-check-no-problem'), !hasProblem);
|
||||
}
|
|
@ -451,5 +451,5 @@ export function checkAppUrl() {
|
|||
return;
|
||||
}
|
||||
showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting.
|
||||
Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`);
|
||||
Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`, 'warning');
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js'
|
|||
import {initDirAuto} from './modules/dirauto.js';
|
||||
import {initRepositorySearch} from './features/repo-search.js';
|
||||
import {initColorPickers} from './features/colorpicker.js';
|
||||
import {initAdminSelfCheck} from './features/admin/selfcheck.js';
|
||||
|
||||
// Init Gitea's Fomantic settings
|
||||
initGiteaFomantic();
|
||||
|
@ -132,6 +133,7 @@ onDomReady(() => {
|
|||
initAdminEmails();
|
||||
initAdminUserListSearchForm();
|
||||
initAdminConfigs();
|
||||
initAdminSelfCheck();
|
||||
|
||||
initDashboardRepoList();
|
||||
|
||||
|
|
Loading…
Reference in New Issue