mirror of
				https://codeberg.org/forgejo/forgejo.git
				synced 2025-10-31 22:41:03 +00:00 
			
		
		
		
	- Massive replacement of changing `code.gitea.io/gitea` to `forgejo.org`. - Resolves forgejo/discussions#258 Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7337 Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org> Reviewed-by: Michael Kriese <michael.kriese@gmx.de> Reviewed-by: Beowulf <beowulf@beocode.eu> Reviewed-by: Panagiotis "Ivory" Vasilopoulos <git@n0toose.net> Co-authored-by: Gusted <postmaster@gusted.xyz> Co-committed-by: Gusted <postmaster@gusted.xyz>
		
			
				
	
	
		
			157 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2018 The Gitea Authors. All rights reserved.
 | |
| // SPDX-License-Identifier: MIT
 | |
| 
 | |
| package markup
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"html"
 | |
| 	"io"
 | |
| 	"regexp"
 | |
| 	"strconv"
 | |
| 
 | |
| 	"forgejo.org/modules/csv"
 | |
| 	"forgejo.org/modules/markup"
 | |
| 	"forgejo.org/modules/setting"
 | |
| 	"forgejo.org/modules/translation"
 | |
| 	"forgejo.org/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: regexp.MustCompile(`^data-table$`)},
 | |
| 		{Element: "th", AllowAttr: "class", Regexp: regexp.MustCompile(`^line-num$`)},
 | |
| 		{Element: "td", AllowAttr: "class", Regexp: regexp.MustCompile(`^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.Links.RawLink() + `/` + util.PathEscapeSegments(ctx.RelativePath) + `">`
 | |
| 
 | |
| 		// Try to get the user translation
 | |
| 		if locale, ok := ctx.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()
 | |
| }
 |