From 30ed21ff7aaff997cb1882f2e64ed04f748184a3 Mon Sep 17 00:00:00 2001 From: juanatsap Date: Sat, 6 Dec 2025 16:31:42 +0000 Subject: [PATCH] refactor: use 'c' alias for constants package - Update all imports from 'constants' to 'c' for brevity - Replace all 'constants.' references with 'c.' - Fix remaining hardcoded content-type headers in httputil - Fix remaining hardcoded User-Agent and Accept headers - Rename CSRF receiver from 'c' to 'csrf' to avoid conflict - Add ContentTypePlainSimple constant for Accept header matching - Fix JSONCached to use proper integer formatting --- coverage.txt | 1162 +++++++++++++++++++++ internal/config/config.go | 8 +- internal/constants/constants.go | 1 + internal/handlers/contact.go | 6 +- internal/handlers/cv_cmdk.go | 6 +- internal/handlers/cv_contact.go | 6 +- internal/handlers/cv_helpers.go | 4 +- internal/handlers/cv_htmx.go | 36 +- internal/handlers/cv_pages.go | 24 +- internal/handlers/cv_pdf.go | 22 +- internal/handlers/cv_text.go | 12 +- internal/handlers/errors.go | 10 +- internal/handlers/health.go | 4 +- internal/httputil/request.go | 10 +- internal/httputil/response.go | 9 +- internal/middleware/browser_only.go | 14 +- internal/middleware/contact_rate_limit.go | 12 +- internal/middleware/csrf.go | 46 +- internal/middleware/preferences.go | 52 +- internal/middleware/security.go | 44 +- internal/middleware/security_logger.go | 14 +- 21 files changed, 1335 insertions(+), 167 deletions(-) create mode 100644 coverage.txt diff --git a/coverage.txt b/coverage.txt new file mode 100644 index 0000000..733be25 --- /dev/null +++ b/coverage.txt @@ -0,0 +1,1162 @@ +mode: atomic +github.com/juanatsap/cv-site/main.go:23.13,29.40 3 0 +github.com/juanatsap/cv-site/main.go:29.40,31.3 1 0 +github.com/juanatsap/cv-site/main.go:31.8,33.3 1 0 +github.com/juanatsap/cv-site/main.go:36.2,41.16 4 0 +github.com/juanatsap/cv-site/main.go:41.16,43.3 1 0 +github.com/juanatsap/cv-site/main.go:46.2,74.12 8 0 +github.com/juanatsap/cv-site/main.go:74.12,82.3 6 0 +github.com/juanatsap/cv-site/main.go:85.2,89.9 3 0 +github.com/juanatsap/cv-site/main.go:90.29,91.44 1 0 +github.com/juanatsap/cv-site/main.go:91.44,93.4 1 0 +github.com/juanatsap/cv-site/main.go:95.25,104.46 5 0 +github.com/juanatsap/cv-site/main.go:104.46,106.41 2 0 +github.com/juanatsap/cv-site/main.go:106.41,108.5 1 0 +github.com/juanatsap/cv-site/main.go:111.3,111.47 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:65.13,81.28 7 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:81.28,87.17 4 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:87.17,89.12 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:92.3,95.22 3 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:95.22,97.12 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:101.3,102.17 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:102.17,104.12 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:107.3,108.17 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:108.17,110.12 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:114.3,116.32 3 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:116.32,119.4 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:121.3,121.19 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:122.20,123.33 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:124.19,125.32 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:126.18,127.31 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:131.3,138.84 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:142.2,143.16 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:143.16,146.3 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:147.2,151.16 3 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:151.16,154.3 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:155.2,172.48 16 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:176.50,178.16 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:178.16,180.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:182.2,183.32 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:183.32,184.20 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:184.20,185.12 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:187.3,188.55 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:188.55,190.4 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:194.2,195.18 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:199.77,200.25 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:200.25,202.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:205.2,210.39 4 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:210.39,215.17 3 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:215.17,217.12 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:221.3,226.69 4 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:230.2,231.38 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:235.58,237.16 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:237.16,239.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:240.2,240.15 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:240.15,241.54 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:241.54,243.4 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:246.2,247.16 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:247.16,249.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:251.2,251.17 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:256.67,261.34 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:261.34,262.35 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:262.35,264.4 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:268.2,276.21 7 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:276.21,278.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:281.2,298.12 9 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:302.58,305.47 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:305.47,307.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:309.2,310.16 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:310.16,312.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:313.2,313.15 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:313.15,314.54 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:314.54,316.4 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:319.2,319.30 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:323.48,325.16 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:325.16,327.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:329.2,330.45 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:334.64,456.33 3 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:456.33,458.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:460.2,461.33 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:461.33,463.3 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:464.2,468.33 3 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:468.33,479.34 2 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:479.34,485.4 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:487.3,487.47 1 0 +github.com/juanatsap/cv-site/cmd/sprites/main.go:491.2,532.53 3 0 +github.com/juanatsap/cv-site/internal/config/config.go:48.21,73.2 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:76.35,78.2 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:82.46,83.42 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:83.42,85.3 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:86.2,86.21 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:89.52,91.54 2 0 +github.com/juanatsap/cv-site/internal/config/config.go:91.54,93.3 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:94.2,94.21 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:97.55,99.59 2 0 +github.com/juanatsap/cv-site/internal/config/config.go:99.59,101.3 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:102.2,102.21 1 0 +github.com/juanatsap/cv-site/internal/config/config.go:105.27,108.2 2 0 +github.com/juanatsap/cv-site/internal/routes/routes.go:12.95,71.2 21 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:20.53,21.18 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:21.18,23.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:24.2,26.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:30.86,67.55 10 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:67.55,80.4 3 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:83.2,83.16 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:83.16,85.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:87.2,87.25 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:87.25,89.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:91.2,91.23 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:105.124,107.2 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:110.141,136.22 10 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:136.22,137.77 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:137.77,142.37 2 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:142.37,150.40 2 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:150.40,152.6 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:154.4,154.14 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:159.2,169.30 3 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:169.30,182.77 3 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:182.77,228.22 3 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:228.22,238.5 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:240.4,245.61 2 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:252.2,252.76 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:252.76,265.3 3 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:268.2,269.16 2 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:269.16,271.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:273.2,273.25 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:273.25,275.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:277.2,277.23 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:281.87,283.16 2 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:283.16,285.3 1 0 +github.com/juanatsap/cv-site/internal/pdf/generator.go:287.2,288.12 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:224.52,226.45 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:226.45,228.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:231.2,238.29 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:238.29,239.42 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:239.42,241.4 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:244.2,244.103 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:248.39,249.34 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:249.34,251.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:253.2,255.16 3 0 +github.com/juanatsap/cv-site/internal/models/cv.go:255.16,257.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:259.2,260.16 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:260.16,262.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:264.2,265.50 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:265.50,267.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:270.2,271.31 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:271.31,273.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:275.2,275.17 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:279.61,281.2 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:284.39,285.34 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:285.34,287.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:289.2,291.16 3 0 +github.com/juanatsap/cv-site/internal/models/cv.go:291.16,293.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:295.2,296.16 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:296.16,298.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:300.2,301.50 2 0 +github.com/juanatsap/cv-site/internal/models/cv.go:301.50,303.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv.go:305.2,305.17 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:32.57,36.2 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:50.44,59.19 6 0 +github.com/juanatsap/cv-site/internal/services/email.go:59.19,61.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:62.2,62.21 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:62.21,64.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:67.2,67.72 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:67.72,69.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:72.2,72.31 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:72.31,74.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:75.2,75.33 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:75.33,77.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:80.2,80.24 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:80.24,82.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:83.2,83.23 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:83.23,85.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:86.2,86.26 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:86.26,88.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:89.2,89.26 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:89.26,91.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:92.2,92.27 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:92.27,94.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:95.2,95.25 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:95.25,97.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:99.2,99.12 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:103.38,105.2 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:108.69,110.40 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:110.40,112.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:115.2,116.24 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:116.24,118.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:118.8,120.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:123.2,124.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:124.16,126.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:129.2,129.86 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:129.86,131.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:134.2,136.12 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:151.101,164.25 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:164.25,166.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:169.2,170.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:170.16,172.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:174.2,175.61 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:175.61,177.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:180.2,181.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:181.16,183.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:185.2,186.61 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:186.61,188.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:190.2,190.48 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:195.94,197.56 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:197.56,199.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:200.2,200.60 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:200.60,202.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:203.2,203.28 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:203.28,205.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:207.2,208.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:208.16,210.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:211.2,224.16 6 0 +github.com/juanatsap/cv-site/internal/services/email.go:224.16,226.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:227.2,227.15 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:227.15,227.37 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:230.2,230.41 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:230.41,232.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:235.2,235.41 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:235.41,237.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:238.2,238.39 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:238.39,240.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:243.2,244.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:244.16,246.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:248.2,249.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:249.16,251.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:253.2,254.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:254.16,256.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:258.2,258.22 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:262.71,270.32 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:270.32,273.17 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:273.17,275.4 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:276.3,277.17 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:277.17,280.4 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:281.3,281.21 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:285.2,286.16 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:286.16,288.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:290.2,290.50 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:290.50,293.3 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:295.2,295.20 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:299.109,308.19 5 0 +github.com/juanatsap/cv-site/internal/services/email.go:308.19,310.3 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:311.2,333.40 17 0 +github.com/juanatsap/cv-site/internal/services/email.go:333.40,335.25 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:335.25,337.4 1 0 +github.com/juanatsap/cv-site/internal/services/email.go:338.3,339.30 2 0 +github.com/juanatsap/cv-site/internal/services/email.go:343.2,345.25 2 0 +github.com/juanatsap/cv-site/internal/services/email_theme.go:12.26,242.2 1 0 +github.com/juanatsap/cv-site/internal/services/email_theme.go:247.40,329.2 1 0 +github.com/juanatsap/cv-site/internal/services/email_theme.go:332.41,360.2 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:22.40,24.2 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:27.63,32.42 2 0 +github.com/juanatsap/cv-site/internal/templates/template.go:32.42,34.3 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:36.2,36.15 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:40.41,44.2 3 0 +github.com/juanatsap/cv-site/internal/templates/template.go:47.47,50.36 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:50.36,52.31 2 0 +github.com/juanatsap/cv-site/internal/templates/template.go:52.31,54.5 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:55.4,55.17 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:57.32,59.4 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:63.44,65.4 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:67.71,68.26 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:68.26,70.5 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:71.4,72.40 2 0 +github.com/juanatsap/cv-site/internal/templates/template.go:72.40,74.12 2 0 +github.com/juanatsap/cv-site/internal/templates/template.go:74.12,76.6 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:77.5,77.28 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:79.4,79.20 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:84.2,86.16 3 0 +github.com/juanatsap/cv-site/internal/templates/template.go:86.16,88.3 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:91.2,101.26 6 0 +github.com/juanatsap/cv-site/internal/templates/template.go:101.26,103.17 2 0 +github.com/juanatsap/cv-site/internal/templates/template.go:103.17,105.4 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:105.9,107.4 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:110.2,113.12 3 0 +github.com/juanatsap/cv-site/internal/templates/template.go:117.34,119.2 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:123.67,126.24 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:126.24,128.49 2 0 +github.com/juanatsap/cv-site/internal/templates/template.go:128.49,135.19 6 0 +github.com/juanatsap/cv-site/internal/templates/template.go:135.19,137.5 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:138.4,138.20 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:140.3,142.18 3 0 +github.com/juanatsap/cv-site/internal/templates/template.go:142.18,144.4 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:145.3,145.19 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:149.2,153.17 4 0 +github.com/juanatsap/cv-site/internal/templates/template.go:153.17,155.3 1 0 +github.com/juanatsap/cv-site/internal/templates/template.go:157.2,157.18 1 0 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:23.52,24.20 1 8 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:24.20,26.3 1 1 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:29.2,29.45 1 7 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:29.45,31.3 1 0 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:34.2,41.29 2 7 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:41.29,42.42 1 23 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:42.42,44.4 1 5 +github.com/juanatsap/cv-site/internal/fileutil/fileutil.go:47.2,47.103 1 2 +github.com/juanatsap/cv-site/internal/fileutil/json.go:19.58,21.16 2 3 +github.com/juanatsap/cv-site/internal/fileutil/json.go:21.16,23.3 1 1 +github.com/juanatsap/cv-site/internal/fileutil/json.go:25.2,26.16 2 2 +github.com/juanatsap/cv-site/internal/fileutil/json.go:26.16,28.3 1 0 +github.com/juanatsap/cv-site/internal/fileutil/json.go:30.2,30.53 1 2 +github.com/juanatsap/cv-site/internal/fileutil/json.go:30.53,32.3 1 1 +github.com/juanatsap/cv-site/internal/fileutil/json.go:34.2,34.12 1 1 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:21.50,22.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:22.71,25.51 2 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:25.51,29.4 3 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:32.3,35.36 3 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:35.36,39.4 3 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:44.3,48.69 4 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:48.69,52.4 3 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:55.3,55.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:60.37,87.40 3 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:87.40,88.36 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:88.36,90.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:93.2,93.14 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:97.43,100.14 2 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:100.14,104.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:107.2,108.14 2 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:108.14,110.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:113.2,115.50 2 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:115.50,117.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/browser_only.go:119.2,119.11 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:25.50,34.2 3 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:37.74,38.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:38.71,41.15 2 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:41.15,43.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:44.3,44.15 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:44.15,46.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:49.3,49.32 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:49.32,51.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:53.3,53.20 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:53.20,57.14 2 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:57.14,65.5 3 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:65.10,68.5 2 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:69.4,69.10 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:72.3,72.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:78.53,87.43 7 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:87.43,94.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:96.2,96.26 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:96.26,98.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:100.2,101.13 2 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:105.41,109.21 3 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:109.21,112.37 3 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:112.37,113.34 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:113.34,115.5 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:117.3,117.17 1 0 +github.com/juanatsap/cv-site/internal/middleware/contact_rate_limit.go:122.65,131.2 3 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:33.42,42.2 3 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:47.69,48.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:48.71,50.97 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:50.97,51.27 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:51.27,57.15 3 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:57.15,64.6 3 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:64.11,66.6 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:67.5,67.11 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:71.3,71.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:76.58,78.44 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:78.44,80.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:82.2,92.19 5 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:97.91,100.38 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:100.38,106.51 4 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:106.51,109.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:113.2,114.16 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:114.16,116.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:119.2,129.19 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:133.62,138.38 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:138.38,140.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:143.2,143.21 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:143.21,145.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:147.2,147.21 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:147.21,150.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:153.2,154.38 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:154.38,157.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:160.2,160.31 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:160.31,163.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:166.2,170.13 4 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:170.13,173.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:175.2,175.39 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:175.39,178.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:180.2,180.13 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:184.36,188.21 3 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:188.21,191.38 3 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:191.38,192.34 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:192.34,194.5 1 0 +github.com/juanatsap/cv-site/internal/middleware/csrf.go:196.3,196.16 1 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:17.49,18.21 1 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:18.21,22.3 3 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:25.56,26.21 1 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:26.21,28.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:29.2,31.15 3 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:35.45,36.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/logger.go:36.71,58.3 5 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:28.60,29.71 1 8 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:29.71,39.35 2 8 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:39.35,41.4 1 2 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:42.3,42.24 1 8 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:43.15,44.26 1 2 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:45.16,46.26 1 1 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:50.3,51.40 2 8 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:56.51,58.9 2 9 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:58.9,67.3 1 1 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:68.2,68.14 1 8 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:77.42,79.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:82.42,84.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:87.41,89.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:92.41,94.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:97.44,99.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:102.37,104.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:107.38,109.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:112.38,114.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:117.38,119.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:122.41,124.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:127.43,129.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:132.39,134.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:137.40,139.2 1 0 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:142.76,152.2 1 8 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:155.30,158.2 2 14 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:161.84,163.16 2 42 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:163.16,165.3 1 28 +github.com/juanatsap/cv-site/internal/middleware/preferences.go:166.2,166.21 1 14 +github.com/juanatsap/cv-site/internal/middleware/recovery.go:10.47,11.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/recovery.go:11.71,12.16 1 0 +github.com/juanatsap/cv-site/internal/middleware/recovery.go:12.16,13.36 1 0 +github.com/juanatsap/cv-site/internal/middleware/recovery.go:13.36,19.5 2 0 +github.com/juanatsap/cv-site/internal/middleware/recovery.go:22.3,22.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:12.54,13.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:13.71,44.42 8 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:44.42,48.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:50.3,50.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:56.52,57.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:57.71,63.30 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:63.30,65.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:68.3,70.30 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:70.30,72.41 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:72.41,74.5 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:78.3,79.19 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:79.19,80.48 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:80.48,83.5 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:87.3,88.20 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:88.20,89.49 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:89.49,92.5 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:97.3,97.36 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:97.36,100.74 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:100.74,104.5 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:107.3,107.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:112.70,124.41 7 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:124.41,125.41 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:125.41,127.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:130.2,130.14 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:148.67,159.2 3 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:162.67,163.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:163.71,166.15 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:166.15,168.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:169.3,169.15 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:169.15,171.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:173.3,173.20 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:173.20,177.4 3 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:179.3,179.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:184.46,191.43 5 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:191.43,198.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:200.2,200.29 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:200.29,202.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:204.2,205.13 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:209.34,213.21 3 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:213.21,216.37 3 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:216.37,217.34 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:217.34,219.5 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:221.3,221.17 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:227.51,228.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:228.71,230.42 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:230.42,232.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:234.3,235.23 2 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:241.58,242.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:242.71,245.42 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:245.42,248.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:248.9,251.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security.go:252.3,252.23 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:50.74,66.16 4 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:66.16,69.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:72.2,75.41 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:75.41,77.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:81.43,82.19 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:83.62,84.22 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:86.74,87.24 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:88.24,89.21 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:90.47,91.22 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:92.10,93.21 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:98.42,100.55 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:100.55,104.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:107.2,107.49 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:107.49,109.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:112.2,113.50 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:113.50,115.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:116.2,116.11 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:120.42,123.50 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:123.50,126.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:129.2,131.16 3 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:131.16,134.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:135.2,135.15 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:135.15,136.35 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:136.35,138.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:142.2,142.46 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:142.46,145.3 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:146.2,146.47 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:146.47,148.3 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:152.53,153.71 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:153.71,169.41 5 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:169.41,190.4 5 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:193.3,193.28 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:193.28,195.54 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:195.54,197.5 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:199.4,211.42 3 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:217.47,225.35 2 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:225.35,226.34 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:226.34,228.4 1 0 +github.com/juanatsap/cv-site/internal/middleware/security_logger.go:231.2,231.14 1 0 +github.com/juanatsap/cv-site/internal/models/ui/loader.go:11.43,12.48 1 5 +github.com/juanatsap/cv-site/internal/models/ui/loader.go:12.48,14.3 1 2 +github.com/juanatsap/cv-site/internal/models/ui/loader.go:16.2,18.61 3 3 +github.com/juanatsap/cv-site/internal/models/ui/loader.go:18.61,20.3 1 0 +github.com/juanatsap/cv-site/internal/models/ui/loader.go:22.2,22.21 1 3 +github.com/juanatsap/cv-site/internal/handlers/contact.go:27.91,32.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:47.73,49.33 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:49.33,52.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:55.2,55.38 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:55.38,59.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:62.2,73.24 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:73.24,78.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:81.2,82.25 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:82.25,85.75 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:85.75,90.31 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:90.31,94.5 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:101.2,101.21 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:101.21,104.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:105.2,105.23 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:105.23,108.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:111.2,122.66 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:122.66,126.57 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:126.57,129.4 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:132.3,133.9 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:137.2,140.23 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:144.80,155.34 4 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:155.34,158.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:160.2,161.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:161.16,165.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:167.2,167.45 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:167.45,170.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:174.94,182.34 4 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:182.34,185.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:187.2,192.16 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:192.16,196.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:198.2,198.46 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:198.46,201.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:205.42,208.14 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:208.14,212.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:215.2,216.14 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:216.14,218.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:221.2,223.64 2 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:223.64,225.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/contact.go:227.2,227.11 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv.go:26.111,33.2 1 7 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:29.70,32.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:32.16,34.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:35.2,35.34 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:35.34,37.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:40.2,41.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:41.16,45.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:48.2,55.36 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:55.36,56.26 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:56.26,57.12 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:59.3,64.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:68.2,68.35 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:68.35,69.27 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:69.27,70.12 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:72.3,73.18 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:73.18,75.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:76.3,81.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:85.2,85.36 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:85.36,86.28 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:86.28,87.12 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:89.3,94.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:98.2,101.60 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_cmdk.go:101.60,103.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:33.75,35.33 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:35.33,38.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:41.2,41.38 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:41.38,45.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:48.2,49.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:49.16,51.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:54.2,54.34 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:54.34,56.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:59.2,71.57 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:71.57,75.53 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:75.53,79.4 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:81.3,82.9 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:86.2,92.27 5 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:92.27,103.67 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:103.67,107.4 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:108.3,108.72 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:109.8,111.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:114.2,114.36 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:118.72,120.24 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:120.24,122.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:125.2,125.29 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:125.29,127.17 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:127.17,132.22 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:132.22,134.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:137.4,137.25 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:137.25,139.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:144.2,144.22 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:144.22,146.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:148.2,148.24 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:148.24,150.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:153.2,153.78 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:153.78,155.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:158.2,158.28 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:158.28,160.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:162.2,162.30 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:162.30,164.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:166.2,166.12 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:170.95,173.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:173.16,177.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:180.2,190.16 5 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:190.16,201.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:203.2,203.46 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:203.46,212.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:216.101,219.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:219.16,221.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:224.2,224.34 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:224.34,226.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:229.2,230.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:230.16,234.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:237.2,250.16 5 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:250.16,261.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:263.2,263.46 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_contact.go:263.46,272.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:24.88,25.22 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:25.22,27.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:30.2,30.31 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:30.31,31.31 1 117 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:31.31,33.4 1 63 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:33.9,36.4 1 54 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:39.2,39.20 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:48.39,60.67 4 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:60.67,62.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:64.2,64.14 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:70.85,73.16 2 99 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:73.16,75.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:78.2,79.13 2 99 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:79.13,81.3 1 18 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:81.8,83.17 2 81 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:83.17,85.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:89.2,92.21 2 99 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:92.21,94.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:96.2,101.18 4 99 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:101.18,102.30 1 33 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:102.30,104.18 2 21 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:104.18,106.5 1 15 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:107.4,108.19 2 21 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:108.19,110.5 1 3 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:111.4,111.75 1 21 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:112.9,112.23 1 12 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:112.23,114.18 2 6 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:114.18,116.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:117.4,117.51 1 6 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:118.9,120.19 2 6 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:120.19,122.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:123.4,123.53 1 6 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:125.8,126.30 1 66 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:126.30,128.18 2 42 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:128.18,130.5 1 30 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:131.4,132.19 2 42 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:132.19,134.5 1 6 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:135.4,135.75 1 42 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:136.9,136.23 1 24 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:136.23,138.18 2 12 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:138.18,140.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:141.4,141.51 1 12 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:142.9,144.19 2 12 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:144.19,146.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:147.4,147.53 1 12 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:151.2,151.15 1 99 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:157.65,161.21 2 45 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:161.21,162.19 1 45 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:162.19,164.4 1 15 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:164.9,166.4 1 30 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:170.2,170.30 1 45 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:170.30,172.23 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:172.23,174.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:178.2,178.83 1 45 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:178.83,180.3 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:183.2,183.64 1 45 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:183.64,185.3 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:193.40,195.16 2 17 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:195.16,197.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:199.2,200.6 2 17 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:200.6,202.64 2 51 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:202.64,204.4 1 17 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:206.3,207.20 2 34 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:207.20,209.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:210.3,210.15 1 34 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:216.42,218.16 2 16 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:218.16,220.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:222.2,223.16 2 16 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:223.16,225.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:228.2,228.46 1 16 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:228.46,230.3 1 5 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:232.2,233.16 2 11 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:233.16,235.3 1 8 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:236.2,236.19 1 3 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:236.19,238.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:240.2,240.12 1 3 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:245.56,247.51 1 8 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:247.51,250.3 2 7 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:253.2,254.16 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:254.16,257.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:260.2,263.16 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:263.16,266.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:267.2,271.56 3 1 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:271.56,272.82 1 479 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:272.82,274.4 1 479 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:275.3,275.13 1 479 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:277.2,277.16 1 1 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:277.16,280.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:282.2,282.25 1 1 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:282.25,285.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:288.2,288.54 1 1 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:296.86,299.16 2 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:299.16,301.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:304.2,305.16 2 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:305.16,307.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:310.2,310.31 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:310.31,317.3 1 99 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:320.2,320.29 1 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:320.29,322.3 1 45 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:325.2,336.18 5 9 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:336.18,338.56 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:338.56,341.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_helpers.go:345.2,359.18 2 9 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:16.74,17.33 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:17.33,20.3 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:23.2,28.29 4 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:28.29,30.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:33.2,37.37 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:41.73,42.33 1 5 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:42.33,45.3 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:48.2,53.28 4 4 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:53.28,55.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:58.2,62.37 2 4 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:68.76,71.16 2 4 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:71.16,73.3 1 1 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:76.2,76.34 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:76.34,79.3 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:82.2,86.16 3 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:86.16,89.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:92.2,95.30 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:95.30,97.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:97.8,99.3 1 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:100.2,105.16 4 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:105.16,108.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:110.2,111.46 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:111.46,114.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:118.73,119.33 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:119.33,122.3 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:125.2,130.29 4 3 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:130.29,132.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_htmx.go:135.2,139.37 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:21.66,23.89 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:23.89,26.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:29.2,29.22 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:29.22,32.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:35.2,36.16 2 4 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:36.16,38.3 1 1 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:41.2,41.34 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:41.34,44.3 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:47.2,48.16 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:48.16,51.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:54.2,63.24 6 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:63.24,65.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:66.2,72.16 5 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:72.16,75.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:77.2,78.46 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:78.46,81.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:85.71,88.16 2 4 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:88.16,90.3 1 1 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:93.2,93.34 1 4 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:93.34,96.3 2 1 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:99.2,100.16 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:100.16,103.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:106.2,107.16 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:107.16,110.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:112.2,113.46 2 3 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:113.46,116.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:122.79,129.21 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:129.21,132.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:135.2,140.34 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:140.34,143.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:146.2,147.28 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:147.28,152.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:156.2,173.16 6 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:173.16,177.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:180.2,188.44 5 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:188.44,191.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pages.go:193.2,193.81 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:20.71,23.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:23.16,26.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:28.2,33.16 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:33.16,36.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:39.2,46.28 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:46.28,48.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:48.8,50.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:54.2,63.28 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:63.28,65.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:65.8,67.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:70.2,72.16 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:72.16,76.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:88.2,90.33 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:90.33,91.20 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:91.20,94.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:96.2,105.28 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:105.28,107.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:107.8,110.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:113.2,118.44 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:118.44,121.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_pdf.go:123.2,123.81 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:35.42,39.39 2 12 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:39.39,40.36 1 99 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:40.36,42.4 1 5 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:46.2,47.48 2 7 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:57.71,60.20 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:60.20,62.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:65.2,65.42 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:65.42,68.3 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:71.2,75.16 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:75.16,79.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:82.2,89.38 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:89.38,92.37 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:92.37,94.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:95.4,96.46 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:99.53,103.4 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:105.35,108.27 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:108.27,109.20 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:109.20,111.6 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:111.11,113.6 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:116.4,123.64 6 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:123.64,124.46 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:124.46,126.6 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:127.5,128.47 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:131.4,131.118 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:136.2,138.16 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:138.16,142.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:145.2,146.49 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:146.49,150.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:153.2,160.45 4 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:160.45,164.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:167.2,167.30 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:171.41,185.29 8 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:185.29,190.3 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:191.2,196.13 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:201.52,204.29 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:204.29,206.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:209.2,209.108 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:209.108,211.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:214.2,215.26 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:215.26,216.28 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:216.28,218.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:218.9,219.9 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:224.2,225.38 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:225.38,227.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:229.2,232.33 3 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:232.33,235.34 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:235.34,236.27 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:236.27,238.10 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:243.3,243.30 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:243.30,245.35 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:245.35,246.28 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:246.28,248.11 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:251.4,251.17 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:251.17,253.5 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:256.3,257.85 2 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:260.2,260.24 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:260.24,262.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/cv_text.go:264.2,264.16 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:26.35,27.18 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:27.18,29.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:30.2,30.18 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:34.86,41.2 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:44.69,48.25 2 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:49.17,50.13 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:51.10,53.91 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:57.2,57.21 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:57.21,59.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:59.8,61.3 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:64.2,68.12 4 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:68.12,79.23 4 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:79.23,81.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:83.3,83.61 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:83.61,85.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:86.3,86.9 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:89.2,89.12 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:89.12,95.22 4 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:95.22,97.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:99.3,99.88 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:99.88,101.4 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:102.3,102.9 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:106.2,107.21 2 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:107.21,109.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:111.2,111.43 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:116.46,118.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:120.48,122.2 1 3 +github.com/juanatsap/cv-site/internal/handlers/errors.go:124.41,126.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:128.62,135.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:137.58,144.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:180.38,181.18 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:181.18,183.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:184.2,184.49 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:188.38,190.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:193.82,199.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:202.57,205.2 2 0 +github.com/juanatsap/cv-site/internal/handlers/errors.go:208.60,211.2 2 0 +github.com/juanatsap/cv-site/internal/handlers/health.go:23.54,27.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/health.go:30.71,39.60 4 0 +github.com/juanatsap/cv-site/internal/handlers/health.go:39.60,41.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:19.70,21.16 2 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:21.16,23.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:26.2,26.34 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:26.34,28.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:30.2,30.42 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:42.72,51.20 2 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:51.20,53.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:54.2,54.22 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:54.22,56.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:57.2,57.21 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:57.21,59.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:60.2,60.23 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:60.23,62.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:65.2,65.42 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:65.42,67.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:70.2,70.51 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:70.51,72.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:75.2,75.48 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:75.48,77.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:80.2,80.60 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:80.60,82.3 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:84.2,84.17 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:116.53,121.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:124.58,132.2 1 0 +github.com/juanatsap/cv-site/internal/handlers/types.go:135.71,144.2 1 0 +github.com/juanatsap/cv-site/internal/lang/lang.go:12.21,14.2 1 3 +github.com/juanatsap/cv-site/internal/lang/lang.go:17.32,19.2 1 9 +github.com/juanatsap/cv-site/internal/lang/lang.go:29.34,30.20 1 4 +github.com/juanatsap/cv-site/internal/lang/lang.go:30.20,32.3 1 2 +github.com/juanatsap/cv-site/internal/lang/lang.go:33.2,33.12 1 2 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:13.43,14.48 1 5 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:14.48,16.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:18.2,20.61 3 3 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:20.61,22.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:25.2,26.35 2 3 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:26.35,28.3 1 21 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:31.2,31.42 1 3 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:31.42,33.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:35.2,35.21 1 3 +github.com/juanatsap/cv-site/internal/models/cv/loader.go:39.61,41.2 1 21 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:16.41,18.2 1 33 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:23.42,24.17 1 26 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:24.17,26.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:27.2,29.24 3 26 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:29.24,33.3 3 33 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:34.2,34.20 1 26 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:38.32,42.47 2 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:42.47,43.46 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:43.46,45.4 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:45.9,47.4 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:51.2,51.36 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:51.36,52.40 1 34 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:52.40,53.47 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:53.47,54.32 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:54.32,59.6 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:60.10,65.5 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:70.2,70.35 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:70.35,71.40 1 3 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:71.40,72.47 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:72.47,73.32 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:73.32,78.6 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:79.10,84.5 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:89.2,89.45 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:89.45,90.46 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:90.46,92.4 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:92.9,94.4 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:98.2,98.36 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:98.36,99.41 1 12 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:99.41,100.47 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:100.47,101.32 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:101.32,106.6 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:107.10,112.5 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:117.2,117.35 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:117.35,118.41 1 15 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:118.41,119.47 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:119.47,120.32 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:120.32,125.6 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:126.10,131.5 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:136.2,136.43 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:136.43,137.46 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:137.46,139.4 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:139.9,141.4 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:144.2,144.21 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:144.21,146.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:147.2,147.12 1 4 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:151.37,154.37 2 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:154.37,156.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:158.2,158.38 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:158.38,160.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:160.8,160.35 1 10 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:160.35,162.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:165.2,165.49 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:165.49,167.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:168.2,168.45 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:168.45,170.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:171.2,171.47 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:171.47,173.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:174.2,174.51 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:174.51,176.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:178.2,178.21 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:178.21,180.3 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:181.2,181.12 1 6 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:185.39,188.41 2 40 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:188.41,190.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:191.2,191.40 1 40 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:191.40,193.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:194.2,194.42 1 40 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:194.42,196.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:199.2,199.54 1 40 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:199.54,201.3 1 4 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:204.2,204.53 1 40 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:204.53,206.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:208.2,208.21 1 40 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:208.21,210.3 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:211.2,211.12 1 35 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:215.38,218.39 2 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:218.39,220.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:221.2,221.44 1 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:221.44,223.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:224.2,224.42 1 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:224.42,226.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:227.2,227.40 1 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:227.40,229.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:231.2,231.21 1 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:231.21,233.3 1 4 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:234.2,234.12 1 4 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:238.35,241.34 2 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:241.34,242.44 1 47 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:242.44,247.4 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:250.3,250.49 1 47 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:250.49,255.4 1 3 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:257.3,257.26 1 47 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:257.26,262.4 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:265.3,265.75 1 47 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:265.75,270.4 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:273.2,273.21 1 11 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:273.21,275.3 1 6 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:276.2,276.12 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:280.37,283.41 2 17 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:283.41,285.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:287.2,287.44 1 17 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:287.44,289.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:292.2,292.32 1 17 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:292.32,294.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:296.2,296.21 1 17 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:296.21,298.3 1 4 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:299.2,299.12 1 13 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:303.36,306.38 2 19 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:306.38,308.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:311.2,311.39 1 19 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:311.39,313.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:318.2,318.21 1 19 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:318.21,320.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:321.2,321.12 1 17 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:325.33,328.40 2 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:328.40,330.3 1 2 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:332.2,332.41 1 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:332.41,334.3 1 1 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:336.2,336.21 1 8 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:336.21,338.3 1 3 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:339.2,339.12 1 5 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:345.38,347.17 2 10 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:347.17,349.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:350.2,351.19 2 10 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:355.37,357.18 2 66 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:357.18,359.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:362.2,363.16 2 66 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:363.16,365.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:368.2,368.20 1 66 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:368.20,370.3 1 3 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:373.2,373.18 1 63 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:373.18,375.3 1 0 +github.com/juanatsap/cv-site/internal/models/cv/validation.go:377.2,377.13 1 63 +github.com/juanatsap/cv-site/internal/validation/contact.go:30.42,32.2 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:35.57,37.24 1 14 +github.com/juanatsap/cv-site/internal/validation/contact.go:37.24,42.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:45.2,45.23 1 13 +github.com/juanatsap/cv-site/internal/validation/contact.go:45.23,48.20 3 6 +github.com/juanatsap/cv-site/internal/validation/contact.go:48.20,53.4 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:55.3,55.41 1 5 +github.com/juanatsap/cv-site/internal/validation/contact.go:55.41,60.4 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:64.2,64.39 1 12 +github.com/juanatsap/cv-site/internal/validation/contact.go:64.39,69.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:71.2,71.40 1 11 +github.com/juanatsap/cv-site/internal/validation/contact.go:71.40,76.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:78.2,78.42 1 11 +github.com/juanatsap/cv-site/internal/validation/contact.go:78.42,83.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:85.2,85.42 1 11 +github.com/juanatsap/cv-site/internal/validation/contact.go:85.42,90.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:93.2,93.44 1 11 +github.com/juanatsap/cv-site/internal/validation/contact.go:93.44,98.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:100.2,100.45 1 10 +github.com/juanatsap/cv-site/internal/validation/contact.go:100.45,105.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:107.2,107.47 1 10 +github.com/juanatsap/cv-site/internal/validation/contact.go:107.47,112.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:114.2,114.47 1 10 +github.com/juanatsap/cv-site/internal/validation/contact.go:114.47,119.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:121.2,121.48 1 9 +github.com/juanatsap/cv-site/internal/validation/contact.go:121.48,126.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:129.2,129.30 1 8 +github.com/juanatsap/cv-site/internal/validation/contact.go:129.30,134.3 1 2 +github.com/juanatsap/cv-site/internal/validation/contact.go:137.2,137.38 1 6 +github.com/juanatsap/cv-site/internal/validation/contact.go:137.38,142.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:144.2,144.39 1 5 +github.com/juanatsap/cv-site/internal/validation/contact.go:144.39,149.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:151.2,151.41 1 5 +github.com/juanatsap/cv-site/internal/validation/contact.go:151.41,156.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:159.2,159.28 1 5 +github.com/juanatsap/cv-site/internal/validation/contact.go:159.28,164.3 1 3 +github.com/juanatsap/cv-site/internal/validation/contact.go:167.2,167.34 1 2 +github.com/juanatsap/cv-site/internal/validation/contact.go:167.34,172.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:175.2,175.55 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:175.55,180.3 1 0 +github.com/juanatsap/cv-site/internal/validation/contact.go:182.2,182.12 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:186.38,190.40 2 23 +github.com/juanatsap/cv-site/internal/validation/contact.go:190.40,192.3 1 2 +github.com/juanatsap/cv-site/internal/validation/contact.go:195.2,196.21 2 21 +github.com/juanatsap/cv-site/internal/validation/contact.go:196.21,198.3 1 4 +github.com/juanatsap/cv-site/internal/validation/contact.go:200.2,204.40 3 17 +github.com/juanatsap/cv-site/internal/validation/contact.go:204.40,206.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:209.2,209.36 1 16 +github.com/juanatsap/cv-site/internal/validation/contact.go:209.36,211.3 1 2 +github.com/juanatsap/cv-site/internal/validation/contact.go:215.2,217.38 2 14 +github.com/juanatsap/cv-site/internal/validation/contact.go:222.44,224.36 1 30 +github.com/juanatsap/cv-site/internal/validation/contact.go:224.36,226.3 1 4 +github.com/juanatsap/cv-site/internal/validation/contact.go:229.2,244.44 3 26 +github.com/juanatsap/cv-site/internal/validation/contact.go:244.44,245.40 1 224 +github.com/juanatsap/cv-site/internal/validation/contact.go:245.40,247.4 1 8 +github.com/juanatsap/cv-site/internal/validation/contact.go:250.2,250.14 1 18 +github.com/juanatsap/cv-site/internal/validation/contact.go:255.36,258.16 2 18 +github.com/juanatsap/cv-site/internal/validation/contact.go:258.16,260.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:264.2,266.36 2 17 +github.com/juanatsap/cv-site/internal/validation/contact.go:271.42,274.19 2 11 +github.com/juanatsap/cv-site/internal/validation/contact.go:274.19,276.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:279.2,281.42 2 10 +github.com/juanatsap/cv-site/internal/validation/contact.go:286.42,289.19 2 9 +github.com/juanatsap/cv-site/internal/validation/contact.go:289.19,291.3 1 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:294.2,296.42 2 8 +github.com/juanatsap/cv-site/internal/validation/contact.go:301.51,320.2 11 1 +github.com/juanatsap/cv-site/internal/validation/contact.go:323.38,327.2 3 8 +github.com/juanatsap/cv-site/internal/validation/contact.go:330.43,340.2 5 5 diff --git a/internal/config/config.go b/internal/config/config.go index 2b6fce6..40ad7a4 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -5,7 +5,7 @@ import ( "os" "strconv" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // Config holds all application configuration @@ -50,7 +50,7 @@ type EmailConfig struct { func Load() *Config { return &Config{ Server: ServerConfig{ - Port: getEnv(constants.EnvVarPort, constants.DefaultPort), + Port: getEnv(c.EnvVarPort, c.DefaultPort), Host: getEnv("HOST", "localhost"), ReadTimeout: getEnvAsInt("READ_TIMEOUT", 15), WriteTimeout: getEnvAsInt("WRITE_TIMEOUT", 15), @@ -105,6 +105,6 @@ func getEnvAsBool(key string, defaultValue bool) bool { } func isDevelopment() bool { - env := getEnv(constants.EnvVarGOEnv, constants.EnvDevelopment) - return env == constants.EnvDevelopment || env == "dev" + env := getEnv(c.EnvVarGOEnv, c.EnvDevelopment) + return env == c.EnvDevelopment || env == "dev" } diff --git a/internal/constants/constants.go b/internal/constants/constants.go index 1480974..2751ff1 100644 --- a/internal/constants/constants.go +++ b/internal/constants/constants.go @@ -12,6 +12,7 @@ const ( ContentTypeHTML = "text/html; charset=utf-8" ContentTypeHTMLFragment = "text/html" // For HTMX fragments ContentTypePlainText = "text/plain; charset=utf-8" + ContentTypePlainSimple = "text/plain" // For Accept header matching ContentTypePDF = "application/pdf" ContentTypeFormURLEnc = "application/x-www-form-urlencoded" ) diff --git a/internal/handlers/contact.go b/internal/handlers/contact.go index cb37d6f..b9b1c64 100644 --- a/internal/handlers/contact.go +++ b/internal/handlers/contact.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" "github.com/juanatsap/cv-site/internal/services" "github.com/juanatsap/cv-site/internal/templates" ) @@ -143,7 +143,7 @@ func (h *ContactHandler) Submit(w http.ResponseWriter, r *http.Request) { // renderSuccess renders the success partial func (h *ContactHandler) renderSuccess(w http.ResponseWriter, r *http.Request) { - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) w.WriteHeader(http.StatusOK) // Fallback HTML for when templates aren't available (e.g., in tests) @@ -173,7 +173,7 @@ func (h *ContactHandler) renderSuccess(w http.ResponseWriter, r *http.Request) { // renderError renders the error partial func (h *ContactHandler) renderError(w http.ResponseWriter, r *http.Request, message string) { - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) w.WriteHeader(http.StatusBadRequest) // Fallback HTML for when templates aren't available (e.g., in tests) diff --git a/internal/handlers/cv_cmdk.go b/internal/handlers/cv_cmdk.go index 9669dee..ffd6f29 100644 --- a/internal/handlers/cv_cmdk.go +++ b/internal/handlers/cv_cmdk.go @@ -5,7 +5,7 @@ import ( "log" "net/http" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" "github.com/juanatsap/cv-site/internal/httputil" ) @@ -89,8 +89,8 @@ func (h *CVHandler) CmdKData(w http.ResponseWriter, r *http.Request) { } // Set headers and encode response - w.Header().Set(constants.HeaderContentType, constants.ContentTypeJSON) - w.Header().Set(constants.HeaderCacheControl, constants.CachePublic1Hour) + w.Header().Set(c.HeaderContentType, c.ContentTypeJSON) + w.Header().Set(c.HeaderCacheControl, c.CachePublic1Hour) if err := json.NewEncoder(w).Encode(response); err != nil { log.Printf("ERROR encoding CMD+K response: %v", err) diff --git a/internal/handlers/cv_contact.go b/internal/handlers/cv_contact.go index 64e7744..722c29a 100644 --- a/internal/handlers/cv_contact.go +++ b/internal/handlers/cv_contact.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" "github.com/juanatsap/cv-site/internal/httputil" "github.com/juanatsap/cv-site/internal/services" ) @@ -173,7 +173,7 @@ func (h *CVHandler) renderContactSuccess(w http.ResponseWriter, r *http.Request, } // Render the success template - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) w.WriteHeader(http.StatusOK) tmpl, err := h.templates.Render("contact-success") @@ -224,7 +224,7 @@ func (h *CVHandler) renderContactError(w http.ResponseWriter, r *http.Request, e // Render the error template // Return 200 OK with error content - HTMX 1.9.x logs console.error for non-2xx responses // Validation errors are expected form feedback, not system errors - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) w.WriteHeader(http.StatusOK) tmpl, err := h.templates.Render("contact-error") diff --git a/internal/handlers/cv_helpers.go b/internal/handlers/cv_helpers.go index aaf04d4..f8aab15 100644 --- a/internal/handlers/cv_helpers.go +++ b/internal/handlers/cv_helpers.go @@ -11,7 +11,7 @@ import ( "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" cvmodel "github.com/juanatsap/cv-site/internal/models/cv" ) @@ -343,7 +343,7 @@ func (h *CVHandler) prepareTemplateData(lang string) (map[string]interface{}, er // Check if production mode AND CSS bundle exists // This ensures graceful fallback to modular CSS if bundle not built - isProduction := os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction + isProduction := os.Getenv(c.EnvVarGOEnv) == c.EnvProduction if isProduction { bundlePath := filepath.Join("static", "dist", "bundle.min.css") if _, err := os.Stat(bundlePath); os.IsNotExist(err) { diff --git a/internal/handlers/cv_htmx.go b/internal/handlers/cv_htmx.go index b141846..fd831ef 100644 --- a/internal/handlers/cv_htmx.go +++ b/internal/handlers/cv_htmx.go @@ -3,7 +3,7 @@ package handlers import ( "net/http" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" "github.com/juanatsap/cv-site/internal/httputil" "github.com/juanatsap/cv-site/internal/middleware" ) @@ -25,13 +25,13 @@ func (h *CVHandler) ToggleLength(w http.ResponseWriter, r *http.Request) { currentLength := prefs.CVLength // Toggle state - newLength := constants.CVLengthLong - if currentLength == constants.CVLengthLong { - newLength = constants.CVLengthShort + newLength := c.CVLengthLong + if currentLength == c.CVLengthLong { + newLength = c.CVLengthShort } // Save new state - middleware.SetPreferenceCookie(w, constants.CookieCVLength, newLength) + middleware.SetPreferenceCookie(w, c.CookieCVLength, newLength) // Return 204 No Content - frontend uses hx-swap="none" so response body is ignored // The cookie is set and hyperscript handles the UI state toggle @@ -49,13 +49,13 @@ func (h *CVHandler) ToggleIcons(w http.ResponseWriter, r *http.Request) { currentIcons := prefs.CVIcons // Toggle state - newIcons := constants.CVIconsHide - if currentIcons == constants.CVIconsHide { - newIcons = constants.CVIconsShow + newIcons := c.CVIconsHide + if currentIcons == c.CVIconsHide { + newIcons = c.CVIconsShow } // Save new state - middleware.SetPreferenceCookie(w, constants.CookieCVIcons, newIcons) + middleware.SetPreferenceCookie(w, c.CookieCVIcons, newIcons) // Return 204 No Content - frontend uses hx-swap="none" so response body is ignored // The cookie is set and hyperscript handles the UI state toggle @@ -73,7 +73,7 @@ func (h *CVHandler) SwitchLanguage(w http.ResponseWriter, r *http.Request) { } // Save language preference - middleware.SetPreferenceCookie(w, constants.CookieCVLanguage, lang) + middleware.SetPreferenceCookie(w, c.CookieCVLanguage, lang) // Prepare template data data, err := h.prepareTemplateData(lang) @@ -86,13 +86,13 @@ func (h *CVHandler) SwitchLanguage(w http.ResponseWriter, r *http.Request) { prefs := middleware.GetPreferences(r) // Add preferences to data - if prefs.CVLength == constants.CVLengthLong { + if prefs.CVLength == c.CVLengthLong { data["CVLengthClass"] = "cv-long" } else { data["CVLengthClass"] = "cv-short" } - data["ShowIcons"] = (prefs.CVIcons == constants.CVIconsShow) - data["ThemeClean"] = (prefs.CVTheme == constants.CVThemeClean) + data["ShowIcons"] = (prefs.CVIcons == c.CVIconsShow) + data["ThemeClean"] = (prefs.CVTheme == c.CVThemeClean) // Render language-switch template with out-of-band swaps tmpl, err := h.templates.Render("language-switch.html") @@ -101,7 +101,7 @@ func (h *CVHandler) SwitchLanguage(w http.ResponseWriter, r *http.Request) { return } - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) if err := tmpl.Execute(w, data); err != nil { HandleError(w, r, TemplateError(err, "language-switch.html")) return @@ -119,13 +119,13 @@ func (h *CVHandler) ToggleTheme(w http.ResponseWriter, r *http.Request) { currentTheme := prefs.CVTheme // Toggle state - newTheme := constants.CVThemeClean - if currentTheme == constants.CVThemeClean { - newTheme = constants.CVThemeDefault + newTheme := c.CVThemeClean + if currentTheme == c.CVThemeClean { + newTheme = c.CVThemeDefault } // Save new state - middleware.SetPreferenceCookie(w, constants.CookieCVTheme, newTheme) + middleware.SetPreferenceCookie(w, c.CookieCVTheme, newTheme) // Return 204 No Content - frontend uses hx-swap="none" so response body is ignored // The cookie is set and hyperscript handles the UI state toggle diff --git a/internal/handlers/cv_pages.go b/internal/handlers/cv_pages.go index 2942235..e0e993b 100644 --- a/internal/handlers/cv_pages.go +++ b/internal/handlers/cv_pages.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" "github.com/juanatsap/cv-site/internal/httputil" "github.com/juanatsap/cv-site/internal/middleware" "github.com/juanatsap/cv-site/internal/pdf" @@ -70,7 +70,7 @@ func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) { return } - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) if err := tmpl.Execute(w, data); err != nil { HandleError(w, r, TemplateError(err, "index.html")) return @@ -99,7 +99,7 @@ func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request) { return } - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) if err := tmpl.Execute(w, data); err != nil { HandleError(w, r, TemplateError(err, "cv-content.html")) return @@ -127,7 +127,7 @@ func (h *CVHandler) DefaultCVShortcut(w http.ResponseWriter, r *http.Request) { lang := strings.TrimSuffix(langWithExt, ".pdf") // Validate language - if !constants.SupportedLanguages[lang] { + if !c.SupportedLanguages[lang] { http.NotFound(w, r) return } @@ -147,11 +147,11 @@ func (h *CVHandler) DefaultCVShortcut(w http.ResponseWriter, r *http.Request) { // Prepare cookies for PDF generation (short, with_skills, light mode) cookies := map[string]string{ - constants.CookieCVLength: constants.CVLengthShort, - constants.CookieCVIcons: constants.CVIconsShow, - constants.CookieCVLanguage: lang, - constants.CookieCVTheme: constants.CVThemeDefault, // with_skills = default theme - constants.CookieColorTheme: constants.ColorThemeLight, // Always light for PDFs + c.CookieCVLength: c.CVLengthShort, + c.CookieCVIcons: c.CVIconsShow, + c.CookieCVLanguage: lang, + c.CookieCVTheme: c.CVThemeDefault, // with_skills = default theme + c.CookieColorTheme: c.ColorThemeLight, // Always light for PDFs } // Construct URL for PDF generation @@ -170,9 +170,9 @@ func (h *CVHandler) DefaultCVShortcut(w http.ResponseWriter, r *http.Request) { filename := filepath.Base(path) // cv-jamr-2025-en.pdf // Set response headers with shortcut filename - w.Header().Set(constants.HeaderContentType, constants.ContentTypePDF) - w.Header().Set(constants.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s", filename)) - w.Header().Set(constants.HeaderContentLength, fmt.Sprintf("%d", len(pdfData))) + w.Header().Set(c.HeaderContentType, c.ContentTypePDF) + w.Header().Set(c.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s", filename)) + w.Header().Set(c.HeaderContentLength, fmt.Sprintf("%d", len(pdfData))) // Write PDF data if _, err := w.Write(pdfData); err != nil { diff --git a/internal/handlers/cv_pdf.go b/internal/handlers/cv_pdf.go index 55f5682..0eb7bf0 100644 --- a/internal/handlers/cv_pdf.go +++ b/internal/handlers/cv_pdf.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" cvmodel "github.com/juanatsap/cv-site/internal/models/cv" "github.com/juanatsap/cv-site/internal/pdf" ) @@ -38,21 +38,21 @@ func (h *CVHandler) ExportPDF(w http.ResponseWriter, r *http.Request) { // Prepare cookies to set preferences cookies := map[string]string{ - constants.CookieCVLength: req.Length, - constants.CookieCVIcons: req.Icons, - constants.CookieCVLanguage: req.Lang, + c.CookieCVLength: req.Length, + c.CookieCVIcons: req.Icons, + c.CookieCVLanguage: req.Lang, } // Set theme cookie based on version parameter - if req.Version == constants.CVThemeClean { - cookies[constants.CookieCVTheme] = constants.CVThemeClean + if req.Version == c.CVThemeClean { + cookies[c.CookieCVTheme] = c.CVThemeClean } else { - cookies[constants.CookieCVTheme] = constants.CVThemeDefault + cookies[c.CookieCVTheme] = c.CVThemeDefault } // CRITICAL: ALWAYS force light mode for PDF generation (print-friendly) // This ensures PDFs are NEVER generated in dark mode, regardless of user's preference - cookies[constants.CookieColorTheme] = constants.ColorThemeLight + cookies[c.CookieColorTheme] = c.ColorThemeLight // Construct URL for PDF generation (navigate to home page) targetURL := fmt.Sprintf("http://%s/?lang=%s", h.serverAddr, req.Lang) @@ -111,9 +111,9 @@ func (h *CVHandler) ExportPDF(w http.ResponseWriter, r *http.Request) { } // Set response headers - w.Header().Set(constants.HeaderContentType, constants.ContentTypePDF) - w.Header().Set(constants.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s", filename)) - w.Header().Set(constants.HeaderContentLength, fmt.Sprintf("%d", len(pdfData))) + w.Header().Set(c.HeaderContentType, c.ContentTypePDF) + w.Header().Set(c.HeaderContentDisposition, fmt.Sprintf("attachment; filename=%s", filename)) + w.Header().Set(c.HeaderContentLength, fmt.Sprintf("%d", len(pdfData))) // Write PDF data if _, err := w.Write(pdfData); err != nil { diff --git a/internal/handlers/cv_text.go b/internal/handlers/cv_text.go index e1aea33..6163887 100644 --- a/internal/handlers/cv_text.go +++ b/internal/handlers/cv_text.go @@ -11,7 +11,7 @@ import ( "text/template" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" "github.com/juanatsap/cv-site/internal/httputil" ) @@ -36,7 +36,7 @@ var textBrowsers = []string{ // isTextBrowser detects if the request comes from a text-based browser or CLI tool func isTextBrowser(r *http.Request) bool { - ua := strings.ToLower(r.Header.Get("User-Agent")) + ua := strings.ToLower(r.Header.Get(c.HeaderUserAgent)) // Check for known text browsers for _, browser := range textBrowsers { @@ -46,8 +46,8 @@ func isTextBrowser(r *http.Request) bool { } // Check Accept header - if client prefers text/plain - accept := r.Header.Get("Accept") - return strings.HasPrefix(accept, "text/plain") + accept := r.Header.Get(c.HeaderAccept) + return strings.HasPrefix(accept, c.ContentTypePlainSimple) } // ============================================================================== @@ -150,8 +150,8 @@ func (h *CVHandler) PlainText(w http.ResponseWriter, r *http.Request) { text := cleanPlainText(buf.String()) // Set response headers - w.Header().Set(constants.HeaderContentType, constants.ContentTypePlainText) - w.Header().Set(constants.HeaderXContentTypeOpts, constants.NoSniff) + w.Header().Set(c.HeaderContentType, c.ContentTypePlainText) + w.Header().Set(c.HeaderXContentTypeOpts, c.NoSniff) // Check if download is requested if r.URL.Query().Get("download") == "true" { diff --git a/internal/handlers/errors.go b/internal/handlers/errors.go index 3c487da..a1e0cda 100644 --- a/internal/handlers/errors.go +++ b/internal/handlers/errors.go @@ -6,7 +6,7 @@ import ( "log" "net/http" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // ErrorResponse represents a structured error response @@ -64,12 +64,12 @@ func HandleError(w http.ResponseWriter, r *http.Request, err error) { // Determine response based on Accept header accept := r.Header.Get("Accept") - isJSON := accept == constants.ContentTypeJSON - isHTMX := r.Header.Get(constants.HeaderHXRequest) != "" + isJSON := accept == c.ContentTypeJSON + isHTMX := r.Header.Get(c.HeaderHXRequest) != "" if isJSON { // JSON response - w.Header().Set(constants.HeaderContentType, constants.ContentTypeJSON) + w.Header().Set(c.HeaderContentType, c.ContentTypeJSON) w.WriteHeader(appErr.StatusCode) response := ErrorResponse{ @@ -90,7 +90,7 @@ func HandleError(w http.ResponseWriter, r *http.Request, err error) { if isHTMX { // HTMX response - return simple HTML fragment - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTMLFragment) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTMLFragment) w.WriteHeader(appErr.StatusCode) message := appErr.Message diff --git a/internal/handlers/health.go b/internal/handlers/health.go index dfcef92..348bee2 100644 --- a/internal/handlers/health.go +++ b/internal/handlers/health.go @@ -6,7 +6,7 @@ import ( "net/http" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // HealthResponse represents the health check response @@ -36,7 +36,7 @@ func (h *HealthHandler) Check(w http.ResponseWriter, r *http.Request) { Version: h.version, } - w.Header().Set(constants.HeaderContentType, constants.ContentTypeJSON) + w.Header().Set(c.HeaderContentType, c.ContentTypeJSON) w.WriteHeader(http.StatusOK) if err := json.NewEncoder(w).Encode(response); err != nil { log.Printf("ERROR encoding health check response: %v", err) diff --git a/internal/httputil/request.go b/internal/httputil/request.go index 903c41d..31067b3 100644 --- a/internal/httputil/request.go +++ b/internal/httputil/request.go @@ -4,15 +4,15 @@ package httputil import ( "net/http" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // Lang extracts and validates the language from query params. // Returns the language or default if invalid/missing. func Lang(r *http.Request) string { lang := r.URL.Query().Get("lang") - if lang == "" || !constants.SupportedLanguages[lang] { - return constants.LangDefault + if lang == "" || !c.SupportedLanguages[lang] { + return c.LangDefault } return lang } @@ -22,9 +22,9 @@ func Lang(r *http.Request) string { func LangOrError(r *http.Request) (string, bool) { lang := r.URL.Query().Get("lang") if lang == "" { - return constants.LangDefault, true + return c.LangDefault, true } - if !constants.SupportedLanguages[lang] { + if !c.SupportedLanguages[lang] { return "", false } return lang, true diff --git a/internal/httputil/response.go b/internal/httputil/response.go index 9cda311..45247ed 100644 --- a/internal/httputil/response.go +++ b/internal/httputil/response.go @@ -2,12 +2,15 @@ package httputil import ( "encoding/json" + "fmt" "net/http" + + c "github.com/juanatsap/cv-site/internal/constants" ) // JSON writes a JSON response with the given status code. func JSON(w http.ResponseWriter, status int, data interface{}) error { - w.Header().Set("Content-Type", "application/json") + w.Header().Set(c.HeaderContentType, c.ContentTypeJSON) w.WriteHeader(status) return json.NewEncoder(w).Encode(data) } @@ -19,13 +22,13 @@ func JSONOk(w http.ResponseWriter, data interface{}) error { // JSONCached writes a JSON response with caching headers. func JSONCached(w http.ResponseWriter, data interface{}, maxAge int) error { - w.Header().Set("Cache-Control", "public, max-age="+string(rune(maxAge))) + w.Header().Set(c.HeaderCacheControl, fmt.Sprintf("public, max-age=%d", maxAge)) return JSONOk(w, data) } // HTML sets HTML content type header. func HTML(w http.ResponseWriter) { - w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) } // NoContent sends a 204 No Content response. diff --git a/internal/middleware/browser_only.go b/internal/middleware/browser_only.go index 495aa14..2af0d94 100644 --- a/internal/middleware/browser_only.go +++ b/internal/middleware/browser_only.go @@ -5,7 +5,7 @@ import ( "net/http" "strings" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) const ( @@ -23,7 +23,7 @@ const ( func BrowserOnly(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Check 1: User-Agent validation - userAgent := r.Header.Get(constants.HeaderUserAgent) + userAgent := r.Header.Get(c.HeaderUserAgent) if userAgent == "" || isBotUserAgent(userAgent) { log.Printf("SECURITY: Blocked non-browser User-Agent from IP %s: %s", getRequestIP(r), userAgent) http.Error(w, "Forbidden: Browser access only", http.StatusForbidden) @@ -31,8 +31,8 @@ func BrowserOnly(next http.Handler) http.Handler { } // Check 2: Require Referer or Origin header - referer := r.Header.Get(constants.HeaderReferer) - origin := r.Header.Get(constants.HeaderOrigin) + referer := r.Header.Get(c.HeaderReferer) + origin := r.Header.Get(c.HeaderOrigin) if referer == "" && origin == "" { log.Printf("SECURITY: Blocked request without Referer/Origin from IP %s", getRequestIP(r)) @@ -43,7 +43,7 @@ func BrowserOnly(next http.Handler) http.Handler { // Check 3: Custom header validation (set by JavaScript) // For HTMX requests, check HX-Request header // For fetch/XMLHttpRequest, check X-Requested-With header - hasHTMXHeader := r.Header.Get(constants.HeaderHXRequest) == "true" + hasHTMXHeader := r.Header.Get(c.HeaderHXRequest) == "true" hasXMLHTTPHeader := r.Header.Get(browserHeaderName) == browserHeaderValue hasCustomBrowserHeader := r.Header.Get("X-Browser-Request") == "true" @@ -98,7 +98,7 @@ func isBotUserAgent(ua string) bool { // getRequestIP extracts the client IP from the request func getRequestIP(r *http.Request) string { // Try X-Forwarded-For first (for proxies/load balancers) - ip := r.Header.Get(constants.HeaderXForwardedFor) + ip := r.Header.Get(c.HeaderXForwardedFor) if ip != "" { // Take first IP if multiple ips := strings.Split(ip, ",") @@ -106,7 +106,7 @@ func getRequestIP(r *http.Request) string { } // Try X-Real-IP - ip = r.Header.Get(constants.HeaderXRealIP) + ip = r.Header.Get(c.HeaderXRealIP) if ip != "" { return ip } diff --git a/internal/middleware/contact_rate_limit.go b/internal/middleware/contact_rate_limit.go index d4997a9..c337add 100644 --- a/internal/middleware/contact_rate_limit.go +++ b/internal/middleware/contact_rate_limit.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // contactRateLimitEntry tracks rate limiting for contact form per IP @@ -39,9 +39,9 @@ func NewContactRateLimiter() *ContactRateLimiter { func (rl *ContactRateLimiter) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Get client IP (handle X-Forwarded-For for proxies) - ip := r.Header.Get(constants.HeaderXForwardedFor) + ip := r.Header.Get(c.HeaderXForwardedFor) if ip == "" { - ip = r.Header.Get(constants.HeaderXRealIP) + ip = r.Header.Get(c.HeaderXRealIP) } if ip == "" { ip = strings.Split(r.RemoteAddr, ":")[0] @@ -54,18 +54,18 @@ func (rl *ContactRateLimiter) Middleware(next http.Handler) http.Handler { if !rl.allow(ip) { // Check if HTMX request - isHTMX := r.Header.Get(constants.HeaderHXRequest) != "" + isHTMX := r.Header.Get(c.HeaderHXRequest) != "" if isHTMX { // Return HTMX-friendly error - w.Header().Set(constants.HeaderContentType, constants.ContentTypeHTML) + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) w.WriteHeader(http.StatusTooManyRequests) _, _ = w.Write([]byte(`

Too Many Requests

You've submitted too many contact forms. Please wait an hour before trying again.

`)) } else { - w.Header().Set(constants.HeaderRetryAfter, "3600") // 1 hour + w.Header().Set(c.HeaderRetryAfter, "3600") // 1 hour http.Error(w, "Too many contact form submissions. Please try again in an hour.", http.StatusTooManyRequests) } return diff --git a/internal/middleware/csrf.go b/internal/middleware/csrf.go index 7bb1f3b..5507e3f 100644 --- a/internal/middleware/csrf.go +++ b/internal/middleware/csrf.go @@ -8,6 +8,8 @@ import ( "net/http" "sync" "time" + + c "github.com/juanatsap/cv-site/internal/constants" ) const ( @@ -44,18 +46,18 @@ func NewCSRFProtection() *CSRFProtection { // Middleware provides CSRF protection for state-changing operations // GET requests: Generate and set CSRF token // POST/PUT/DELETE: Validate CSRF token -func (c *CSRFProtection) Middleware(next http.Handler) http.Handler { +func (csrf *CSRFProtection) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Only validate on state-changing methods if r.Method == http.MethodPost || r.Method == http.MethodPut || r.Method == http.MethodDelete { - if !c.validateToken(r) { + if !csrf.validateToken(r) { log.Printf("SECURITY: CSRF validation failed from IP %s", getClientIP(r)) // Check if HTMX request - isHTMX := r.Header.Get("HX-Request") != "" + isHTMX := r.Header.Get(c.HeaderHXRequest) != "" if isHTMX { - w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Header().Set(c.HeaderContentType, c.ContentTypeHTML) w.WriteHeader(http.StatusForbidden) _, _ = w.Write([]byte(`

Security Error

@@ -73,7 +75,7 @@ func (c *CSRFProtection) Middleware(next http.Handler) http.Handler { } // generateToken creates a new CSRF token -func (c *CSRFProtection) generateToken() (string, error) { +func (csrf *CSRFProtection) generateToken() (string, error) { bytes := make([]byte, csrfTokenLength) if _, err := rand.Read(bytes); err != nil { return "", err @@ -82,26 +84,26 @@ func (c *CSRFProtection) generateToken() (string, error) { token := base64.URLEncoding.EncodeToString(bytes) // Store token with expiration - c.mu.Lock() - c.tokens[token] = &csrfTokenEntry{ + csrf.mu.Lock() + csrf.tokens[token] = &csrfTokenEntry{ token: token, expiresAt: time.Now().Add(csrfTokenTTL), } - c.mu.Unlock() + csrf.mu.Unlock() return token, nil } // GetToken retrieves or generates a CSRF token for the request // This should be called when rendering forms -func (c *CSRFProtection) GetToken(w http.ResponseWriter, r *http.Request) (string, error) { +func (csrf *CSRFProtection) GetToken(w http.ResponseWriter, r *http.Request) (string, error) { // Check if token exists in cookie cookie, err := r.Cookie(csrfCookieName) if err == nil && cookie.Value != "" { // Validate existing token - c.mu.RLock() - entry, exists := c.tokens[cookie.Value] - c.mu.RUnlock() + csrf.mu.RLock() + entry, exists := csrf.tokens[cookie.Value] + csrf.mu.RUnlock() if exists && time.Now().Before(entry.expiresAt) { // Token is valid, return it @@ -110,7 +112,7 @@ func (c *CSRFProtection) GetToken(w http.ResponseWriter, r *http.Request) (strin } // Generate new token - token, err := c.generateToken() + token, err := csrf.generateToken() if err != nil { return "", fmt.Errorf("failed to generate CSRF token: %w", err) } @@ -130,7 +132,7 @@ func (c *CSRFProtection) GetToken(w http.ResponseWriter, r *http.Request) (strin } // validateToken validates the CSRF token from the request -func (c *CSRFProtection) validateToken(r *http.Request) bool { +func (csrf *CSRFProtection) validateToken(r *http.Request) bool { // Get token from form var formToken string @@ -163,9 +165,9 @@ func (c *CSRFProtection) validateToken(r *http.Request) bool { } // Validate token exists and is not expired - c.mu.RLock() - entry, exists := c.tokens[formToken] - c.mu.RUnlock() + csrf.mu.RLock() + entry, exists := csrf.tokens[formToken] + csrf.mu.RUnlock() if !exists { log.Printf("CSRF: Token not found in store") @@ -181,19 +183,19 @@ func (c *CSRFProtection) validateToken(r *http.Request) bool { } // cleanup removes expired tokens periodically -func (c *CSRFProtection) cleanup() { +func (csrf *CSRFProtection) cleanup() { ticker := time.NewTicker(1 * time.Hour) defer ticker.Stop() for range ticker.C { - c.mu.Lock() + csrf.mu.Lock() now := time.Now() - for token, entry := range c.tokens { + for token, entry := range csrf.tokens { if now.After(entry.expiresAt) { - delete(c.tokens, token) + delete(csrf.tokens, token) } } - c.mu.Unlock() + csrf.mu.Unlock() } } diff --git a/internal/middleware/preferences.go b/internal/middleware/preferences.go index 9862e26..17fd53c 100644 --- a/internal/middleware/preferences.go +++ b/internal/middleware/preferences.go @@ -5,7 +5,7 @@ import ( "net/http" "os" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // contextKey is a private type for context keys to avoid collisions @@ -30,22 +30,22 @@ type Preferences struct { func PreferencesMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { prefs := &Preferences{ - CVLength: getPreferenceCookie(r, constants.CookieCVLength, constants.CVLengthShort), - CVIcons: getPreferenceCookie(r, constants.CookieCVIcons, constants.CVIconsShow), - CVLanguage: getPreferenceCookie(r, constants.CookieCVLanguage, constants.LangEnglish), - CVTheme: getPreferenceCookie(r, constants.CookieCVTheme, constants.CVThemeDefault), - ColorTheme: getPreferenceCookie(r, constants.CookieColorTheme, constants.ColorThemeLight), + CVLength: getPreferenceCookie(r, c.CookieCVLength, c.CVLengthShort), + CVIcons: getPreferenceCookie(r, c.CookieCVIcons, c.CVIconsShow), + CVLanguage: getPreferenceCookie(r, c.CookieCVLanguage, c.LangEnglish), + CVTheme: getPreferenceCookie(r, c.CookieCVTheme, c.CVThemeDefault), + ColorTheme: getPreferenceCookie(r, c.CookieColorTheme, c.ColorThemeLight), } // Migrate old preference values (one-time auto-migration) if prefs.CVLength == "extended" { - prefs.CVLength = constants.CVLengthLong + prefs.CVLength = c.CVLengthLong } switch prefs.CVIcons { case "true": - prefs.CVIcons = constants.CVIconsShow + prefs.CVIcons = c.CVIconsShow case "false": - prefs.CVIcons = constants.CVIconsHide + prefs.CVIcons = c.CVIconsHide } // Store preferences in context @@ -60,11 +60,11 @@ func GetPreferences(r *http.Request) *Preferences { if !ok { // Return default preferences if not found return &Preferences{ - CVLength: constants.CVLengthShort, - CVIcons: constants.CVIconsShow, - CVLanguage: constants.LangEnglish, - CVTheme: constants.CVThemeDefault, - ColorTheme: constants.ColorThemeLight, + CVLength: c.CVLengthShort, + CVIcons: c.CVIconsShow, + CVLanguage: c.LangEnglish, + CVTheme: c.CVThemeDefault, + ColorTheme: c.ColorThemeLight, } } return prefs @@ -102,42 +102,42 @@ func GetColorTheme(r *http.Request) string { // IsLongCV returns true if the user prefers long CV format func IsLongCV(r *http.Request) bool { - return GetCVLength(r) == constants.CVLengthLong + return GetCVLength(r) == c.CVLengthLong } // IsShortCV returns true if the user prefers short CV format func IsShortCV(r *http.Request) bool { - return GetCVLength(r) == constants.CVLengthShort + return GetCVLength(r) == c.CVLengthShort } // ShowIcons returns true if icons should be visible func ShowIcons(r *http.Request) bool { - return GetCVIcons(r) == constants.CVIconsShow + return GetCVIcons(r) == c.CVIconsShow } // HideIcons returns true if icons should be hidden func HideIcons(r *http.Request) bool { - return GetCVIcons(r) == constants.CVIconsHide + return GetCVIcons(r) == c.CVIconsHide } // IsCleanTheme returns true if clean theme is selected func IsCleanTheme(r *http.Request) bool { - return GetCVTheme(r) == constants.CVThemeClean + return GetCVTheme(r) == c.CVThemeClean } // IsDefaultTheme returns true if default theme is selected func IsDefaultTheme(r *http.Request) bool { - return GetCVTheme(r) == constants.CVThemeDefault + return GetCVTheme(r) == c.CVThemeDefault } // IsDarkMode returns true if dark mode is enabled func IsDarkMode(r *http.Request) bool { - return GetColorTheme(r) == constants.ColorThemeDark + return GetColorTheme(r) == c.ColorThemeDark } // IsLightMode returns true if light mode is enabled func IsLightMode(r *http.Request) bool { - return GetColorTheme(r) == constants.ColorThemeLight + return GetColorTheme(r) == c.ColorThemeLight } // SetPreferenceCookie sets a preference cookie (1 year expiry) @@ -145,8 +145,8 @@ func SetPreferenceCookie(w http.ResponseWriter, name string, value string) { http.SetCookie(w, &http.Cookie{ Name: name, Value: value, - Path: constants.CookiePath, - MaxAge: constants.CookieMaxAge, + Path: c.CookiePath, + MaxAge: c.CookieMaxAge, HttpOnly: true, SameSite: http.SameSiteStrictMode, Secure: isProductionMode(), // Secure in production with HTTPS @@ -155,8 +155,8 @@ func SetPreferenceCookie(w http.ResponseWriter, name string, value string) { // isProductionMode checks if the application is running in production func isProductionMode() bool { - env := os.Getenv(constants.EnvVarGOEnv) - return env == constants.EnvProduction || env == "prod" + env := os.Getenv(c.EnvVarGOEnv) + return env == c.EnvProduction || env == "prod" } // getPreferenceCookie gets a preference cookie value, returns default if not found diff --git a/internal/middleware/security.go b/internal/middleware/security.go index d7b8a2e..ef0acb3 100644 --- a/internal/middleware/security.go +++ b/internal/middleware/security.go @@ -7,26 +7,26 @@ import ( "sync" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // SecurityHeaders adds production-grade security headers to responses func SecurityHeaders(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Prevent clickjacking - w.Header().Set(constants.HeaderXFrameOptions, constants.FrameOptionsSameOrigin) + w.Header().Set(c.HeaderXFrameOptions, c.FrameOptionsSameOrigin) // Prevent MIME type sniffing - w.Header().Set(constants.HeaderXContentTypeOpts, constants.NoSniff) + w.Header().Set(c.HeaderXContentTypeOpts, c.NoSniff) // XSS Protection (legacy but still useful for older browsers) - w.Header().Set(constants.HeaderXXSSProtection, constants.XSSProtection) + w.Header().Set(c.HeaderXXSSProtection, c.XSSProtection) // Referrer policy - strict privacy - w.Header().Set(constants.HeaderReferrerPolicy, constants.ReferrerPolicy) + w.Header().Set(c.HeaderReferrerPolicy, c.ReferrerPolicy) // Permissions Policy - disable unnecessary features - w.Header().Set(constants.HeaderPermissionsPolicy, + w.Header().Set(c.HeaderPermissionsPolicy, "geolocation=(), microphone=(), camera=(), payment=(), usb=(), "+ "magnetometer=(), gyroscope=(), accelerometer=()") @@ -40,12 +40,12 @@ func SecurityHeaders(next http.Handler) http.Handler { "frame-ancestors 'self'; " + "base-uri 'self'; " + "form-action 'self'" - w.Header().Set(constants.HeaderCSP, csp) + w.Header().Set(c.HeaderCSP, csp) // HSTS - only in production with HTTPS - if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction { + if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction { // 1 year max-age, include subdomains - w.Header().Set(constants.HeaderHSTS, constants.HSTSMaxAge) + w.Header().Set(c.HeaderHSTS, c.HSTSMaxAge) } next.ServeHTTP(w, r) @@ -76,7 +76,7 @@ func OriginChecker(next http.Handler) http.Handler { } // Check Origin header (for CORS requests) - origin := r.Header.Get(constants.HeaderOrigin) + origin := r.Header.Get(c.HeaderOrigin) if origin != "" { if !isAllowedOrigin(origin, allowedOrigins) { http.Error(w, "Forbidden: External access not allowed", http.StatusForbidden) @@ -85,7 +85,7 @@ func OriginChecker(next http.Handler) http.Handler { } // Check Referer header (for direct requests) - referer := r.Header.Get(constants.HeaderReferer) + referer := r.Header.Get(c.HeaderReferer) if referer != "" { if !isAllowedOrigin(referer, allowedOrigins) { http.Error(w, "Forbidden: External access not allowed", http.StatusForbidden) @@ -98,7 +98,7 @@ func OriginChecker(next http.Handler) http.Handler { if origin == "" && referer == "" { // For production, you might want to be stricter here // For now, allow it (users can bookmark /export/pdf directly) - if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction && r.URL.Path == constants.RouteExportPDF { + if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction && r.URL.Path == c.RouteExportPDF { // In production, require at least a referer for PDF endpoint http.Error(w, "Forbidden: Direct access not allowed", http.StatusForbidden) return @@ -163,16 +163,16 @@ func NewRateLimiter(limit int, window time.Duration) *RateLimiter { func (rl *RateLimiter) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Get client IP (handle X-Forwarded-For for proxies) - ip := r.Header.Get(constants.HeaderXForwardedFor) + ip := r.Header.Get(c.HeaderXForwardedFor) if ip == "" { - ip = r.Header.Get(constants.HeaderXRealIP) + ip = r.Header.Get(c.HeaderXRealIP) } if ip == "" { ip = strings.Split(r.RemoteAddr, ":")[0] } if !rl.allow(ip) { - w.Header().Set(constants.HeaderRetryAfter, "60") + w.Header().Set(c.HeaderRetryAfter, "60") http.Error(w, "Rate limit exceeded. Please try again later.", http.StatusTooManyRequests) return } @@ -227,12 +227,12 @@ func (rl *RateLimiter) cleanup() { // 1 hour in development, 1 day in production func CacheControl(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - cacheValue := constants.CachePublic1Hour - if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction { - cacheValue = constants.CachePublic1Day + cacheValue := c.CachePublic1Hour + if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction { + cacheValue = c.CachePublic1Day } - w.Header().Set(constants.HeaderCacheControl, cacheValue) + w.Header().Set(c.HeaderCacheControl, cacheValue) next.ServeHTTP(w, r) }) } @@ -243,12 +243,12 @@ func DynamicCacheControl(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // For dynamic HTML pages: short cache, must revalidate // This improves performance while ensuring fresh content - if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction { + if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction { // Production: 5 minutes cache, but must revalidate - w.Header().Set(constants.HeaderCacheControl, constants.CachePublic5Min) + w.Header().Set(c.HeaderCacheControl, c.CachePublic5Min) } else { // Development: no cache for easier testing - w.Header().Set(constants.HeaderCacheControl, constants.CacheNoStore) + w.Header().Set(c.HeaderCacheControl, c.CacheNoStore) } next.ServeHTTP(w, r) }) diff --git a/internal/middleware/security_logger.go b/internal/middleware/security_logger.go index cae0dff..657881a 100644 --- a/internal/middleware/security_logger.go +++ b/internal/middleware/security_logger.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/juanatsap/cv-site/internal/constants" + c "github.com/juanatsap/cv-site/internal/constants" ) // SecurityEvent represents a security-related event @@ -57,7 +57,7 @@ func LogSecurityEvent(eventType string, r *http.Request, details string) { EventType: eventType, Severity: severity, IP: getClientIP(r), - UserAgent: r.Header.Get(constants.HeaderUserAgent), + UserAgent: r.Header.Get(c.HeaderUserAgent), Method: r.Method, Path: r.URL.Path, Details: details, @@ -74,7 +74,7 @@ func LogSecurityEvent(eventType string, r *http.Request, details string) { log.Printf("[SECURITY] %s", eventJSON) // Also log to separate security log file in production - if os.Getenv(constants.EnvVarGOEnv) == constants.EnvProduction { + if os.Getenv(c.EnvVarGOEnv) == c.EnvProduction { logToSecurityFile(eventJSON) } } @@ -99,14 +99,14 @@ func getSeverity(eventType string) string { // getClientIP extracts the real client IP from request headers func getClientIP(r *http.Request) string { // Check X-Forwarded-For header (proxy/load balancer) - if xff := r.Header.Get(constants.HeaderXForwardedFor); xff != "" { + if xff := r.Header.Get(c.HeaderXForwardedFor); xff != "" { // Take first IP from comma-separated list ips := strings.Split(xff, ",") return strings.TrimSpace(ips[0]) } // Check X-Real-IP header - if xri := r.Header.Get(constants.HeaderXRealIP); xri != "" { + if xri := r.Header.Get(c.HeaderXRealIP); xri != "" { return xri } @@ -181,7 +181,7 @@ func SecurityLogger(next http.Handler) http.Handler { EventType: "REQUEST", Severity: SeverityInfo, IP: getClientIP(r), - UserAgent: r.Header.Get(constants.HeaderUserAgent), + UserAgent: r.Header.Get(c.HeaderUserAgent), Method: r.Method, Path: r.URL.Path, Details: string(detailsJSON), @@ -203,7 +203,7 @@ func SecurityLogger(next http.Handler) http.Handler { EventType: "HTTP_ERROR", Severity: severity, IP: getClientIP(r), - UserAgent: r.Header.Get(constants.HeaderUserAgent), + UserAgent: r.Header.Get(c.HeaderUserAgent), Method: r.Method, Path: r.URL.Path, Details: http.StatusText(wrapped.status),