feat: enhance PDF export with 4 customizable parameters
Add comprehensive parameter support to /export/pdf endpoint:
- lang: Language selection (en/es)
- length: CV length (short/long)
- icons: Icon visibility (show/hide)
- version: Theme variant (extended/clean)
Backend Changes:
- Enhanced PDF generator with cookie injection for user preferences
- Cookies set before chromedp navigation to apply all preferences
- Updated filename pattern: CV-{Name}-{lang}-{length}-{version}.pdf
- Comprehensive parameter validation with descriptive error messages
- All parameters optional with sensible defaults (en, short, show, extended)
Testing:
- Added pdf_test.go with parameter validation tests
- Tests cover all valid/invalid parameter combinations
- Tests verify default parameter application
Documentation:
- Updated API documentation (doc/3-API.md)
- Added detailed parameter descriptions and examples
- Updated quick reference with all parameter options
- Added process flow diagram showing cookie injection
- Documented error responses for each invalid parameter
Implementation Details:
- Cookie domain set to "localhost" for chromedp context
- Cookies: cv-language, cv-length, cv-icons, cv-theme
- PDF generation leverages existing @media print CSS
- No changes to frontend CSS or templates
Tested:
- Parameter validation (✅ All invalid params rejected correctly)
- Default parameters (✅ Applied when params omitted)
- PDF generation with all parameter combinations (✅ Working)
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/network"
|
||||
"github.com/chromedp/cdproto/page"
|
||||
"github.com/chromedp/chromedp"
|
||||
)
|
||||
@@ -77,6 +78,83 @@ func (g *Generator) GenerateFromURL(ctx context.Context, url string) ([]byte, er
|
||||
return pdfBuffer, nil
|
||||
}
|
||||
|
||||
// GenerateFromURLWithCookies generates a PDF from a given URL with custom cookies
|
||||
func (g *Generator) GenerateFromURLWithCookies(ctx context.Context, url string, cookies map[string]string) ([]byte, error) {
|
||||
// Create context with timeout
|
||||
ctx, cancel := context.WithTimeout(ctx, g.timeout)
|
||||
defer cancel()
|
||||
|
||||
// Create chromedp context
|
||||
allocCtx, allocCancel := chromedp.NewContext(ctx)
|
||||
defer allocCancel()
|
||||
|
||||
// Buffer to store PDF
|
||||
var pdfBuffer []byte
|
||||
|
||||
// Build tasks - set cookies BEFORE navigation
|
||||
var tasks chromedp.Tasks
|
||||
|
||||
// Add cookies if provided - must be done before navigation
|
||||
if len(cookies) > 0 {
|
||||
tasks = append(tasks, chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
// Set cookies with domain (extract from URL)
|
||||
// For localhost:1999, domain should be "localhost"
|
||||
domain := "localhost"
|
||||
|
||||
for name, value := range cookies {
|
||||
expr := network.SetCookie(name, value).
|
||||
WithDomain(domain).
|
||||
WithPath("/").
|
||||
WithHTTPOnly(true).
|
||||
WithSecure(false). // Set to true in production with HTTPS
|
||||
WithSameSite(network.CookieSameSiteStrict)
|
||||
|
||||
if err := expr.Do(ctx); err != nil {
|
||||
return fmt.Errorf("failed to set cookie %s: %w", name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
// Navigate to URL
|
||||
tasks = append(tasks, chromedp.Navigate(url))
|
||||
|
||||
// Wait for page to be ready
|
||||
tasks = append(tasks,
|
||||
chromedp.WaitReady("body"),
|
||||
// Small delay to ensure all content is loaded
|
||||
chromedp.Sleep(500*time.Millisecond),
|
||||
// Generate PDF with print-optimized settings
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
var err error
|
||||
pdfBuffer, _, err = page.PrintToPDF().
|
||||
WithPrintBackground(true).
|
||||
WithPreferCSSPageSize(true).
|
||||
WithMarginTop(0).
|
||||
WithMarginBottom(0).
|
||||
WithMarginLeft(0).
|
||||
WithMarginRight(0).
|
||||
WithPaperWidth(8.27). // A4 width in inches
|
||||
WithPaperHeight(11.69). // A4 height in inches
|
||||
Do(ctx)
|
||||
return err
|
||||
}),
|
||||
)
|
||||
|
||||
// Run chromedp tasks
|
||||
err := chromedp.Run(allocCtx, tasks)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("chromedp execution failed: %w", err)
|
||||
}
|
||||
|
||||
if len(pdfBuffer) == 0 {
|
||||
return nil, fmt.Errorf("generated PDF is empty")
|
||||
}
|
||||
|
||||
return pdfBuffer, nil
|
||||
}
|
||||
|
||||
// StreamFromURL generates a PDF and writes it to the provided writer
|
||||
func (g *Generator) StreamFromURL(ctx context.Context, url string, w io.Writer) error {
|
||||
pdfData, err := g.GenerateFromURL(ctx, url)
|
||||
|
||||
Reference in New Issue
Block a user