feat: allow any README for .profile (#8798)
		
	closes #1624 Co-authored-by: Maxim Slipenko <maks1ms@altlinux.org> Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/8798 Reviewed-by: Otto <otto@codeberg.org> Co-authored-by: Maxim Slipenko <maks1ms@noreply.codeberg.org> Co-committed-by: Maxim Slipenko <maks1ms@noreply.codeberg.org>
This commit is contained in:
		
					parent
					
						
							
								a87153b089
							
						
					
				
			
			
				commit
				
					
						ed3b70cbb9
					
				
			
		
					 7 changed files with 102 additions and 34 deletions
				
			
		| 
						 | 
				
			
			@ -5,6 +5,8 @@ package org
 | 
			
		|||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	gotemplate "html/template"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
| 
						 | 
				
			
			@ -180,20 +182,30 @@ func prepareOrgProfileReadme(ctx *context.Context, profileGitRepo *git.Repositor
 | 
			
		|||
	} else {
 | 
			
		||||
		defer rc.Close()
 | 
			
		||||
 | 
			
		||||
		if profileContent, err := markdown.RenderReader(&markup.RenderContext{
 | 
			
		||||
			Ctx:     ctx,
 | 
			
		||||
			GitRepo: profileGitRepo,
 | 
			
		||||
			Links: markup.Links{
 | 
			
		||||
				// Pass repo link to markdown render for the full link of media elements.
 | 
			
		||||
				// The profile of default branch would be shown.
 | 
			
		||||
				Base:       profileDbRepo.Link(),
 | 
			
		||||
				BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
 | 
			
		||||
			},
 | 
			
		||||
			Metas: map[string]string{"mode": "document"},
 | 
			
		||||
		}, rc); err != nil {
 | 
			
		||||
			log.Error("failed to RenderString: %v", err)
 | 
			
		||||
		if markupType := markup.Type(profileReadme.Name()); markupType != "" {
 | 
			
		||||
			if profileContent, err := markdown.RenderReader(&markup.RenderContext{
 | 
			
		||||
				Ctx:     ctx,
 | 
			
		||||
				Type:    markupType,
 | 
			
		||||
				GitRepo: profileGitRepo,
 | 
			
		||||
				Links: markup.Links{
 | 
			
		||||
					// Pass repo link to markdown render for the full link of media elements.
 | 
			
		||||
					// The profile of default branch would be shown.
 | 
			
		||||
					Base:       profileDbRepo.Link(),
 | 
			
		||||
					BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
 | 
			
		||||
				},
 | 
			
		||||
				Metas: map[string]string{"mode": "document"},
 | 
			
		||||
			}, rc); err != nil {
 | 
			
		||||
				log.Error("failed to RenderString: %v", err)
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.Data["ProfileReadme"] = profileContent
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.Data["ProfileReadme"] = profileContent
 | 
			
		||||
			content, err := io.ReadAll(rc)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Error("Read readme content failed: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
			ctx.Data["ProfileReadme"] = gotemplate.HTMLEscapeString(util.UnsafeBytesToString(content))
 | 
			
		||||
			ctx.Data["IsProfileReadmePlain"] = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@ import (
 | 
			
		|||
	"forgejo.org/modules/markup/markdown"
 | 
			
		||||
	"forgejo.org/modules/optional"
 | 
			
		||||
	"forgejo.org/modules/setting"
 | 
			
		||||
	"forgejo.org/routers/web/repo"
 | 
			
		||||
	"forgejo.org/services/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +105,22 @@ func FindUserProfileReadme(ctx *context.Context, doer *user_model.User) (profile
 | 
			
		|||
				if commit, err := profileGitRepo.GetBranchCommit(profileDbRepo.DefaultBranch); err != nil {
 | 
			
		||||
					log.Error("FindUserProfileReadme failed to GetBranchCommit: %v", err)
 | 
			
		||||
				} else {
 | 
			
		||||
					profileReadmeBlob, _ = commit.GetBlobByFoldedPath("README.md")
 | 
			
		||||
					tree, err := commit.SubTree("")
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						log.Error("FindUserProfileReadme failed to get SubTree: %v", err)
 | 
			
		||||
					} else {
 | 
			
		||||
						entries, err := tree.ListEntries()
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							log.Error("FindUserProfileReadme failed to list entries: %v", err)
 | 
			
		||||
						} else {
 | 
			
		||||
							_, readmeEntry, err := repo.FindReadmeFileInEntries(ctx, entries, true)
 | 
			
		||||
							if err != nil {
 | 
			
		||||
								log.Error("FindUserProfileReadme failed to find readme in entries: %v", err)
 | 
			
		||||
							} else if readmeEntry != nil {
 | 
			
		||||
								profileReadmeBlob = readmeEntry.Blob()
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,8 @@ package user
 | 
			
		|||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	gotemplate "html/template"
 | 
			
		||||
	"io"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
| 
						 | 
				
			
			@ -269,23 +271,33 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileDb
 | 
			
		|||
		} else {
 | 
			
		||||
			defer rc.Close()
 | 
			
		||||
 | 
			
		||||
			if profileContent, err := markdown.RenderReader(&markup.RenderContext{
 | 
			
		||||
				Ctx:     ctx,
 | 
			
		||||
				GitRepo: profileGitRepo,
 | 
			
		||||
				Links: markup.Links{
 | 
			
		||||
					// Give the repo link 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
 | 
			
		||||
					Base:       profileDbRepo.Link(),
 | 
			
		||||
					BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
 | 
			
		||||
				},
 | 
			
		||||
				Metas: map[string]string{"mode": "document"},
 | 
			
		||||
			}, rc); err != nil {
 | 
			
		||||
				log.Error("failed to RenderString: %v", err)
 | 
			
		||||
			if markupType := markup.Type(profileReadme.Name()); markupType != "" {
 | 
			
		||||
				if profileContent, err := markdown.RenderReader(&markup.RenderContext{
 | 
			
		||||
					Ctx:     ctx,
 | 
			
		||||
					Type:    markupType,
 | 
			
		||||
					GitRepo: profileGitRepo,
 | 
			
		||||
					Links: markup.Links{
 | 
			
		||||
						// Give the repo link 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
 | 
			
		||||
						Base:       profileDbRepo.Link(),
 | 
			
		||||
						BranchPath: path.Join("branch", util.PathEscapeSegments(profileDbRepo.DefaultBranch)),
 | 
			
		||||
					},
 | 
			
		||||
					Metas: map[string]string{"mode": "document"},
 | 
			
		||||
				}, rc); err != nil {
 | 
			
		||||
					log.Error("failed to RenderString: %v", err)
 | 
			
		||||
				} else {
 | 
			
		||||
					ctx.Data["ProfileReadme"] = profileContent
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.Data["ProfileReadme"] = profileContent
 | 
			
		||||
				content, err := io.ReadAll(rc)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					log.Error("Read readme content failed: %v", err)
 | 
			
		||||
				}
 | 
			
		||||
				ctx.Data["ProfileReadme"] = gotemplate.HTMLEscapeString(util.UnsafeBytesToString(content))
 | 
			
		||||
				ctx.Data["IsProfileReadmePlain"] = true
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	default: // default to "repositories"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,13 @@
 | 
			
		|||
		<div class="ui mobile reversed stackable grid">
 | 
			
		||||
			<div class="ui {{if .ShowMemberAndTeamTab}}eleven wide{{end}} column">
 | 
			
		||||
				{{if .ProfileReadme}}
 | 
			
		||||
					<div id="readme_profile" class="markup">{{.ProfileReadme}}</div>
 | 
			
		||||
					<div id="readme_profile" class="{{if not .IsProfileReadmePlain}}markup{{end}}">
 | 
			
		||||
					{{if .IsProfileReadmePlain}}
 | 
			
		||||
						<pre>{{.ProfileReadme}}</pre>
 | 
			
		||||
					{{else}}
 | 
			
		||||
						{{.ProfileReadme}}
 | 
			
		||||
					{{end}}
 | 
			
		||||
					</div>
 | 
			
		||||
				{{end}}
 | 
			
		||||
				{{template "shared/repo_search" .}}
 | 
			
		||||
				{{template "explore/repo_list" .}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -51,7 +51,13 @@
 | 
			
		|||
				{{else if eq .TabName "followers"}}
 | 
			
		||||
					{{template "repo/user_cards" .}}
 | 
			
		||||
				{{else if eq .TabName "overview"}}
 | 
			
		||||
					<div id="readme_profile" class="markup">{{.ProfileReadme}}</div>
 | 
			
		||||
					<div id="readme_profile" class="{{if not .IsProfileReadmePlain}}markup{{end}}">
 | 
			
		||||
					{{if .IsProfileReadmePlain}}
 | 
			
		||||
						<pre>{{.ProfileReadme}}</pre>
 | 
			
		||||
					{{else}}
 | 
			
		||||
						{{.ProfileReadme}}
 | 
			
		||||
					{{end}}
 | 
			
		||||
					</div>
 | 
			
		||||
				{{else}}
 | 
			
		||||
					{{template "shared/repo_search" .}}
 | 
			
		||||
					{{template "explore/repo_list" .}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,15 @@ func TestOrgProfile(t *testing.T) {
 | 
			
		|||
		checkReadme(t, "README.md", "README.md", 1)
 | 
			
		||||
		checkReadme(t, "readme.md", "readme.md", 1)
 | 
			
		||||
		checkReadme(t, "ReadMe.mD", "ReadMe.mD", 1)
 | 
			
		||||
		checkReadme(t, "readme.org does not render", "README.org", 0)
 | 
			
		||||
		checkReadme(t, "readme.org", "README.org", 1)
 | 
			
		||||
		checkReadme(t, "README.en-us.md", "README.en-us.md", 1)
 | 
			
		||||
		checkReadme(t, "README.en.md", "README.en.md", 1)
 | 
			
		||||
		checkReadme(t, "README.txt", "README.txt", 1)
 | 
			
		||||
		checkReadme(t, "README", "README", 1)
 | 
			
		||||
		checkReadme(t, "README.mdown", "README.mdown", 1)
 | 
			
		||||
		checkReadme(t, "README.i18n.md", "README.i18n.md", 1)
 | 
			
		||||
		checkReadme(t, "readmee", "readmee", 0)
 | 
			
		||||
		checkReadme(t, "test.md", "test.md", 0)
 | 
			
		||||
 | 
			
		||||
		t.Run("readme-size", func(t *testing.T) {
 | 
			
		||||
			defer tests.PrintCurrentTest(t)()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -64,7 +64,15 @@ func TestUserProfile(t *testing.T) {
 | 
			
		|||
		checkReadme(t, "README.md", "README.md", 1)
 | 
			
		||||
		checkReadme(t, "readme.md", "readme.md", 1)
 | 
			
		||||
		checkReadme(t, "ReadMe.mD", "ReadMe.mD", 1)
 | 
			
		||||
		checkReadme(t, "readme.org does not render", "README.org", 0)
 | 
			
		||||
		checkReadme(t, "readme.org", "README.org", 1)
 | 
			
		||||
		checkReadme(t, "README.en-us.md", "README.en-us.md", 1)
 | 
			
		||||
		checkReadme(t, "README.en.md", "README.en.md", 1)
 | 
			
		||||
		checkReadme(t, "README.txt", "README.txt", 1)
 | 
			
		||||
		checkReadme(t, "README", "README", 1)
 | 
			
		||||
		checkReadme(t, "README.mdown", "README.mdown", 1)
 | 
			
		||||
		checkReadme(t, "README.i18n.md", "README.i18n.md", 1)
 | 
			
		||||
		checkReadme(t, "readmee", "readmee", 0)
 | 
			
		||||
		checkReadme(t, "test.md", "test.md", 0)
 | 
			
		||||
 | 
			
		||||
		t.Run("readme-size", func(t *testing.T) {
 | 
			
		||||
			defer tests.PrintCurrentTest(t)()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue