1
1
mirror of https://github.com/go-gitea/gitea synced 2025-07-05 18:17:19 +00:00

Email option to embed images as base64 instead of link (#32061)

ref: #15081
ref: #14037

Documentation: https://gitea.com/gitea/docs/pulls/69

# Example
Content:

![image](https://github.com/user-attachments/assets/e73ebfbe-e329-40f6-9c4a-f73832bbb181)
Result in Email:

![image](https://github.com/user-attachments/assets/55b7019f-e17a-46c3-a374-3b4769d5c2d6)
Result with source code:
(first image is external image, 2nd is now embedded)

![image](https://github.com/user-attachments/assets/8e2804a1-580f-4a69-adcb-cc5d16f7da81)

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
sommerf-lf
2025-03-05 17:29:29 +01:00
committed by GitHub
parent f0f10413ae
commit 7cdde20c73
7 changed files with 328 additions and 28 deletions

View File

@ -102,25 +102,77 @@ func MakeAbsoluteURL(ctx context.Context, link string) string {
return GuessCurrentHostURL(ctx) + "/" + strings.TrimPrefix(link, "/")
}
func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool {
type urlType int
const (
urlTypeGiteaAbsolute urlType = iota + 1 // "http://gitea/subpath"
urlTypeGiteaPageRelative // "/subpath"
urlTypeGiteaSiteRelative // "?key=val"
urlTypeUnknown // "http://other"
)
func detectURLRoutePath(ctx context.Context, s string) (routePath string, ut urlType) {
u, err := url.Parse(s)
if err != nil {
return false
return "", urlTypeUnknown
}
cleanedPath := ""
if u.Path != "" {
cleanedPath := util.PathJoinRelX(u.Path)
if cleanedPath == "" || cleanedPath == "." {
u.Path = "/"
} else {
u.Path = "/" + cleanedPath + "/"
}
cleanedPath = util.PathJoinRelX(u.Path)
cleanedPath = util.Iif(cleanedPath == ".", "", "/"+cleanedPath)
}
if urlIsRelative(s, u) {
return u.Path == "" || strings.HasPrefix(strings.ToLower(u.Path), strings.ToLower(setting.AppSubURL+"/"))
}
if u.Path == "" {
u.Path = "/"
if u.Path == "" {
return "", urlTypeGiteaPageRelative
}
if strings.HasPrefix(strings.ToLower(cleanedPath+"/"), strings.ToLower(setting.AppSubURL+"/")) {
return cleanedPath[len(setting.AppSubURL):], urlTypeGiteaSiteRelative
}
return "", urlTypeUnknown
}
u.Path = cleanedPath + "/"
urlLower := strings.ToLower(u.String())
return strings.HasPrefix(urlLower, strings.ToLower(setting.AppURL)) || strings.HasPrefix(urlLower, strings.ToLower(GuessCurrentAppURL(ctx)))
if strings.HasPrefix(urlLower, strings.ToLower(setting.AppURL)) {
return cleanedPath[len(setting.AppSubURL):], urlTypeGiteaAbsolute
}
guessedCurURL := GuessCurrentAppURL(ctx)
if strings.HasPrefix(urlLower, strings.ToLower(guessedCurURL)) {
return cleanedPath[len(setting.AppSubURL):], urlTypeGiteaAbsolute
}
return "", urlTypeUnknown
}
func IsCurrentGiteaSiteURL(ctx context.Context, s string) bool {
_, ut := detectURLRoutePath(ctx, s)
return ut != urlTypeUnknown
}
type GiteaSiteURL struct {
RoutePath string
OwnerName string
RepoName string
RepoSubPath string
}
func ParseGiteaSiteURL(ctx context.Context, s string) *GiteaSiteURL {
routePath, ut := detectURLRoutePath(ctx, s)
if ut == urlTypeUnknown || ut == urlTypeGiteaPageRelative {
return nil
}
ret := &GiteaSiteURL{RoutePath: routePath}
fields := strings.SplitN(strings.TrimPrefix(ret.RoutePath, "/"), "/", 3)
// TODO: now it only does a quick check for some known reserved paths, should do more strict checks in the future
if fields[0] == "attachments" {
return ret
}
if len(fields) < 2 {
return ret
}
ret.OwnerName = fields[0]
ret.RepoName = fields[1]
if len(fields) == 3 {
ret.RepoSubPath = "/" + fields[2]
}
return ret
}