diff --git a/cmd/web.go b/cmd/web.go index ef82486c1f..44babd51c5 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -114,7 +114,7 @@ func showWebStartupMessage(msg string) { log.Info("* WorkPath: %s", setting.AppWorkPath) log.Info("* CustomPath: %s", setting.CustomPath) log.Info("* ConfigFile: %s", setting.CustomConf) - log.Info("%s", msg) + log.Info("%s", msg) // show startup message } func serveInstall(ctx *cli.Context) error { diff --git a/models/actions/schedule_list.go b/models/actions/schedule_list.go index b806550b87..ecd2c1121c 100644 --- a/models/actions/schedule_list.go +++ b/models/actions/schedule_list.go @@ -44,6 +44,9 @@ func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error { schedule.TriggerUser = user_model.NewActionsUser() } else { schedule.TriggerUser = users[schedule.TriggerUserID] + if schedule.TriggerUser == nil { + schedule.TriggerUser = user_model.NewGhostUser() + } } } return nil diff --git a/models/actions/task.go b/models/actions/task.go index 96a6d2e80c..9946cf5233 100644 --- a/models/actions/task.go +++ b/models/actions/task.go @@ -11,6 +11,7 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -227,7 +228,9 @@ func CreateTaskForRunner(ctx context.Context, runner *ActionRunner) (*ActionTask if runner.RepoID != 0 { jobCond = builder.Eq{"repo_id": runner.RepoID} } else if runner.OwnerID != 0 { - jobCond = builder.In("repo_id", builder.Select("id").From("repository").Where(builder.Eq{"owner_id": runner.OwnerID})) + jobCond = builder.In("repo_id", builder.Select("`repository`.id").From("repository"). + Join("INNER", "repo_unit", "`repository`.id = `repo_unit`.repo_id"). + Where(builder.Eq{"`repository`.owner_id": runner.OwnerID, "`repo_unit`.type": unit.TypeActions})) } if jobCond.IsValid() { jobCond = builder.In("run_id", builder.Select("id").From("action_run").Where(jobCond)) diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index b9cfb1b251..1ed3b5df2a 100644 --- a/models/asymkey/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -76,23 +76,14 @@ func calcFingerprintNative(publicKeyContent string) (string, error) { // CalcFingerprint calculate public key's fingerprint func CalcFingerprint(publicKeyContent string) (string, error) { // Call the method based on configuration - var ( - fnName, fp string - err error - ) - if len(setting.SSH.KeygenPath) == 0 { - fnName = "calcFingerprintNative" - fp, err = calcFingerprintNative(publicKeyContent) - } else { - fnName = "calcFingerprintSSHKeygen" - fp, err = calcFingerprintSSHKeygen(publicKeyContent) - } + useNative := setting.SSH.KeygenPath == "" + calcFn := util.Iif(useNative, calcFingerprintNative, calcFingerprintSSHKeygen) + fp, err := calcFn(publicKeyContent) if err != nil { if IsErrKeyUnableVerify(err) { - log.Info("%s", publicKeyContent) return "", err } - return "", fmt.Errorf("%s: %w", fnName, err) + return "", fmt.Errorf("CalcFingerprint(%s): %w", util.Iif(useNative, "native", "ssh-keygen"), err) } return fp, nil } diff --git a/models/repo/issue.go b/models/repo/issue.go index 6f6b565a00..0dd4fd5ed4 100644 --- a/models/repo/issue.go +++ b/models/repo/issue.go @@ -53,7 +53,7 @@ func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool { var u *RepoUnit var err error if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { - log.Trace("%s", err) + log.Trace("IsDependenciesEnabled: %v", err) return setting.Service.DefaultEnableDependencies } return u.IssuesConfig().EnableDependencies diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go index 6c1b4ab240..774385483b 100644 --- a/modules/templates/util_misc.go +++ b/modules/templates/util_misc.go @@ -142,35 +142,39 @@ type remoteAddress struct { Password string } -func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress { - a := remoteAddress{} - - remoteURL := m.OriginalURL - if ignoreOriginalURL || remoteURL == "" { - var err error - remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName) - if err != nil { - log.Error("GetRemoteURL %v", err) - return a - } +func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress { + ret := remoteAddress{} + remoteURL, err := git.GetRemoteAddress(ctx, m.RepoPath(), remoteName) + if err != nil { + log.Error("GetRemoteURL %v", err) + return ret } u, err := giturl.Parse(remoteURL) if err != nil { log.Error("giturl.Parse %v", err) - return a + return ret } if u.Scheme != "ssh" && u.Scheme != "file" { if u.User != nil { - a.Username = u.User.Username() - a.Password, _ = u.User.Password() + ret.Username = u.User.Username() + ret.Password, _ = u.User.Password() } - u.User = nil } - a.Address = u.String() - return a + // The URL stored in the git repo could contain authentication, + // erase it, or it will be shown in the UI. + u.User = nil + ret.Address = u.String() + // Why not use m.OriginalURL to set ret.Address? + // It should be OK to use it, since m.OriginalURL should be the same as the authentication-erased URL from the Git repository. + // However, the old code has already stored authentication in m.OriginalURL when updating mirror settings. + // That means we need to use "giturl.Parse" for m.OriginalURL again to ensure authentication is erased. + // Instead of doing this, why not directly use the authentication-erased URL from the Git repository? + // It should be the same as long as there are no bugs. + + return ret } func FilenameIsImage(filename string) bool { diff --git a/modules/util/util.go b/modules/util/util.go index 5c75158196..e4d658d7f8 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -212,3 +212,11 @@ func ToFloat64(number any) (float64, error) { func ToPointer[T any](val T) *T { return &val } + +// Iif is an "inline-if", it returns "trueVal" if "condition" is true, otherwise "falseVal" +func Iif[T any](condition bool, trueVal, falseVal T) T { + if condition { + return trueVal + } + return falseVal +} diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 2640819a54..0d304dd66d 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -311,7 +311,7 @@ func SearchIssues(ctx *context.APIContext) { ctx.SetLinkHeader(int(total), limit) ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } // ListIssues list the issues of a repository @@ -548,7 +548,7 @@ func ListIssues(ctx *context.APIContext) { ctx.SetLinkHeader(int(total), listOptions.PageSize) ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 { @@ -614,7 +614,7 @@ func GetIssue(ctx *context.APIContext) { ctx.NotFound() return } - ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue)) + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue)) } // CreateIssue create an issue of a repository @@ -737,7 +737,7 @@ func CreateIssue(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetIssueByID", err) return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue)) } // EditIssue modify an issue of a repository @@ -913,7 +913,7 @@ func EditIssue(ctx *context.APIContext) { ctx.InternalServerError(err) return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, issue)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, issue)) } func DeleteIssue(ctx *context.APIContext) { diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index fc9e88d63d..6f3e4b5e77 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -108,7 +108,7 @@ func ListIssueAttachments(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments) + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, ctx.Doer, issue).Attachments) } // CreateIssueAttachment creates an attachment and saves the given file diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index a42920d4fd..c40e92c01b 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -153,7 +153,7 @@ func GetIssueDependencies(ctx *context.APIContext) { blockerIssues = append(blockerIssues, &blocker.Issue) } - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, blockerIssues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, blockerIssues)) } // CreateIssueDependency create a new issue dependencies @@ -214,7 +214,7 @@ func CreateIssueDependency(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target)) } // RemoveIssueDependency remove an issue dependency @@ -275,7 +275,7 @@ func RemoveIssueDependency(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, target)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, target)) } // GetIssueBlocks list issues that are blocked by this issue @@ -381,7 +381,7 @@ func GetIssueBlocks(ctx *context.APIContext) { issues = append(issues, &depMeta.Issue) } - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } // CreateIssueBlocking block the issue given in the body by the issue in path @@ -438,7 +438,7 @@ func CreateIssueBlocking(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency)) } // RemoveIssueBlocking unblock the issue given in the body by the issue in path @@ -495,7 +495,7 @@ func RemoveIssueBlocking(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, dependency)) + ctx.JSON(http.StatusCreated, convert.ToAPIIssue(ctx, ctx.Doer, dependency)) } func getParamsIssue(ctx *context.APIContext) *issues_model.Issue { diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go index 8fcf670fd0..af3e06332a 100644 --- a/routers/api/v1/repo/issue_pin.go +++ b/routers/api/v1/repo/issue_pin.go @@ -207,7 +207,7 @@ func ListPinnedIssues(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(ctx, ctx.Doer, issues)) } // ListPinnedPullRequests returns a list of all pinned PRs diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index c640515881..f83855efac 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -138,7 +138,7 @@ func ListTrackedTimes(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } // AddTime add time manual to the given issue @@ -225,7 +225,7 @@ func AddTime(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, trackedTime)) + ctx.JSON(http.StatusOK, convert.ToTrackedTime(ctx, user, trackedTime)) } // ResetIssueTime reset time manual to the given issue @@ -455,7 +455,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) return } - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } // ListTrackedTimesByRepository lists all tracked times of the repository @@ -567,7 +567,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } // ListMyTrackedTimes lists all tracked times of the current user @@ -629,5 +629,5 @@ func ListMyTrackedTimes(ctx *context.APIContext) { } ctx.SetTotalCountHeader(count) - ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, trackedTimes)) + ctx.JSON(http.StatusOK, convert.ToTrackedTimeList(ctx, ctx.Doer, trackedTimes)) } diff --git a/routers/private/actions.go b/routers/private/actions.go index 397f20a091..425c480b3e 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -27,7 +27,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { defer rd.Close() if err := json.NewDecoder(rd).Decode(&genRequest); err != nil { - log.Error("%v", err) + log.Error("JSON Decode failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) @@ -36,7 +36,7 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { owner, repo, err := parseScope(ctx, genRequest.Scope) if err != nil { - log.Error("%v", err) + log.Error("parseScope failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) @@ -46,18 +46,18 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { token, err = actions_model.NewRunnerToken(ctx, owner, repo) if err != nil { - err := fmt.Sprintf("error while creating runner token: %v", err) - log.Error("%v", err) + errMsg := fmt.Sprintf("error while creating runner token: %v", err) + log.Error("NewRunnerToken failed: %v", errMsg) ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: err, + Err: errMsg, }) return } } else if err != nil { - err := fmt.Sprintf("could not get unactivated runner token: %v", err) - log.Error("%v", err) + errMsg := fmt.Sprintf("could not get unactivated runner token: %v", err) + log.Error("GetLatestRunnerToken failed: %v", errMsg) ctx.JSON(http.StatusInternalServerError, private.Response{ - Err: err, + Err: errMsg, }) return } diff --git a/routers/private/hook_verification.go b/routers/private/hook_verification.go index 42b8e5abed..764c976fa9 100644 --- a/routers/private/hook_verification.go +++ b/routers/private/hook_verification.go @@ -47,7 +47,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env [] _ = stdoutWriter.Close() err := readAndVerifyCommitsFromShaReader(stdoutReader, repo, env) if err != nil { - log.Error("%v", err) + log.Error("readAndVerifyCommitsFromShaReader failed: %v", err) cancel() } _ = stdoutReader.Close() @@ -66,7 +66,6 @@ func readAndVerifyCommitsFromShaReader(input io.ReadCloser, repo *git.Repository line := scanner.Text() err := readAndVerifyCommit(line, repo, env) if err != nil { - log.Error("%v", err) return err } } diff --git a/routers/private/mail.go b/routers/private/mail.go index c19ee67896..cf3abb31c6 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -35,7 +35,7 @@ func SendEmail(ctx *context.PrivateContext) { defer rd.Close() if err := json.NewDecoder(rd).Decode(&mail); err != nil { - log.Error("%v", err) + log.Error("JSON Decode failed: %v", err) ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), }) diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 3dcf0d2aa8..15bd667a4f 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -403,7 +403,6 @@ func EditUserPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplUserEdit, &form) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplUserEdit, &form) default: diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index c9e0386041..53494df630 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -215,7 +215,6 @@ func ResetPasswdPost(ctx *context.Context) { case errors.Is(err, password.ErrIsPwned): ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplResetPassword, nil) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplResetPassword, nil) default: ctx.ServerError("UpdateAuth", err) @@ -299,7 +298,6 @@ func MustChangePasswordPost(ctx *context.Context) { ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned"), tplMustChangePassword, &form) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Data["Err_Password"] = true ctx.RenderWithErr(ctx.Tr("auth.password_pwned_err"), tplMustChangePassword, &form) default: diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index db1dac0120..38f9b85ace 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "net/http" - "net/url" "strconv" "strings" @@ -195,14 +194,15 @@ func NewProjectPost(ctx *context.Context) { // ChangeProjectStatus updates the status of a project between "open" and "close" func ChangeProjectStatus(ctx *context.Context) { - toClose := false + var toClose bool switch ctx.Params(":action") { case "open": toClose = false case "close": toClose = true default: - ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects") + ctx.JSONRedirect(ctx.ContextUser.HomeLink() + "/-/projects") + return } id := ctx.ParamsInt64(":id") @@ -210,7 +210,7 @@ func ChangeProjectStatus(ctx *context.Context) { ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) return } - ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects?state=" + url.QueryEscape(ctx.Params(":action"))) + ctx.JSONRedirect(fmt.Sprintf("%s/-/projects/%d", ctx.ContextUser.HomeLink(), id)) } // DeleteProject delete a project diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index a4e3f7165a..afa6160d42 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -2179,7 +2179,7 @@ func GetIssueInfo(ctx *context.Context) { } } - ctx.JSON(http.StatusOK, convert.ToIssue(ctx, issue)) + ctx.JSON(http.StatusOK, convert.ToIssue(ctx, ctx.Doer, issue)) } // UpdateIssueTitle change issue's title @@ -2713,7 +2713,7 @@ func SearchIssues(ctx *context.Context) { } ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues)) } func getUserIDForFilter(ctx *context.Context, queryName string) int64 { @@ -2883,7 +2883,7 @@ func ListIssues(ctx *context.Context) { } ctx.SetTotalCountHeader(total) - ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, issues)) + ctx.JSON(http.StatusOK, convert.ToIssueList(ctx, ctx.Doer, issues)) } func BatchDeleteIssues(ctx *context.Context) { diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index aa42585590..a0c044fd64 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "net/http" - "net/url" "strings" "code.gitea.io/gitea/models/db" @@ -180,14 +179,10 @@ func ChangeProjectStatus(ctx *context.Context) { id := ctx.ParamsInt64(":id") if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { - if project_model.IsErrProjectNotExist(err) { - ctx.NotFound("", err) - } else { - ctx.ServerError("ChangeProjectStatusByIDAndRepoID", err) - } + ctx.NotFoundOrServerError("ChangeProjectStatusByRepoIDAndID", project_model.IsErrProjectNotExist, err) return } - ctx.JSONRedirect(ctx.Repo.RepoLink + "/projects?state=" + url.QueryEscape(ctx.Params(":action"))) + ctx.JSONRedirect(fmt.Sprintf("%s/projects/%d", ctx.Repo.RepoLink, id)) } // DeleteProject delete a project diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index 386309aa71..6f412aed7f 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -74,7 +74,6 @@ func AccountPost(ctx *context.Context) { case errors.Is(err, password.ErrIsPwned): ctx.Flash.Error(ctx.Tr("auth.password_pwned")) case password.IsErrIsPwnedRequest(err): - log.Error("%s", err.Error()) ctx.Flash.Error(ctx.Tr("auth.password_pwned_err")) default: ctx.ServerError("UpdateAuth", err) diff --git a/services/actions/notifier.go b/services/actions/notifier.go index eec5f814da..6551da39e7 100644 --- a/services/actions/notifier.go +++ b/services/actions/notifier.go @@ -49,7 +49,7 @@ func (n *actionsNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu newNotifyInputFromIssue(issue, webhook_module.HookEventIssues).WithPayload(&api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, issue.Poster, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, issue.Poster, nil), }).Notify(withMethod(ctx, "NewIssue")) @@ -89,7 +89,7 @@ func (n *actionsNotifier) IssueChangeContent(ctx context.Context, doer *user_mod WithPayload(&api.IssuePayload{ Action: api.HookIssueEdited, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }). @@ -127,7 +127,7 @@ func (n *actionsNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode } apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), } @@ -229,7 +229,7 @@ func notifyIssueChange(ctx context.Context, doer *user_model.User, issue *issues WithPayload(&api.IssuePayload{ Action: action, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }). @@ -293,7 +293,7 @@ func notifyIssueCommentChange(ctx context.Context, doer *user_model.User, commen payload := &api.IssueCommentPayload{ Action: action, - Issue: convert.ToAPIIssue(ctx, comment.Issue), + Issue: convert.ToAPIIssue(ctx, doer, comment.Issue), Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index 5d1e2c122b..ef37ff87ee 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -560,12 +560,9 @@ func DetectAndHandleSchedules(ctx context.Context, repo *repo_model.Repository) } // We need a notifyInput to call handleSchedules - // Here we use the commit author as the Doer of the notifyInput - commitUser, err := user_model.GetUserByEmail(ctx, commit.Author.Email) - if err != nil { - return fmt.Errorf("get user by email: %w", err) - } - notifyInput := newNotifyInput(repo, commitUser, webhook_module.HookEventSchedule) + // if repo is a mirror, commit author maybe an external user, + // so we use action user as the Doer of the notifyInput + notifyInput := newNotifyInput(repo, user_model.NewActionsUser(), webhook_module.HookEventSchedule) return handleSchedules(ctx, scheduleWorkflows, commit, notifyInput, repo.DefaultBranch) } diff --git a/services/context/captcha.go b/services/context/captcha.go index a1999900c9..fa8d779f56 100644 --- a/services/context/captcha.go +++ b/services/context/captcha.go @@ -79,11 +79,11 @@ func VerifyCaptcha(ctx *Context, tpl base.TplName, form any) { case setting.CfTurnstile: valid, err = turnstile.Verify(ctx, ctx.Req.Form.Get(cfTurnstileResponseField)) default: - ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) + ctx.ServerError("Unknown Captcha Type", fmt.Errorf("unknown Captcha Type: %s", setting.Service.CaptchaType)) return } if err != nil { - log.Debug("%v", err) + log.Debug("Captcha Verify failed: %v", err) } if !valid { diff --git a/services/convert/issue.go b/services/convert/issue.go index c6e06180c8..54b00cd88e 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -18,19 +18,19 @@ import ( api "code.gitea.io/gitea/modules/structs" ) -func ToIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue { - return toIssue(ctx, issue, WebAssetDownloadURL) +func ToIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue { + return toIssue(ctx, doer, issue, WebAssetDownloadURL) } // ToAPIIssue converts an Issue to API format // it assumes some fields assigned with values: // Required - Poster, Labels, // Optional - Milestone, Assignee, PullRequest -func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue { - return toIssue(ctx, issue, APIAssetDownloadURL) +func ToAPIIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) *api.Issue { + return toIssue(ctx, doer, issue, APIAssetDownloadURL) } -func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue { +func toIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, getDownloadURL func(repo *repo_model.Repository, attach *repo_model.Attachment) string) *api.Issue { if err := issue.LoadLabels(ctx); err != nil { return &api.Issue{} } @@ -44,7 +44,7 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func apiIssue := &api.Issue{ ID: issue.ID, Index: issue.Index, - Poster: ToUser(ctx, issue.Poster, nil), + Poster: ToUser(ctx, issue.Poster, doer), Title: issue.Title, Body: issue.Content, Attachments: toAttachments(issue.Repo, issue.Attachments, getDownloadURL), @@ -114,25 +114,25 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func } // ToIssueList converts an IssueList to API format -func ToIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue { +func ToIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue { result := make([]*api.Issue, len(il)) for i := range il { - result[i] = ToIssue(ctx, il[i]) + result[i] = ToIssue(ctx, doer, il[i]) } return result } // ToAPIIssueList converts an IssueList to API format -func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue { +func ToAPIIssueList(ctx context.Context, doer *user_model.User, il issues_model.IssueList) []*api.Issue { result := make([]*api.Issue, len(il)) for i := range il { - result[i] = ToAPIIssue(ctx, il[i]) + result[i] = ToAPIIssue(ctx, doer, il[i]) } return result } // ToTrackedTime converts TrackedTime to API format -func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { +func ToTrackedTime(ctx context.Context, doer *user_model.User, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { apiT = &api.TrackedTime{ ID: t.ID, IssueID: t.IssueID, @@ -141,7 +141,7 @@ func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api. Created: t.Created, } if t.Issue != nil { - apiT.Issue = ToAPIIssue(ctx, t.Issue) + apiT.Issue = ToAPIIssue(ctx, doer, t.Issue) } if t.User != nil { apiT.UserName = t.User.Name @@ -192,10 +192,10 @@ func ToStopWatches(ctx context.Context, sws []*issues_model.Stopwatch) (api.Stop } // ToTrackedTimeList converts TrackedTimeList to API format -func ToTrackedTimeList(ctx context.Context, tl issues_model.TrackedTimeList) api.TrackedTimeList { +func ToTrackedTimeList(ctx context.Context, doer *user_model.User, tl issues_model.TrackedTimeList) api.TrackedTimeList { result := make([]*api.TrackedTime, 0, len(tl)) for _, t := range tl { - result = append(result, ToTrackedTime(ctx, t)) + result = append(result, ToTrackedTime(ctx, doer, t)) } return result } diff --git a/services/convert/issue_comment.go b/services/convert/issue_comment.go index b034a50897..9ffaf1e84c 100644 --- a/services/convert/issue_comment.go +++ b/services/convert/issue_comment.go @@ -120,7 +120,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu return nil } - comment.TrackedTime = ToTrackedTime(ctx, c.Time) + comment.TrackedTime = ToTrackedTime(ctx, doer, c.Time) } if c.RefIssueID != 0 { @@ -129,7 +129,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu log.Error("GetIssueByID(%d): %v", c.RefIssueID, err) return nil } - comment.RefIssue = ToAPIIssue(ctx, issue) + comment.RefIssue = ToAPIIssue(ctx, doer, issue) } if c.RefCommentID != 0 { @@ -180,7 +180,7 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu } if c.DependentIssue != nil { - comment.DependentIssue = ToAPIIssue(ctx, c.DependentIssue) + comment.DependentIssue = ToAPIIssue(ctx, doer, c.DependentIssue) } return comment diff --git a/services/convert/pull.go b/services/convert/pull.go index 6d98121ed5..775bf3806d 100644 --- a/services/convert/pull.go +++ b/services/convert/pull.go @@ -33,7 +33,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u return nil } - apiIssue := ToAPIIssue(ctx, pr.Issue) + apiIssue := ToAPIIssue(ctx, doer, pr.Issue) if err := pr.LoadBaseRepo(ctx); err != nil { log.Error("GetRepositoryById[%d]: %v", pr.ID, err) return nil diff --git a/services/migrations/gitbucket.go b/services/migrations/gitbucket.go index 5f11555839..4fe9e30a39 100644 --- a/services/migrations/gitbucket.go +++ b/services/migrations/gitbucket.go @@ -72,6 +72,11 @@ func (g *GitBucketDownloader) LogString() string { // NewGitBucketDownloader creates a GitBucket downloader func NewGitBucketDownloader(ctx context.Context, baseURL, userName, password, token, repoOwner, repoName string) *GitBucketDownloader { githubDownloader := NewGithubDownloaderV3(ctx, baseURL, userName, password, token, repoOwner, repoName) + // Gitbucket 4.40 uses different internal hard-coded perPage values. + // Issues, PRs, and other major parts use 25. Release page uses 10. + // Some API doesn't support paging yet. Sounds difficult, but using + // minimum number among them worked out very well. + githubDownloader.maxPerPage = 10 githubDownloader.SkipReactions = true githubDownloader.SkipReviews = true return &GitBucketDownloader{ diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 2a38d4ba55..fa23986c54 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -13,6 +13,7 @@ import ( system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" + giturl "code.gitea.io/gitea/modules/git/url" "code.gitea.io/gitea/modules/gitrepo" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -30,10 +31,15 @@ const gitShortEmptySha = "0000000" // UpdateAddress writes new address to Git repository and database func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error { + u, err := giturl.Parse(addr) + if err != nil { + return fmt.Errorf("invalid addr: %v", err) + } + remoteName := m.GetRemoteName() repoPath := m.GetRepository(ctx).RepoPath() // Remove old remote - _, _, err := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) + _, _, err = git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { return err } @@ -70,7 +76,9 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } } - m.Repo.OriginalURL = addr + // erase authentication before storing in database + u.User = nil + m.Repo.OriginalURL = u.String() return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url") } @@ -449,19 +457,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return false } - var gitRepo *git.Repository - if len(results) == 0 { - log.Trace("SyncMirrors [repo: %-v]: no branches updated", m.Repo) - } else { - log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) - gitRepo, err = gitrepo.OpenRepository(ctx, m.Repo) - if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err) - return false - } - defer gitRepo.Close() + gitRepo, err := gitrepo.OpenRepository(ctx, m.Repo) + if err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err) + return false + } + defer gitRepo.Close() + log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results)) + if len(results) > 0 { if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok { + log.Error("SyncMirrors [repo: %-v]: checkAndUpdateEmptyRepository: %v", m.Repo, err) return false } } @@ -534,16 +540,24 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } log.Trace("SyncMirrors [repo: %-v]: done notifying updated branches/tags - now updating last commit time", m.Repo) - // Get latest commit date and update to current repository updated time - commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath()) + isEmpty, err := gitRepo.IsEmpty() if err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err) + log.Error("SyncMirrors [repo: %-v]: unable to check empty git repo: %v", m.Repo, err) return false } + if !isEmpty { + // Get latest commit date and update to current repository updated time + commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath()) + if err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err) + return false + } + + if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil { + log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) + return false + } - if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil { - log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) - return false } log.Trace("SyncMirrors [repo: %-v]: Successfully updated", m.Repo) diff --git a/services/notify/notify.go b/services/notify/notify.go index 9cb329d302..5ed63646aa 100644 --- a/services/notify/notify.go +++ b/services/notify/notify.go @@ -91,7 +91,7 @@ func AutoMergePullRequest(ctx context.Context, doer *user_model.User, pr *issues // NewPullRequest notifies new pull request to notifiers func NewPullRequest(ctx context.Context, pr *issues_model.PullRequest, mentions []*user_model.User) { if err := pr.LoadIssue(ctx); err != nil { - log.Error("%v", err) + log.Error("LoadIssue failed: %v", err) return } if err := pr.Issue.LoadPoster(ctx); err != nil { @@ -112,7 +112,7 @@ func PullRequestSynchronized(ctx context.Context, doer *user_model.User, pr *iss // PullRequestReview notifies new pull request review func PullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { if err := review.LoadReviewer(ctx); err != nil { - log.Error("%v", err) + log.Error("LoadReviewer failed: %v", err) return } for _, notifier := range notifiers { diff --git a/services/repository/files/cherry_pick.go b/services/repository/files/cherry_pick.go index 613b46d8f6..451a182155 100644 --- a/services/repository/files/cherry_pick.go +++ b/services/repository/files/cherry_pick.go @@ -28,7 +28,7 @@ func CherryPick(ctx context.Context, repo *repo_model.Repository, doer *user_mod t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() if err := t.Clone(opts.OldBranch, false); err != nil { diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index f6d5643dc9..e5f7e2af96 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -111,7 +111,7 @@ func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() if err := t.Clone(opts.OldBranch, true); err != nil { diff --git a/services/repository/files/update.go b/services/repository/files/update.go index a6c813f024..e677949e86 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -143,7 +143,7 @@ func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use t, err := NewTemporaryUploadRepository(ctx, repo) if err != nil { - log.Error("%v", err) + log.Error("NewTemporaryUploadRepository failed: %v", err) } defer t.Close() hasOldBranch := true diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index 03c5bede8b..a9b3422653 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -67,7 +67,7 @@ func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelCleared, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -168,7 +168,7 @@ func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo permission, _ := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), } @@ -214,7 +214,7 @@ func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model From: oldTitle, }, }, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -250,7 +250,7 @@ func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode } else { apiIssue := &api.IssuePayload{ Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), CommitID: commitID, @@ -281,7 +281,7 @@ func (m *webhookNotifier) NewIssue(ctx context.Context, issue *issues_model.Issu if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, issue.Poster, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, issue.Poster, nil), }); err != nil { @@ -349,7 +349,7 @@ func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_mod From: oldContent, }, }, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -384,7 +384,7 @@ func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.Us permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentEdited, - Issue: convert.ToAPIIssue(ctx, c.Issue), + Issue: convert.ToAPIIssue(ctx, doer, c.Issue), Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c), Changes: &api.ChangesPayload{ Body: &api.ChangesFromPayload{ @@ -412,7 +412,7 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentCreated, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Comment: convert.ToAPIComment(ctx, repo, comment), Repository: convert.ToRepo(ctx, repo, permission), Sender: convert.ToUser(ctx, doer, nil), @@ -449,7 +449,7 @@ func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.Us permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentDeleted, - Issue: convert.ToAPIIssue(ctx, comment.Issue), + Issue: convert.ToAPIIssue(ctx, doer, comment.Issue), Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), @@ -533,7 +533,7 @@ func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelUpdated, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -575,7 +575,7 @@ func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{ Action: hookAction, Index: issue.Index, - Issue: convert.ToAPIIssue(ctx, issue), + Issue: convert.ToAPIIssue(ctx, doer, issue), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index f2505e82cf..ec5d0fc9e2 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -209,7 +209,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model if isOldWikiExist { err := gitRepo.RemoveFilesFromIndex(oldWikiPath) if err != nil { - log.Error("%v", err) + log.Error("RemoveFilesFromIndex failed: %v", err) return err } } @@ -219,18 +219,18 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model objectHash, err := gitRepo.HashObject(strings.NewReader(content)) if err != nil { - log.Error("%v", err) + log.Error("HashObject failed: %v", err) return err } if err := gitRepo.AddObjectToIndex("100644", objectHash, newWikiPath); err != nil { - log.Error("%v", err) + log.Error("AddObjectToIndex failed: %v", err) return err } tree, err := gitRepo.WriteTree() if err != nil { - log.Error("%v", err) + log.Error("WriteTree failed: %v", err) return err } @@ -255,7 +255,7 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model commitHash, err := gitRepo.CommitTree(doer.NewGitSig(), committer, tree, commitTreeOpts) if err != nil { - log.Error("%v", err) + log.Error("CommitTree failed: %v", err) return err } @@ -270,11 +270,11 @@ func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model 0, ), }); err != nil { - log.Error("%v", err) + log.Error("Push failed: %v", err) if git.IsErrPushOutOfDate(err) || git.IsErrPushRejected(err) { return err } - return fmt.Errorf("Push: %w", err) + return fmt.Errorf("failed to push: %w", err) } return nil diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 5ea003e5ec..33d8a2f963 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -62,10 +62,7 @@ {{template "admin/layout_footer" .}} diff --git a/templates/org/projects/list.tmpl b/templates/org/projects/list.tmpl index ec9cfece9a..80dde1c4d2 100644 --- a/templates/org/projects/list.tmpl +++ b/templates/org/projects/list.tmpl @@ -13,11 +13,9 @@
{{template "shared/user/profile_big_avatar" .}}
-
-
+
{{template "user/overview/header" .}} -
- {{template "projects/list" .}} + {{template "projects/list" .}}
diff --git a/templates/org/projects/view.tmpl b/templates/org/projects/view.tmpl index 495204b06d..e1ab81c4cd 100644 --- a/templates/org/projects/view.tmpl +++ b/templates/org/projects/view.tmpl @@ -1,7 +1,7 @@ {{template "base/head" .}}
{{template "shared/user/org_profile_avatar" .}} -
+
{{template "user/overview/header" .}}
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 3ae7fffa1c..c37fb46975 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -18,10 +18,10 @@ {{end}} {{end}}
-
+

{{RenderCommitMessage $.Context .Commit.Message ($.Repository.ComposeMetas ctx)}}{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses}}

