first-commit

This commit is contained in:
2025-08-25 15:46:12 +08:00
commit f4d95dfff4
5665 changed files with 705359 additions and 0 deletions

156
modules/markup/csv/csv.go Normal file
View File

@@ -0,0 +1,156 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package markup
import (
"bufio"
"html"
"io"
"strconv"
"code.gitea.io/gitea/modules/csv"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util"
)
func init() {
markup.RegisterRenderer(Renderer{})
}
// Renderer implements markup.Renderer for csv files
type Renderer struct{}
// Name implements markup.Renderer
func (Renderer) Name() string {
return "csv"
}
// Extensions implements markup.Renderer
func (Renderer) Extensions() []string {
return []string{".csv", ".tsv"}
}
// SanitizerRules implements markup.Renderer
func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
return []setting.MarkupSanitizerRule{
{Element: "table", AllowAttr: "class", Regexp: `^data-table$`},
{Element: "th", AllowAttr: "class", Regexp: `^line-num$`},
{Element: "td", AllowAttr: "class", Regexp: `^line-num$`},
}
}
func writeField(w io.Writer, element, class, field string) error {
if _, err := io.WriteString(w, "<"); err != nil {
return err
}
if _, err := io.WriteString(w, element); err != nil {
return err
}
if len(class) > 0 {
if _, err := io.WriteString(w, ` class="`); err != nil {
return err
}
if _, err := io.WriteString(w, class); err != nil {
return err
}
if _, err := io.WriteString(w, `"`); err != nil {
return err
}
}
if _, err := io.WriteString(w, ">"); err != nil {
return err
}
if _, err := io.WriteString(w, html.EscapeString(field)); err != nil {
return err
}
if _, err := io.WriteString(w, "</"); err != nil {
return err
}
if _, err := io.WriteString(w, element); err != nil {
return err
}
_, err := io.WriteString(w, ">")
return err
}
// Render implements markup.Renderer
func (r Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
tmpBlock := bufio.NewWriter(output)
maxSize := setting.UI.CSV.MaxFileSize
maxRows := setting.UI.CSV.MaxRows
if maxSize != 0 {
input = io.LimitReader(input, maxSize+1)
}
rd, err := csv.CreateReaderAndDetermineDelimiter(ctx, input)
if err != nil {
return err
}
if _, err := tmpBlock.WriteString(`<table class="data-table">`); err != nil {
return err
}
row := 0
for {
fields, err := rd.Read()
if err == io.EOF || (row >= maxRows && maxRows != 0) {
break
}
if err != nil {
continue
}
if _, err := tmpBlock.WriteString("<tr>"); err != nil {
return err
}
element := "td"
if row == 0 {
element = "th"
}
if err := writeField(tmpBlock, element, "line-num", strconv.Itoa(row+1)); err != nil {
return err
}
for _, field := range fields {
if err := writeField(tmpBlock, element, "", field); err != nil {
return err
}
}
if _, err := tmpBlock.WriteString("</tr>"); err != nil {
return err
}
row++
}
if _, err = tmpBlock.WriteString("</table>"); err != nil {
return err
}
// Check if maxRows or maxSize is reached, and if true, warn.
if (row >= maxRows && maxRows != 0) || (rd.InputOffset() >= maxSize && maxSize != 0) {
warn := `<table class="data-table"><tr><td>`
rawLink := ` <a href="` + ctx.RenderHelper.ResolveLink(util.PathEscapeSegments(ctx.RenderOptions.RelativePath), markup.LinkTypeRaw) + `">`
// Try to get the user translation
if locale, ok := ctx.Value(translation.ContextKey).(translation.Locale); ok {
warn += locale.TrString("repo.file_too_large")
rawLink += locale.TrString("repo.file_view_raw")
} else {
warn += "The file is too large to be shown."
rawLink += "View Raw"
}
warn += rawLink + `</a></td></tr></table>`
// Write the HTML string to the output
if _, err := tmpBlock.WriteString(warn); err != nil {
return err
}
}
return tmpBlock.Flush()
}

View File

@@ -0,0 +1,30 @@
// Copyright 2018 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package markup
import (
"strings"
"testing"
"code.gitea.io/gitea/modules/markup"
"github.com/stretchr/testify/assert"
)
func TestRenderCSV(t *testing.T) {
var render Renderer
kases := map[string]string{
"a": "<table class=\"data-table\"><tr><th class=\"line-num\">1</th><th>a</th></tr></table>",
"1,2": "<table class=\"data-table\"><tr><th class=\"line-num\">1</th><th>1</th><th>2</th></tr></table>",
"1;2\n3;4": "<table class=\"data-table\"><tr><th class=\"line-num\">1</th><th>1</th><th>2</th></tr><tr><td class=\"line-num\">2</td><td>3</td><td>4</td></tr></table>",
"<br/>": "<table class=\"data-table\"><tr><th class=\"line-num\">1</th><th>&lt;br/&gt;</th></tr></table>",
}
for k, v := range kases {
var buf strings.Builder
err := render.Render(markup.NewRenderContext(t.Context()), strings.NewReader(k), &buf)
assert.NoError(t, err)
assert.Equal(t, v, buf.String())
}
}