mirror of
https://github.com/go-gitea/gitea
synced 2025-12-07 13:28:25 +00:00
Merge branch 'main' into allow-force-push-protected-branches
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"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/context"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
|
||||
const (
|
||||
tplDashboard base.TplName = "admin/dashboard"
|
||||
tplSelfCheck base.TplName = "admin/self_check"
|
||||
tplCron base.TplName = "admin/cron"
|
||||
tplQueue base.TplName = "admin/queue"
|
||||
tplStacktrace base.TplName = "admin/stacktrace"
|
||||
@@ -172,6 +174,33 @@ func DashboardPost(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func SelfCheck(ctx *context.Context) {
|
||||
ctx.Data["PageIsAdminSelfCheck"] = true
|
||||
r, err := db.CheckCollationsDefaultEngine()
|
||||
if err != nil {
|
||||
ctx.Flash.Error(fmt.Sprintf("CheckCollationsDefaultEngine: %v", err), true)
|
||||
}
|
||||
|
||||
if r != nil {
|
||||
ctx.Data["DatabaseType"] = setting.Database.Type
|
||||
ctx.Data["DatabaseCheckResult"] = r
|
||||
hasProblem := false
|
||||
if !r.CollationEquals(r.DatabaseCollation, r.ExpectedCollation) {
|
||||
ctx.Data["DatabaseCheckCollationMismatch"] = true
|
||||
hasProblem = true
|
||||
}
|
||||
if !r.IsCollationCaseSensitive(r.DatabaseCollation) {
|
||||
ctx.Data["DatabaseCheckCollationCaseInsensitive"] = true
|
||||
hasProblem = true
|
||||
}
|
||||
ctx.Data["DatabaseCheckInconsistentCollationColumns"] = r.InconsistentCollationColumns
|
||||
hasProblem = hasProblem || len(r.InconsistentCollationColumns) > 0
|
||||
|
||||
ctx.Data["DatabaseCheckHasProblems"] = hasProblem
|
||||
}
|
||||
ctx.HTML(http.StatusOK, tplSelfCheck)
|
||||
}
|
||||
|
||||
func CronTasks(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("admin.monitor.cron")
|
||||
ctx.Data["PageIsAdminMonitorCron"] = true
|
||||
|
||||
@@ -58,4 +58,11 @@ func MonitorDiagnosis(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
_ = pprof.Lookup("goroutine").WriteTo(f, 1)
|
||||
|
||||
f, err = zipWriter.CreateHeader(&zip.FileHeader{Name: "heap.dat", Method: zip.Deflate, Modified: time.Now()})
|
||||
if err != nil {
|
||||
ctx.ServerError("Failed to create zip file", err)
|
||||
return
|
||||
}
|
||||
_ = pprof.Lookup("heap").WriteTo(f, 0)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
@@ -55,7 +56,7 @@ func DeleteNotices(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
if err := system_model.DeleteNoticesByIDs(ctx, ids); err != nil {
|
||||
if err := db.DeleteByIDs[system_model.Notice](ctx, ids...); err != nil {
|
||||
ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error())
|
||||
ctx.Status(http.StatusInternalServerError)
|
||||
} else {
|
||||
|
||||
@@ -45,10 +45,6 @@ const (
|
||||
|
||||
// autoSignIn reads cookie and try to auto-login.
|
||||
func autoSignIn(ctx *context.Context) (bool, error) {
|
||||
if !db.HasEngine {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
isSucceed := false
|
||||
defer func() {
|
||||
if !isSucceed {
|
||||
@@ -145,7 +141,11 @@ func CheckAutoLogin(ctx *context.Context) bool {
|
||||
|
||||
if isSucceed {
|
||||
middleware.DeleteRedirectToCookie(ctx.Resp)
|
||||
ctx.RedirectToFirst(redirectTo, setting.AppSubURL+string(setting.LandingPageURL))
|
||||
nextRedirectTo := setting.AppSubURL + string(setting.LandingPageURL)
|
||||
if setting.LandingPageURL == setting.LandingPageLogin {
|
||||
nextRedirectTo = setting.AppSubURL + "/" // do not cycle-redirect to the login page
|
||||
}
|
||||
ctx.RedirectToFirst(redirectTo, nextRedirectTo)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -368,14 +368,14 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
|
||||
return setting.AppSubURL + "/"
|
||||
}
|
||||
|
||||
func getUserName(gothUser *goth.User) string {
|
||||
func getUserName(gothUser *goth.User) (string, error) {
|
||||
switch setting.OAuth2Client.Username {
|
||||
case setting.OAuth2UsernameEmail:
|
||||
return strings.Split(gothUser.Email, "@")[0]
|
||||
return user_model.NormalizeUserName(strings.Split(gothUser.Email, "@")[0])
|
||||
case setting.OAuth2UsernameNickname:
|
||||
return gothUser.NickName
|
||||
return user_model.NormalizeUserName(gothUser.NickName)
|
||||
default: // OAuth2UsernameUserid
|
||||
return gothUser.UserID
|
||||
return gothUser.UserID, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,11 @@ func LinkAccount(ctx *context.Context) {
|
||||
}
|
||||
|
||||
gu, _ := gothUser.(goth.User)
|
||||
uname := getUserName(&gu)
|
||||
uname, err := getUserName(&gu)
|
||||
if err != nil {
|
||||
ctx.ServerError("UserSignIn", err)
|
||||
return
|
||||
}
|
||||
email := gu.Email
|
||||
ctx.Data["user_name"] = uname
|
||||
ctx.Data["email"] = email
|
||||
|
||||
@@ -970,8 +970,13 @@ func SignInOAuthCallback(ctx *context.Context) {
|
||||
ctx.ServerError("CreateUser", err)
|
||||
return
|
||||
}
|
||||
uname, err := getUserName(&gothUser)
|
||||
if err != nil {
|
||||
ctx.ServerError("UserSignIn", err)
|
||||
return
|
||||
}
|
||||
u = &user_model.User{
|
||||
Name: getUserName(&gothUser),
|
||||
Name: uname,
|
||||
FullName: gothUser.Name,
|
||||
Email: gothUser.Email,
|
||||
LoginType: auth.OAuth2,
|
||||
|
||||
+11
-11
@@ -28,16 +28,16 @@ func requireSignIn(ctx *context.Context) {
|
||||
|
||||
func gitHTTPRouters(m *web.Route) {
|
||||
m.Group("", func() {
|
||||
m.PostOptions("/git-upload-pack", repo.ServiceUploadPack)
|
||||
m.PostOptions("/git-receive-pack", repo.ServiceReceivePack)
|
||||
m.GetOptions("/info/refs", repo.GetInfoRefs)
|
||||
m.GetOptions("/HEAD", repo.GetTextFile("HEAD"))
|
||||
m.GetOptions("/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
|
||||
m.GetOptions("/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
|
||||
m.GetOptions("/objects/info/packs", repo.GetInfoPacks)
|
||||
m.GetOptions("/objects/info/{file:[^/]*}", repo.GetTextFile(""))
|
||||
m.GetOptions("/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
||||
m.GetOptions("/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
||||
m.Methods("POST,OPTIONS", "/git-upload-pack", repo.ServiceUploadPack)
|
||||
m.Methods("POST,OPTIONS", "/git-receive-pack", repo.ServiceReceivePack)
|
||||
m.Methods("GET,OPTIONS", "/info/refs", repo.GetInfoRefs)
|
||||
m.Methods("GET,OPTIONS", "/HEAD", repo.GetTextFile("HEAD"))
|
||||
m.Methods("GET,OPTIONS", "/objects/info/alternates", repo.GetTextFile("objects/info/alternates"))
|
||||
m.Methods("GET,OPTIONS", "/objects/info/http-alternates", repo.GetTextFile("objects/info/http-alternates"))
|
||||
m.Methods("GET,OPTIONS", "/objects/info/packs", repo.GetInfoPacks)
|
||||
m.Methods("GET,OPTIONS", "/objects/info/{file:[^/]*}", repo.GetTextFile(""))
|
||||
m.Methods("GET,OPTIONS", "/objects/{head:[0-9a-f]{2}}/{hash:[0-9a-f]{38}}", repo.GetLooseObject)
|
||||
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.pack", repo.GetPackFile)
|
||||
m.Methods("GET,OPTIONS", "/objects/pack/pack-{file:[0-9a-f]{40}}.idx", repo.GetIdxFile)
|
||||
}, ignSignInAndCsrf, requireSignIn, repo.HTTPGitEnabledHandler, repo.CorsHandler(), context_service.UserAssignmentWeb())
|
||||
}
|
||||
|
||||
@@ -33,10 +33,6 @@ func DummyOK(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func DummyBadRequest(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func RobotsTxt(w http.ResponseWriter, req *http.Request) {
|
||||
robotsTxt := util.FilePathJoinAbs(setting.CustomPath, "public/robots.txt")
|
||||
if ok, _ := util.IsExist(robotsTxt); !ok {
|
||||
|
||||
+11
-6
@@ -18,6 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/markup/markdown"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
||||
)
|
||||
|
||||
@@ -157,14 +158,14 @@ func Home(ctx *context.Context) {
|
||||
|
||||
ctx.Data["ShowMemberAndTeamTab"] = ctx.Org.IsMember || len(members) > 0
|
||||
|
||||
profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
|
||||
profileDbRepo, profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
|
||||
defer profileClose()
|
||||
prepareOrgProfileReadme(ctx, profileGitRepo, profileReadmeBlob)
|
||||
prepareOrgProfileReadme(ctx, profileGitRepo, profileDbRepo, profileReadmeBlob)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplOrgHome)
|
||||
}
|
||||
|
||||
func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repository, profileReadme *git.Blob) {
|
||||
func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repository, profileDbRepo *repo_model.Repository, profileReadme *git.Blob) {
|
||||
if profileGitRepo == nil || profileReadme == nil {
|
||||
return
|
||||
}
|
||||
@@ -172,10 +173,14 @@ func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repositor
|
||||
if bytes, err := profileReadme.GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil {
|
||||
log.Error("failed to GetBlobContent: %v", err)
|
||||
} else {
|
||||
// Pass URLPrefix to markdown render for the full link of media elements.
|
||||
// The profile of default branch would be shown.
|
||||
prefix := profileDbRepo.Link() + "/src/branch/" + util.PathEscapeSegments(profileDbRepo.DefaultBranch)
|
||||
if profileContent, err := markdown.RenderString(&markup.RenderContext{
|
||||
Ctx: ctx,
|
||||
GitRepo: profileGitRepo,
|
||||
Metas: map[string]string{"mode": "document"},
|
||||
Ctx: ctx,
|
||||
GitRepo: profileGitRepo,
|
||||
URLPrefix: prefix,
|
||||
Metas: map[string]string{"mode": "document"},
|
||||
}, bytes); err != nil {
|
||||
log.Error("failed to RenderString: %v", err)
|
||||
} else {
|
||||
|
||||
@@ -125,7 +125,7 @@ func RefBlame(ctx *context.Context) {
|
||||
}
|
||||
|
||||
type blameResult struct {
|
||||
Parts []git.BlamePart
|
||||
Parts []*git.BlamePart
|
||||
UsesIgnoreRevs bool
|
||||
FaultyIgnoreRevsFile bool
|
||||
}
|
||||
@@ -175,7 +175,9 @@ func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, fil
|
||||
func fillBlameResult(br *git.BlameReader, r *blameResult) error {
|
||||
r.UsesIgnoreRevs = br.UsesIgnoreRevs()
|
||||
|
||||
r.Parts = make([]git.BlamePart, 0, 5)
|
||||
previousHelper := make(map[string]*git.BlamePart)
|
||||
|
||||
r.Parts = make([]*git.BlamePart, 0, 5)
|
||||
for {
|
||||
blamePart, err := br.NextPart()
|
||||
if err != nil {
|
||||
@@ -184,13 +186,23 @@ func fillBlameResult(br *git.BlameReader, r *blameResult) error {
|
||||
if blamePart == nil {
|
||||
break
|
||||
}
|
||||
r.Parts = append(r.Parts, *blamePart)
|
||||
|
||||
if prev, ok := previousHelper[blamePart.Sha]; ok {
|
||||
if blamePart.PreviousSha == "" {
|
||||
blamePart.PreviousSha = prev.PreviousSha
|
||||
blamePart.PreviousPath = prev.PreviousPath
|
||||
}
|
||||
} else {
|
||||
previousHelper[blamePart.Sha] = blamePart
|
||||
}
|
||||
|
||||
r.Parts = append(r.Parts, blamePart)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) map[string]*user_model.UserCommit {
|
||||
func processBlameParts(ctx *context.Context, blameParts []*git.BlamePart) map[string]*user_model.UserCommit {
|
||||
// store commit data by SHA to look up avatar info etc
|
||||
commitNames := make(map[string]*user_model.UserCommit)
|
||||
// and as blameParts can reference the same commits multiple
|
||||
@@ -232,7 +244,7 @@ func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) map[str
|
||||
return commitNames
|
||||
}
|
||||
|
||||
func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames map[string]*user_model.UserCommit) {
|
||||
func renderBlame(ctx *context.Context, blameParts []*git.BlamePart, commitNames map[string]*user_model.UserCommit) {
|
||||
repoLink := ctx.Repo.RepoLink
|
||||
|
||||
language := ""
|
||||
|
||||
@@ -653,7 +653,15 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C
|
||||
if pb != nil && pb.EnableStatusCheck {
|
||||
ctx.Data["is_context_required"] = func(context string) bool {
|
||||
for _, c := range pb.StatusCheckContexts {
|
||||
if gp, err := glob.Compile(c); err == nil && gp.Match(context) {
|
||||
if c == context {
|
||||
return true
|
||||
}
|
||||
if gp, err := glob.Compile(c); err != nil {
|
||||
// All newly created status_check_contexts are checked to ensure they are valid glob expressions before being stored in the database.
|
||||
// But some old status_check_context created before glob was introduced may be invalid glob expressions.
|
||||
// So log the error here for debugging.
|
||||
log.Error("compile glob %q: %v", c, err)
|
||||
} else if gp.Match(context) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,7 +418,7 @@ func SettingsPost(ctx *context.Context) {
|
||||
Interval: interval,
|
||||
RemoteAddress: remoteAddress,
|
||||
}
|
||||
if err := repo_model.InsertPushMirror(ctx, m); err != nil {
|
||||
if err := db.Insert(ctx, m); err != nil {
|
||||
ctx.ServerError("InsertPushMirror", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -15,9 +15,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
tplRepoVariables base.TplName = "repo/settings/actions"
|
||||
tplOrgVariables base.TplName = "org/settings/actions"
|
||||
tplUserVariables base.TplName = "user/settings/actions"
|
||||
tplRepoVariables base.TplName = "repo/settings/actions"
|
||||
tplOrgVariables base.TplName = "org/settings/actions"
|
||||
tplUserVariables base.TplName = "user/settings/actions"
|
||||
tplAdminVariables base.TplName = "admin/actions"
|
||||
)
|
||||
|
||||
type variablesCtx struct {
|
||||
@@ -26,6 +27,7 @@ type variablesCtx struct {
|
||||
IsRepo bool
|
||||
IsOrg bool
|
||||
IsUser bool
|
||||
IsGlobal bool
|
||||
VariablesTemplate base.TplName
|
||||
RedirectLink string
|
||||
}
|
||||
@@ -33,6 +35,7 @@ type variablesCtx struct {
|
||||
func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
|
||||
if ctx.Data["PageIsRepoSettings"] == true {
|
||||
return &variablesCtx{
|
||||
OwnerID: 0,
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
IsRepo: true,
|
||||
VariablesTemplate: tplRepoVariables,
|
||||
@@ -48,6 +51,7 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
|
||||
}
|
||||
return &variablesCtx{
|
||||
OwnerID: ctx.ContextUser.ID,
|
||||
RepoID: 0,
|
||||
IsOrg: true,
|
||||
VariablesTemplate: tplOrgVariables,
|
||||
RedirectLink: ctx.Org.OrgLink + "/settings/actions/variables",
|
||||
@@ -57,12 +61,23 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) {
|
||||
if ctx.Data["PageIsUserSettings"] == true {
|
||||
return &variablesCtx{
|
||||
OwnerID: ctx.Doer.ID,
|
||||
RepoID: 0,
|
||||
IsUser: true,
|
||||
VariablesTemplate: tplUserVariables,
|
||||
RedirectLink: setting.AppSubURL + "/user/settings/actions/variables",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if ctx.Data["PageIsAdmin"] == true {
|
||||
return &variablesCtx{
|
||||
OwnerID: 0,
|
||||
RepoID: 0,
|
||||
IsGlobal: true,
|
||||
VariablesTemplate: tplAdminVariables,
|
||||
RedirectLink: setting.AppSubURL + "/admin/actions/variables",
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unable to set Variables context")
|
||||
}
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profileGitRepo *git.Repository, profileReadmeBlob *git.Blob, profileClose func()) {
|
||||
func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadmeBlob *git.Blob, profileClose func()) {
|
||||
profileDbRepo, err := repo_model.GetRepositoryByName(ctx, ctx.ContextUser.ID, ".profile")
|
||||
if err == nil {
|
||||
perm, err := access_model.GetUserRepoPermission(ctx, profileDbRepo, doer)
|
||||
@@ -105,7 +105,7 @@ func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profile
|
||||
} else if !repo_model.IsErrRepoNotExist(err) {
|
||||
log.Error("FindUserProfileReadme failed to GetRepositoryByName: %v", err)
|
||||
}
|
||||
return profileGitRepo, profileReadmeBlob, func() {
|
||||
return profileDbRepo, profileGitRepo, profileReadmeBlob, func() {
|
||||
if profileGitRepo != nil {
|
||||
_ = profileGitRepo.Close()
|
||||
}
|
||||
@@ -115,7 +115,7 @@ func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profile
|
||||
func RenderUserHeader(ctx *context.Context) {
|
||||
prepareContextForCommonProfile(ctx)
|
||||
|
||||
_, profileReadmeBlob, profileClose := FindUserProfileReadme(ctx, ctx.Doer)
|
||||
_, _, profileReadmeBlob, profileClose := FindUserProfileReadme(ctx, ctx.Doer)
|
||||
defer profileClose()
|
||||
ctx.Data["HasProfileReadme"] = profileReadmeBlob != nil
|
||||
}
|
||||
|
||||
@@ -64,17 +64,17 @@ func userProfile(ctx *context.Context) {
|
||||
ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data)
|
||||
}
|
||||
|
||||
profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
|
||||
profileDbRepo, profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx, ctx.Doer)
|
||||
defer profileClose()
|
||||
|
||||
showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID)
|
||||
prepareUserProfileTabData(ctx, showPrivate, profileGitRepo, profileReadmeBlob)
|
||||
prepareUserProfileTabData(ctx, showPrivate, profileDbRepo, profileGitRepo, profileReadmeBlob)
|
||||
// call PrepareContextForProfileBigAvatar later to avoid re-querying the NumFollowers & NumFollowing
|
||||
shared_user.PrepareContextForProfileBigAvatar(ctx)
|
||||
ctx.HTML(http.StatusOK, tplProfile)
|
||||
}
|
||||
|
||||
func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGitRepo *git.Repository, profileReadme *git.Blob) {
|
||||
func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDbRepo *repo_model.Repository, profileGitRepo *git.Repository, profileReadme *git.Blob) {
|
||||
// if there is a profile readme, default to "overview" page, otherwise, default to "repositories" page
|
||||
// if there is not a profile readme, the overview tab should be treated as the repositories tab
|
||||
tab := ctx.FormString("tab")
|
||||
@@ -233,10 +233,18 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGi
|
||||
if bytes, err := profileReadme.GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil {
|
||||
log.Error("failed to GetBlobContent: %v", err)
|
||||
} else {
|
||||
// Give the URLPrefix to the markdown render for the full link of media element.
|
||||
// the media link usually be like /[user]/[repoName]/media/branch/[branchName],
|
||||
// Eg. /Tom/.profile/media/branch/main
|
||||
// The branch shown on the profile page is the default branch, this need to be in sync with doc, see:
|
||||
// https://docs.gitea.com/usage/profile-readme
|
||||
|
||||
prefix := profileDbRepo.Link() + "/src/branch/" + util.PathEscapeSegments(profileDbRepo.DefaultBranch)
|
||||
if profileContent, err := markdown.RenderString(&markup.RenderContext{
|
||||
Ctx: ctx,
|
||||
GitRepo: profileGitRepo,
|
||||
Metas: map[string]string{"mode": "document"},
|
||||
Ctx: ctx,
|
||||
GitRepo: profileGitRepo,
|
||||
URLPrefix: prefix,
|
||||
Metas: map[string]string{"mode": "document"},
|
||||
}, bytes); err != nil {
|
||||
log.Error("failed to RenderString: %v", err)
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/avatars"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
@@ -130,7 +131,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser *
|
||||
ctxUser.UseCustomAvatar = form.Source == forms.AvatarLocal
|
||||
if len(form.Gravatar) > 0 {
|
||||
if form.Avatar != nil {
|
||||
ctxUser.Avatar = base.EncodeMD5(form.Gravatar)
|
||||
ctxUser.Avatar = avatars.HashEmail(form.Gravatar)
|
||||
} else {
|
||||
ctxUser.Avatar = ""
|
||||
}
|
||||
|
||||
+38
-21
@@ -60,13 +60,12 @@ const (
|
||||
GzipMinSize = 1400
|
||||
)
|
||||
|
||||
// CorsHandler return a http handler who set CORS options if enabled by config
|
||||
func CorsHandler() func(next http.Handler) http.Handler {
|
||||
// optionsCorsHandler return a http handler which sets CORS options if enabled by config, it blocks non-CORS OPTIONS requests.
|
||||
func optionsCorsHandler() func(next http.Handler) http.Handler {
|
||||
var corsHandler func(next http.Handler) http.Handler
|
||||
if setting.CORSConfig.Enabled {
|
||||
return cors.Handler(cors.Options{
|
||||
// Scheme: setting.CORSConfig.Scheme, // FIXME: the cors middleware needs scheme option
|
||||
AllowedOrigins: setting.CORSConfig.AllowDomain,
|
||||
// setting.CORSConfig.AllowSubdomain // FIXME: the cors middleware needs allowSubdomain option
|
||||
corsHandler = cors.Handler(cors.Options{
|
||||
AllowedOrigins: setting.CORSConfig.AllowDomain,
|
||||
AllowedMethods: setting.CORSConfig.Methods,
|
||||
AllowCredentials: setting.CORSConfig.AllowCredentials,
|
||||
AllowedHeaders: setting.CORSConfig.Headers,
|
||||
@@ -75,7 +74,23 @@ func CorsHandler() func(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return next
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodOptions {
|
||||
if corsHandler != nil && r.Header.Get("Access-Control-Request-Method") != "" {
|
||||
corsHandler(next).ServeHTTP(w, r)
|
||||
} else {
|
||||
// it should explicitly deny OPTIONS requests if CORS handler is not executed, to avoid the next GET/POST handler being incorrectly called by the OPTIONS request
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
}
|
||||
return
|
||||
}
|
||||
// for non-OPTIONS requests, call the CORS handler to add some related headers like "Vary"
|
||||
if corsHandler != nil {
|
||||
corsHandler(next).ServeHTTP(w, r)
|
||||
} else {
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,7 +233,7 @@ func Routes() *web.Route {
|
||||
routes := web.NewRoute()
|
||||
|
||||
routes.Head("/", misc.DummyOK) // for health check - doesn't need to be passed through gzip handler
|
||||
routes.Methods("GET, HEAD", "/assets/*", CorsHandler(), public.FileHandlerFunc())
|
||||
routes.Methods("GET, HEAD, OPTIONS", "/assets/*", optionsCorsHandler(), public.FileHandlerFunc())
|
||||
routes.Methods("GET, HEAD", "/avatars/*", storageHandler(setting.Avatar.Storage, "avatars", storage.Avatars))
|
||||
routes.Methods("GET, HEAD", "/repo-avatars/*", storageHandler(setting.RepoAvatar.Storage, "repo-avatars", storage.RepoAvatars))
|
||||
routes.Methods("GET, HEAD", "/apple-touch-icon.png", misc.StaticRedirect("/assets/img/apple-touch-icon.png"))
|
||||
@@ -417,7 +432,7 @@ func registerRoutes(m *web.Route) {
|
||||
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo_setting.PackagistHooksEditPost)
|
||||
}
|
||||
|
||||
addSettingVariablesRoutes := func() {
|
||||
addSettingsVariablesRoutes := func() {
|
||||
m.Group("/variables", func() {
|
||||
m.Get("", repo_setting.Variables)
|
||||
m.Post("/new", web.Bind(forms.EditVariableForm{}), repo_setting.VariableCreate)
|
||||
@@ -458,8 +473,8 @@ func registerRoutes(m *web.Route) {
|
||||
m.Get("/change-password", func(ctx *context.Context) {
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
|
||||
})
|
||||
m.Any("/*", CorsHandler(), public.FileHandlerFunc())
|
||||
}, CorsHandler())
|
||||
m.Methods("GET, HEAD", "/*", public.FileHandlerFunc())
|
||||
}, optionsCorsHandler())
|
||||
|
||||
m.Group("/explore", func() {
|
||||
m.Get("", func(ctx *context.Context) {
|
||||
@@ -532,12 +547,11 @@ func registerRoutes(m *web.Route) {
|
||||
// TODO manage redirection
|
||||
m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
|
||||
}, ignSignInAndCsrf, reqSignIn)
|
||||
m.Get("/login/oauth/userinfo", ignSignInAndCsrf, auth.InfoOAuth)
|
||||
m.Options("/login/oauth/access_token", CorsHandler(), misc.DummyBadRequest)
|
||||
m.Post("/login/oauth/access_token", CorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
|
||||
m.Get("/login/oauth/keys", ignSignInAndCsrf, auth.OIDCKeys)
|
||||
m.Options("/login/oauth/introspect", CorsHandler(), misc.DummyBadRequest)
|
||||
m.Post("/login/oauth/introspect", CorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
|
||||
|
||||
m.Methods("GET, OPTIONS", "/login/oauth/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
|
||||
m.Methods("POST, OPTIONS", "/login/oauth/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
|
||||
m.Methods("GET, OPTIONS", "/login/oauth/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys)
|
||||
m.Methods("POST, OPTIONS", "/login/oauth/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
|
||||
|
||||
m.Group("/user/settings", func() {
|
||||
m.Get("", user_setting.Profile)
|
||||
@@ -616,7 +630,7 @@ func registerRoutes(m *web.Route) {
|
||||
m.Get("", user_setting.RedirectToDefaultSetting)
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingVariablesRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
}, actions.MustEnableActions)
|
||||
|
||||
m.Get("/organization", user_setting.Organization)
|
||||
@@ -664,6 +678,8 @@ func registerRoutes(m *web.Route) {
|
||||
m.Get("", admin.Dashboard)
|
||||
m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
|
||||
|
||||
m.Get("/self_check", admin.SelfCheck)
|
||||
|
||||
m.Group("/config", func() {
|
||||
m.Get("", admin.Config)
|
||||
m.Post("", admin.ChangeConfig)
|
||||
@@ -761,13 +777,14 @@ func registerRoutes(m *web.Route) {
|
||||
m.Group("/actions", func() {
|
||||
m.Get("", admin.RedirectToDefaultSetting)
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
})
|
||||
}, adminReq, ctxDataSet("EnableOAuth2", setting.OAuth2.Enable, "EnablePackages", setting.Packages.Enabled))
|
||||
// ***** END: Admin *****
|
||||
|
||||
m.Group("", func() {
|
||||
m.Get("/{username}", user.UsernameSubRoute)
|
||||
m.Get("/attachments/{uuid}", repo.GetAttachment)
|
||||
m.Methods("GET, OPTIONS", "/attachments/{uuid}", optionsCorsHandler(), repo.GetAttachment)
|
||||
}, ignSignIn)
|
||||
|
||||
m.Post("/{username}", reqSignIn, context_service.UserAssignmentWeb(), user.Action)
|
||||
@@ -903,7 +920,7 @@ func registerRoutes(m *web.Route) {
|
||||
m.Get("", org_setting.RedirectToDefaultSetting)
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingVariablesRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
}, actions.MustEnableActions)
|
||||
|
||||
m.Methods("GET,POST", "/delete", org.SettingsDelete)
|
||||
@@ -1082,7 +1099,7 @@ func registerRoutes(m *web.Route) {
|
||||
m.Get("", repo_setting.RedirectToDefaultSetting)
|
||||
addSettingsRunnersRoutes()
|
||||
addSettingsSecretsRoutes()
|
||||
addSettingVariablesRoutes()
|
||||
addSettingsVariablesRoutes()
|
||||
}, actions.MustEnableActions)
|
||||
// the follow handler must be under "settings", otherwise this incomplete repo can't be accessed
|
||||
m.Group("/migrate", func() {
|
||||
|
||||
Reference in New Issue
Block a user