{{if not $.PageIsWiki}} -
+
{{ctx.Locale.Tr "repo.diff.browse_source"}} diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 9ede83dcb7..6b343e4ee0 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -111,7 +111,7 @@ {{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.IsArchived) $.IsShowingAllCommits}}

-
+
- {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}}{{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}} - - {{if $file.IsGenerated}} - {{ctx.Locale.Tr "repo.diff.generated"}} - {{end}} - {{if $file.IsVendored}} - {{ctx.Locale.Tr "repo.diff.vendored"}} - {{end}} - {{if and $file.Mode $file.OldMode}} - {{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}} - {{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} - {{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}} - {{else if $file.Mode}} - {{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} - {{end}} + {{if $file.IsRenamed}}{{$file.OldName}} → {{end}}{{$file.Name}} + {{if .IsLFSFile}} ({{ctx.Locale.Tr "repo.stored_lfs"}}){{end}} + + {{if $file.IsGenerated}} + {{ctx.Locale.Tr "repo.diff.generated"}} + {{end}} + {{if $file.IsVendored}} + {{ctx.Locale.Tr "repo.diff.vendored"}} + {{end}} + {{if and $file.Mode $file.OldMode}} + {{$old := ctx.Locale.Tr ($file.ModeTranslationKey $file.OldMode)}} + {{$new := ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} + {{ctx.Locale.Tr "git.filemode.changed_filemode" $old $new}} + {{else if $file.Mode}} + {{ctx.Locale.Tr ($file.ModeTranslationKey $file.Mode)}} + {{end}} +
{{if $showFileViewToggle}} diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 75a0005e56..e224febaf2 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -59,8 +59,11 @@
{{end}} {{template "repo/sub_menu" .}} + {{$n := len .TreeNames}} + {{$l := Eval $n "-" 1}} + {{$isHomepage := (eq $n 0)}}
-
+
{{template "repo/branch_dropdown" dict "root" . "ContainerClasses" "tw-mr-1"}} {{if and .CanCompareOrPull .IsViewBranch (not .Repository.IsArchived)}} {{$cmpBranch := ""}} @@ -75,9 +78,7 @@ {{end}} - {{$n := len .TreeNames}} - {{$l := Eval $n "-" 1}} - {{if eq $n 0}} + {{if $isHomepage}} {{ctx.Locale.Tr "repo.find_file.go_to_file"}} {{end}} @@ -101,20 +102,20 @@ {{end}} - {{if and (eq $n 0) (.Repository.IsTemplate)}} + {{if and $isHomepage (.Repository.IsTemplate)}} {{ctx.Locale.Tr "repo.use_template"}} {{end}} - {{if ne $n 0}} + {{if (not $isHomepage)}} {{StringUtils.EllipsisString .Repository.Name 30}} {{- range $i, $v := .TreeNames -}} / {{- if eq $i $l -}} - {{StringUtils.EllipsisString $v 30}} + {{$v}} {{- else -}} - {{$p := index $.Paths $i}}{{StringUtils.EllipsisString $v 30}} + {{$p := index $.Paths $i}}{{$v}} {{- end -}} {{- end -}} @@ -122,7 +123,7 @@
- {{if eq $n 0}} + {{if $isHomepage}}
{{template "repo/clone_buttons" .}}
{{template "repo/cite/cite_modal" .}} {{end}} - {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}} + {{if and (not $isHomepage) (not .IsViewFile) (not .IsBlame)}} {{svg "octicon-history" 16 "tw-mr-2"}}{{ctx.Locale.Tr "repo.file_history"}} diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 8b73afe6d0..1d1fdb36ef 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -156,7 +156,7 @@
- {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName false}} + {{$address := MirrorRemoteAddress $.Context .Repository .PullMirror.GetRemoteName}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 2680b374cd..333121c205 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -11,13 +11,13 @@ {{end}} {{if not .ReadmeInList}} -
-
+
+
{{template "repo/latest_commit" .}}
{{if .LatestCommit}} {{if .LatestCommit.Committer}} -
+
{{TimeSince .LatestCommit.Committer.When ctx.Locale}}
{{end}} diff --git a/templates/repo/view_list.tmpl b/templates/repo/view_list.tmpl index 7c463c50a6..fb257bd474 100644 --- a/templates/repo/view_list.tmpl +++ b/templates/repo/view_list.tmpl @@ -1,8 +1,12 @@ - diff --git a/templates/user/notification/notification_div.tmpl b/templates/user/notification/notification_div.tmpl index 04e79ba749..bf3b51ee3b 100644 --- a/templates/user/notification/notification_div.tmpl +++ b/templates/user/notification/notification_div.tmpl @@ -1,7 +1,7 @@
{{$notificationUnreadCount := call .NotificationUnreadCount}} -
+ diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 5880c80cc9..51b7a4f0ef 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -6,11 +6,8 @@
{{template "shared/user/profile_big_avatar" .}}
-
-
- {{template "user/overview/header" .}} -
- +
+ {{template "user/overview/header" .}} {{if eq .TabName "activity"}} {{if .ContextUser.KeepActivityPrivate}}
diff --git a/web_src/css/actions.css b/web_src/css/actions.css index e7b9a3855a..1d5bea2395 100644 --- a/web_src/css/actions.css +++ b/web_src/css/actions.css @@ -44,7 +44,7 @@ } .run-list-item-right { - flex: 0 0 15%; + flex: 0 0 min(20%, 130px); display: flex; flex-direction: column; gap: 3px; diff --git a/web_src/css/base.css b/web_src/css/base.css index 498199339a..a1f9c087fd 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -24,7 +24,21 @@ --repo-header-issue-min-height: 41px; --min-height-textarea: 132px; /* padding + 6 lines + border = calc(1.57142em + 6lh + 2px), but lh is not fully supported */ --tab-size: 4; - --checkbox-size: 16px; /* height and width of checkbox and radio inputs */ + --checkbox-size: 15px; /* height and width of checkbox and radio inputs */ + --page-spacing: 16px; /* space between page elements */ + --page-margin-x: 32px; /* minimum space on left and right side of page */ +} + +@media (min-width: 768px) and (max-width: 1200px) { + :root { + --page-margin-x: 16px; + } +} + +@media (max-width: 767.98px) { + :root { + --page-margin-x: 8px; + } } :root * { @@ -668,11 +682,14 @@ img.ui.avatar, margin-bottom: 14px; } -/* add padding to all content when there is no .secondary.nav. this uses padding instead of - margin because with the negative margin on .ui.grid we would have to set margin-top: 0, - but that does not work universally for all pages */ +/* add margin to all pages when there is no .secondary.nav */ .page-content > :first-child:not(.secondary-nav) { - padding-top: 14px; + margin-top: var(--page-spacing); +} +/* if .ui.grid is the first child the first grid-column has 'padding-top: 1rem' which we need + to compensate here */ +.page-content > :first-child.ui.grid { + margin-top: calc(var(--page-spacing) - 1rem); } .ui.pagination.menu .active.item { @@ -1330,6 +1347,7 @@ overflow-menu .ui.label { white-space: pre-wrap; word-break: break-all; overflow-wrap: anywhere; + line-height: inherit; /* needed for inline code preview in markup */ } .blame .code-inner { diff --git a/web_src/css/form.css b/web_src/css/form.css index 2a976c056d..a8f73b6b66 100644 --- a/web_src/css/form.css +++ b/web_src/css/form.css @@ -249,21 +249,6 @@ textarea:focus, .user.signup form .optional .title { margin-left: 250px !important; } - .user.activate form .inline.field > input, - .user.forgot.password form .inline.field > input, - .user.reset.password form .inline.field > input, - .user.link-account form .inline.field > input, - .user.signin form .inline.field > input, - .user.signup form .inline.field > input, - .user.activate form .inline.field > textarea, - .user.forgot.password form .inline.field > textarea, - .user.reset.password form .inline.field > textarea, - .user.link-account form .inline.field > textarea, - .user.signin form .inline.field > textarea, - .user.signup form .inline.field > textarea, - .oauth-login-link { - width: 50%; - } } @media (max-width: 767.98px) { @@ -310,14 +295,7 @@ textarea:focus, .user.reset.password form .inline.field > label, .user.link-account form .inline.field > label, .user.signin form .inline.field > label, - .user.signup form .inline.field > label, - .user.activate form input, - .user.forgot.password form input, - .user.reset.password form input, - .user.link-account form input, - .user.signin form input, - .user.signup form input, - .oauth-login-link { + .user.signup form .inline.field > label { width: 100% !important; } } @@ -435,9 +413,9 @@ textarea:focus, .repository.new.repo form label, .repository.new.migrate form label, .repository.new.fork form label, - .repository.new.repo form input, - .repository.new.migrate form input, - .repository.new.fork form input, + .repository.new.repo form .inline.field > input, + .repository.new.migrate form .inline.field > input, + .repository.new.fork form .inline.field > input, .repository.new.fork form .field a, .repository.new.repo form .selection.dropdown, .repository.new.migrate form .selection.dropdown, diff --git a/web_src/css/modules/checkbox.css b/web_src/css/modules/checkbox.css index 9238e0b3f3..d3e45714a4 100644 --- a/web_src/css/modules/checkbox.css +++ b/web_src/css/modules/checkbox.css @@ -20,7 +20,7 @@ input[type="radio"] { .ui.checkbox input[type="checkbox"], .ui.checkbox input[type="radio"] { position: absolute; - top: 0; + top: 1px; left: 0; width: var(--checkbox-size); height: var(--checkbox-size); diff --git a/web_src/css/modules/container.css b/web_src/css/modules/container.css index dc854f89d0..f394d6c06d 100644 --- a/web_src/css/modules/container.css +++ b/web_src/css/modules/container.css @@ -49,30 +49,11 @@ /* overwrite width of containers inside the main page content div (div with class "page-content") */ .page-content .ui.ui.ui.container:not(.fluid) { width: 1280px; - max-width: calc(100% - 64px); + max-width: calc(100% - calc(2 * var(--page-margin-x))); margin-left: auto; margin-right: auto; } .ui.container.fluid.padded { - padding: 0 32px; -} - -/* enable fluid page widths for medium size viewports */ -@media (min-width: 768px) and (max-width: 1200px) { - .page-content .ui.ui.ui.container:not(.fluid) { - max-width: calc(100% - 32px); - } - .ui.container.fluid.padded { - padding: 0 16px; - } -} - -@media (max-width: 767.98px) { - .page-content .ui.ui.ui.container:not(.fluid) { - max-width: calc(100% - 16px); - } - .ui.container.fluid.padded { - padding: 0 8px; - } + padding: 0 var(--page-margin-x); } diff --git a/web_src/css/modules/flexcontainer.css b/web_src/css/modules/flexcontainer.css index 0b559f1e7d..1ca513687f 100644 --- a/web_src/css/modules/flexcontainer.css +++ b/web_src/css/modules/flexcontainer.css @@ -2,7 +2,8 @@ .flex-container { display: flex !important; - gap: 16px; + gap: var(--page-spacing); + margin-top: var(--page-spacing); } .flex-container-nav { diff --git a/web_src/css/repo.css b/web_src/css/repo.css index 28e78730d3..53766ac0f9 100644 --- a/web_src/css/repo.css +++ b/web_src/css/repo.css @@ -177,12 +177,44 @@ } } -.repository.file.list .repo-path { - word-break: break-word; +.commit-summary { + flex: 1; + overflow-wrap: anywhere; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; } -.repository.file.list #repo-files-table { - table-layout: fixed; +.commit-header .commit-summary, +td .commit-summary { + white-space: normal; +} + +.latest-commit { + display: flex; + flex: 1; + align-items: center; + overflow: hidden; + text-overflow: ellipsis; +} + +@media (max-width: 767.98px) { + .latest-commit .sha { + display: none; + } + .latest-commit .commit-summary { + margin-left: 8px; + } +} + +.repo-path { + display: flex; + overflow-wrap: anywhere; +} + +/* this is what limits the commit table width to a value that works on all viewport sizes */ +#repo-files-table th:first-of-type { + max-width: calc(calc(min(100vw, 1280px)) - 145px - calc(2 * var(--page-margin-x))); } .repository.file.list #repo-files-table thead th { @@ -262,7 +294,6 @@ } .repository.file.list #repo-files-table td.age { - width: 120px; color: var(--color-text-light-1); } @@ -1223,10 +1254,6 @@ margin: 0; } -.repository #commits-table td.message { - text-overflow: unset; -} - .repository #commits-table.ui.basic.striped.table tbody tr:nth-child(2n) { background-color: var(--color-light) !important; } @@ -2153,6 +2180,20 @@ display: inline-block !important; } +.commit-header-buttons { + display: flex; + gap: 4px; + align-items: flex-start; + white-space: nowrap; +} + +@media (max-width: 767.98px) { + .commit-header-buttons { + flex-direction: column; + align-items: stretch; + } +} + .settings.webhooks .list > .item:not(:first-child), .settings.githooks .list > .item:not(:first-child), .settings.actions .list > .item:not(:first-child) { @@ -2469,7 +2510,7 @@ tbody.commit-list { .author-wrapper { overflow: hidden; text-overflow: ellipsis; - max-width: calc(100% - 50px); + max-width: 100%; display: inline-block; vertical-align: middle; } @@ -2494,10 +2535,6 @@ tbody.commit-list { tr.commit-list { width: 100%; } - th .message-wrapper { - display: block; - max-width: calc(100vw - 70px); - } .author-wrapper { max-width: 80px; } @@ -2507,27 +2544,18 @@ tbody.commit-list { tr.commit-list { width: 723px; } - th .message-wrapper { - max-width: 120px; - } } @media (min-width: 992px) and (max-width: 1200px) { tr.commit-list { width: 933px; } - th .message-wrapper { - max-width: 350px; - } } @media (min-width: 1201px) { tr.commit-list { width: 1127px; } - th .message-wrapper { - max-width: 525px; - } } .commit-list .commit-status-link { @@ -2854,7 +2882,7 @@ tbody.commit-list { .repository.file.list #repo-files-table .entry td.message, .repository.file.list #repo-files-table .commit-list td.message, .repository.file.list #repo-files-table .entry span.commit-summary, - .repository.file.list #repo-files-table .commit-list span.commit-summary { + .repository.file.list #repo-files-table .commit-list tr span.commit-summary { display: none !important; } .repository.view.issue .comment-list .timeline, diff --git a/web_src/css/themes/theme-gitea-dark.css b/web_src/css/themes/theme-gitea-dark.css index 07e217742d..ed6718e40c 100644 --- a/web_src/css/themes/theme-gitea-dark.css +++ b/web_src/css/themes/theme-gitea-dark.css @@ -65,7 +65,7 @@ --color-console-fg-subtle: #bec4c8; --color-console-bg: #171b1e; --color-console-border: #2e353b; - --color-console-hover-bg: #e8e8ff16; + --color-console-hover-bg: #292d31; --color-console-active-bg: #2e353b; --color-console-menu-bg: #252b30; --color-console-menu-border: #424b51; diff --git a/web_src/css/themes/theme-gitea-light.css b/web_src/css/themes/theme-gitea-light.css index 2741e0e0bd..b10ad7d840 100644 --- a/web_src/css/themes/theme-gitea-light.css +++ b/web_src/css/themes/theme-gitea-light.css @@ -63,12 +63,12 @@ /* console colors - used for actions console and console files */ --color-console-fg: #f8f8f9; --color-console-fg-subtle: #bec4c8; - --color-console-bg: #181b1d; - --color-console-border: #313538; - --color-console-hover-bg: #ffffff16; - --color-console-active-bg: #313538; - --color-console-menu-bg: #272b2e; - --color-console-menu-border: #464a4d; + --color-console-bg: #171b1e; + --color-console-border: #2e353b; + --color-console-hover-bg: #292d31; + --color-console-active-bg: #2e353b; + --color-console-menu-bg: #252b30; + --color-console-menu-border: #424b51; /* named colors */ --color-red: #db2828; --color-orange: #f2711c; diff --git a/web_src/js/components/RepoActionView.vue b/web_src/js/components/RepoActionView.vue index f10694cde0..378f726688 100644 --- a/web_src/js/components/RepoActionView.vue +++ b/web_src/js/components/RepoActionView.vue @@ -526,8 +526,16 @@ export function initRepositoryActionView() { .action-summary { display: flex; + flex-wrap: wrap; gap: 5px; - margin: 0 0 0 28px; + margin-left: 28px; +} + +@media (max-width: 767.98px) { + .action-commit-summary { + margin-left: 0; + margin-top: 8px; + } } /* ================ */ @@ -540,6 +548,14 @@ export function initRepositoryActionView() { top: 12px; max-height: 100vh; overflow-y: auto; + background: var(--color-body); + z-index: 2; /* above .job-info-header */ +} + +@media (max-width: 767.98px) { + .action-view-left { + position: static; /* can not sticky because multiple jobs would overlap into right view */ + } } .job-artifacts-title { @@ -701,7 +717,9 @@ export function initRepositoryActionView() { position: sticky; top: 0; height: 60px; - z-index: 1; + z-index: 1; /* above .job-step-container */ + background: var(--color-console-bg); + border-radius: 3px; } .job-info-header:has(+ .job-step-container) { @@ -739,7 +757,7 @@ export function initRepositoryActionView() { .job-step-container .job-step-summary.step-expandable:hover { color: var(--color-console-fg); - background-color: var(--color-console-hover-bg); + background: var(--color-console-hover-bg); } .job-step-container .job-step-summary .step-summary-msg { @@ -757,17 +775,15 @@ export function initRepositoryActionView() { top: 60px; } -@media (max-width: 768px) { +@media (max-width: 767.98px) { .action-view-body { flex-direction: column; } .action-view-left, .action-view-right { width: 100%; } - .action-view-left { max-width: none; - overflow-y: hidden; } } diff --git a/web_src/js/features/admin/common.js b/web_src/js/features/admin/common.js index f388b1122e..b35502d52f 100644 --- a/web_src/js/features/admin/common.js +++ b/web_src/js/features/admin/common.js @@ -207,13 +207,13 @@ export function initAdminCommon() { // Notice if (document.querySelector('.admin.notice')) { - const $detailModal = document.getElementById('detail-modal'); + const detailModal = document.getElementById('detail-modal'); // Attach view detail modals $('.view-detail').on('click', function () { - $detailModal.find('.content pre').text($(this).parents('tr').find('.notice-description').text()); - $detailModal.find('.sub.header').text(this.closest('tr')?.querySelector('relative-time')?.getAttribute('title')); - $detailModal.modal('show'); + const description = this.closest('tr').querySelector('.notice-description').textContent; + detailModal.querySelector('.content pre').textContent = description; + $(detailModal).modal('show'); return false; }); diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index bb45c6ae57..1438caeb60 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -435,12 +435,10 @@ export function initRepoPullRequestReview() { offset += $('.diff-detail-box').outerHeight() + $(diffHeader).outerHeight(); } - document.getElementById(`show-outdated-${id}`).classList.add('tw-hidden'); - document.getElementById(`code-comments-${id}`).classList.remove('tw-hidden'); - document.getElementById(`code-preview-${id}`).classList.remove('tw-hidden'); - document.getElementById(`hide-outdated-${id}`).classList.remove('tw-hidden'); + hideElem(`#show-outdated-${id}`); + showElem(`#code-comments-${id}, #code-preview-${id}, #hide-outdated-${id}`); // if the comment box is folded, expand it - if (ancestorDiffBox.getAttribute('data-folded') === 'true') { + if (ancestorDiffBox?.getAttribute('data-folded') === 'true') { setFileFolding(ancestorDiffBox, ancestorDiffBox.querySelector('.fold-file'), false); }
- {{template "repo/latest_commit" .}} + +
+
+ {{template "repo/latest_commit" .}} +
+
{{if .LatestCommit}}{{if .LatestCommit.Committer}}{{TimeSince .LatestCommit.Committer.When ctx.Locale}}{{end}}{{end}}