fix: Improve plain text CV output with dedicated template
- Replace html2text library conversion with dedicated text template - Create clean, well-formatted cv-text.txt template - Remove k3a/html2text dependency - Fix lint warnings in security tests (ineffectual assignments) - Output now shows only CV content without UI/menu elements
This commit is contained in:
@@ -4,60 +4,62 @@ import (
|
||||
"bytes"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/k3a/html2text"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// ==============================================================================
|
||||
// PLAIN TEXT HANDLER
|
||||
// Converts HTML CV to readable plain text for terminal/AI consumption
|
||||
// Renders CV as clean plain text for terminal/AI consumption
|
||||
// ==============================================================================
|
||||
|
||||
// PlainText renders the CV as plain text
|
||||
// Useful for: curl users, AI crawlers, accessibility, copy-paste
|
||||
func (h *CVHandler) PlainText(w http.ResponseWriter, r *http.Request) {
|
||||
// Get language from query parameter, default to English
|
||||
lang := r.URL.Query().Get("lang")
|
||||
if lang == "" {
|
||||
lang = "en"
|
||||
langCode := r.URL.Query().Get("lang")
|
||||
if langCode == "" {
|
||||
langCode = "en"
|
||||
}
|
||||
|
||||
// Validate language
|
||||
if lang != "en" && lang != "es" {
|
||||
if langCode != "en" && langCode != "es" {
|
||||
http.Error(w, "Unsupported language. Use 'en' or 'es'", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Prepare template data using shared helper
|
||||
data, err := h.prepareTemplateData(lang)
|
||||
// Prepare template data using shared helper (loads CV data)
|
||||
data, err := h.prepareTemplateData(langCode)
|
||||
if err != nil {
|
||||
log.Printf("PlainText: Failed to load CV data: %v", err)
|
||||
http.Error(w, "Failed to load CV data", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Add preferences for full CV display (show everything)
|
||||
data["CVLengthClass"] = "cv-long"
|
||||
data["ShowIcons"] = false // Icons don't render in text
|
||||
data["ThemeClean"] = false
|
||||
// Add base URL for footer
|
||||
data["BaseURL"] = h.serverAddr
|
||||
|
||||
// Render HTML template to buffer
|
||||
tmpl, err := h.templates.Render("index.html")
|
||||
// Load and parse the plain text template
|
||||
tmplPath := filepath.Join("templates", "cv-text.txt")
|
||||
tmpl, err := template.New("cv-text.txt").ParseFiles(tmplPath)
|
||||
if err != nil {
|
||||
log.Printf("PlainText: Failed to load template: %v", err)
|
||||
http.Error(w, "Failed to load template", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var htmlBuffer bytes.Buffer
|
||||
if err := tmpl.Execute(&htmlBuffer, data); err != nil {
|
||||
// Render to buffer
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
log.Printf("PlainText: Failed to execute template: %v", err)
|
||||
http.Error(w, "Failed to render template: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert HTML to plain text
|
||||
text := html2text.HTML2Text(htmlBuffer.String())
|
||||
// Clean up the output
|
||||
text := cleanPlainText(buf.String())
|
||||
|
||||
// Set response headers
|
||||
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
@@ -66,3 +68,27 @@ func (h *CVHandler) PlainText(w http.ResponseWriter, r *http.Request) {
|
||||
// Write plain text response
|
||||
_, _ = w.Write([]byte(text))
|
||||
}
|
||||
|
||||
// cleanPlainText removes extra whitespace and HTML tags from plain text
|
||||
func cleanPlainText(text string) string {
|
||||
// Remove HTML tags (from safeHTML fields)
|
||||
htmlTagRe := regexp.MustCompile(`<[^>]*>`)
|
||||
text = htmlTagRe.ReplaceAllString(text, "")
|
||||
|
||||
// Replace multiple blank lines with double newline
|
||||
multipleNewlines := regexp.MustCompile(`\n{3,}`)
|
||||
text = multipleNewlines.ReplaceAllString(text, "\n\n")
|
||||
|
||||
// Trim each line
|
||||
lines := strings.Split(text, "\n")
|
||||
var cleanedLines []string
|
||||
for _, line := range lines {
|
||||
cleanedLines = append(cleanedLines, strings.TrimRight(line, " \t"))
|
||||
}
|
||||
text = strings.Join(cleanedLines, "\n")
|
||||
|
||||
// Trim overall
|
||||
text = strings.TrimSpace(text)
|
||||
|
||||
return text
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user