From 6135ca060320638d690d79db71316e166fbe7726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdinand=20M=C3=BCtsch?= Date: Thu, 28 Sep 2023 13:41:10 +0200 Subject: [PATCH] feat(wip): implement activity chart generation (see #12) --- coverage/coverage.out | 697 +++++++++++++----------- go.mod | 2 +- go.sum | 21 +- main.go | 4 + models/summary.go | 21 + models/view/projects.go | 2 +- routes/api/activity.go | 67 +++ routes/api/avatar.go | 6 +- services/activity.go | 121 ++++ services/imports/wakatime_heartbeats.go | 2 + services/services.go | 4 + services/user.go | 18 + utils/color.go | 21 +- utils/http.go | 1 + 14 files changed, 656 insertions(+), 331 deletions(-) create mode 100644 routes/api/activity.go create mode 100644 services/activity.go diff --git a/coverage/coverage.out b/coverage/coverage.out index 17f4cb2b..b82e7d8e 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -368,6 +368,152 @@ github.com/muety/wakapi/middlewares/sentry.go:16.43,20.3 1 0 github.com/muety/wakapi/middlewares/sentry.go:23.78,26.54 3 0 github.com/muety/wakapi/middlewares/sentry.go:26.54,27.43 1 0 github.com/muety/wakapi/middlewares/sentry.go:27.43,29.4 1 0 +github.com/muety/wakapi/routes/api/activity.go:22.126,28.2 1 0 +github.com/muety/wakapi/routes/api/activity.go:30.64,39.2 4 0 +github.com/muety/wakapi/routes/api/activity.go:42.87,45.16 3 0 +github.com/muety/wakapi/routes/api/activity.go:45.16,48.3 2 0 +github.com/muety/wakapi/routes/api/activity.go:50.2,50.68 1 0 +github.com/muety/wakapi/routes/api/activity.go:50.68,51.159 1 0 +github.com/muety/wakapi/routes/api/activity.go:51.159,54.4 2 0 +github.com/muety/wakapi/routes/api/activity.go:57.2,58.16 2 0 +github.com/muety/wakapi/routes/api/activity.go:58.16,62.3 3 0 +github.com/muety/wakapi/routes/api/activity.go:65.2,68.24 4 0 +github.com/muety/wakapi/routes/api/avatar.go:19.40,21.16 2 0 +github.com/muety/wakapi/routes/api/avatar.go:21.16,22.13 1 0 +github.com/muety/wakapi/routes/api/avatar.go:25.2,28.3 1 0 +github.com/muety/wakapi/routes/api/avatar.go:31.59,36.2 4 0 +github.com/muety/wakapi/routes/api/avatar.go:38.69,41.37 2 0 +github.com/muety/wakapi/routes/api/avatar.go:41.37,43.3 1 0 +github.com/muety/wakapi/routes/api/avatar.go:45.2,45.29 1 0 +github.com/muety/wakapi/routes/api/avatar.go:45.29,47.3 1 0 +github.com/muety/wakapi/routes/api/avatar.go:48.2,53.32 5 0 +github.com/muety/wakapi/routes/api/badge.go:27.112,34.2 1 1 +github.com/muety/wakapi/routes/api/badge.go:36.58,38.2 1 1 +github.com/muety/wakapi/routes/api/badge.go:40.68,42.16 2 1 +github.com/muety/wakapi/routes/api/badge.go:42.16,45.3 2 0 +github.com/muety/wakapi/routes/api/badge.go:47.2,48.16 2 1 +github.com/muety/wakapi/routes/api/badge.go:48.16,52.3 3 1 +github.com/muety/wakapi/routes/api/badge.go:54.2,56.62 3 1 +github.com/muety/wakapi/routes/api/badge.go:56.62,59.3 2 0 +github.com/muety/wakapi/routes/api/badge.go:61.2,69.16 3 1 +github.com/muety/wakapi/routes/api/badge.go:69.16,73.3 3 0 +github.com/muety/wakapi/routes/api/badge.go:75.2,76.66 2 1 +github.com/muety/wakapi/routes/api/badge.go:76.66,78.3 1 0 +github.com/muety/wakapi/routes/api/badge.go:79.2,79.66 1 1 +github.com/muety/wakapi/routes/api/badge.go:79.66,81.3 1 0 +github.com/muety/wakapi/routes/api/badge.go:83.2,83.101 1 1 +github.com/muety/wakapi/routes/api/badge.go:83.101,85.3 1 1 +github.com/muety/wakapi/routes/api/badge.go:87.2,89.25 3 1 +github.com/muety/wakapi/routes/api/badge.go:92.53,97.2 4 1 +github.com/muety/wakapi/routes/api/diagnostics.go:20.138,26.2 1 0 +github.com/muety/wakapi/routes/api/diagnostics.go:28.67,30.2 1 0 +github.com/muety/wakapi/routes/api/diagnostics.go:39.78,42.69 2 0 +github.com/muety/wakapi/routes/api/diagnostics.go:42.69,47.3 4 0 +github.com/muety/wakapi/routes/api/diagnostics.go:49.2,49.66 1 0 +github.com/muety/wakapi/routes/api/diagnostics.go:49.66,54.3 4 0 +github.com/muety/wakapi/routes/api/diagnostics.go:56.2,56.59 1 0 +github.com/muety/wakapi/routes/api/health.go:15.57,17.2 1 0 +github.com/muety/wakapi/routes/api/health.go:19.62,21.2 1 0 +github.com/muety/wakapi/routes/api/health.go:29.72,31.41 2 0 +github.com/muety/wakapi/routes/api/health.go:31.41,32.38 1 0 +github.com/muety/wakapi/routes/api/health.go:32.38,34.4 1 0 +github.com/muety/wakapi/routes/api/health.go:37.2,38.56 2 0 +github.com/muety/wakapi/routes/api/heartbeat.go:26.187,33.2 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:39.65,40.34 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:40.34,54.3 9 0 +github.com/muety/wakapi/routes/api/heartbeat.go:65.76,67.16 2 0 +github.com/muety/wakapi/routes/api/heartbeat.go:67.16,69.3 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:71.2,73.16 3 0 +github.com/muety/wakapi/routes/api/heartbeat.go:73.16,78.3 4 0 +github.com/muety/wakapi/routes/api/heartbeat.go:80.2,84.32 4 0 +github.com/muety/wakapi/routes/api/heartbeat.go:84.32,85.16 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:85.16,89.4 3 0 +github.com/muety/wakapi/routes/api/heartbeat.go:92.3,92.25 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:92.25,97.4 4 0 +github.com/muety/wakapi/routes/api/heartbeat.go:98.3,98.23 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:98.23,100.4 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:102.3,109.65 7 0 +github.com/muety/wakapi/routes/api/heartbeat.go:109.65,113.4 3 0 +github.com/muety/wakapi/routes/api/heartbeat.go:115.3,115.14 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:118.2,118.64 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:118.64,123.3 4 0 +github.com/muety/wakapi/routes/api/heartbeat.go:125.2,125.19 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:125.19,127.52 2 0 +github.com/muety/wakapi/routes/api/heartbeat.go:127.52,132.4 4 0 +github.com/muety/wakapi/routes/api/heartbeat.go:135.2,135.15 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:135.16,135.17 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:137.2,137.90 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:146.59,149.25 2 0 +github.com/muety/wakapi/routes/api/heartbeat.go:149.25,154.3 4 0 +github.com/muety/wakapi/routes/api/heartbeat.go:156.2,158.3 1 0 +github.com/muety/wakapi/routes/api/heartbeat.go:172.45,172.46 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:183.45,183.46 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:194.45,194.46 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:204.45,204.46 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:215.45,215.46 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:226.45,226.46 0 0 +github.com/muety/wakapi/routes/api/heartbeat.go:237.45,237.46 0 0 +github.com/muety/wakapi/routes/api/metrics.go:64.249,73.2 1 0 +github.com/muety/wakapi/routes/api/metrics.go:75.60,76.38 1 0 +github.com/muety/wakapi/routes/api/metrics.go:76.38,78.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:80.2,86.29 5 0 +github.com/muety/wakapi/routes/api/metrics.go:89.70,91.20 2 0 +github.com/muety/wakapi/routes/api/metrics.go:91.20,95.3 3 0 +github.com/muety/wakapi/routes/api/metrics.go:97.2,99.63 2 0 +github.com/muety/wakapi/routes/api/metrics.go:99.63,104.3 4 0 +github.com/muety/wakapi/routes/api/metrics.go:104.8,105.34 1 0 +github.com/muety/wakapi/routes/api/metrics.go:105.34,107.4 1 0 +github.com/muety/wakapi/routes/api/metrics.go:110.2,110.21 1 0 +github.com/muety/wakapi/routes/api/metrics.go:110.21,111.66 1 0 +github.com/muety/wakapi/routes/api/metrics.go:111.66,116.4 4 0 +github.com/muety/wakapi/routes/api/metrics.go:116.9,117.36 1 0 +github.com/muety/wakapi/routes/api/metrics.go:117.36,119.5 1 0 +github.com/muety/wakapi/routes/api/metrics.go:123.2,126.34 3 0 +github.com/muety/wakapi/routes/api/metrics.go:129.81,133.16 3 0 +github.com/muety/wakapi/routes/api/metrics.go:133.16,136.3 2 0 +github.com/muety/wakapi/routes/api/metrics.go:138.2,141.16 3 0 +github.com/muety/wakapi/routes/api/metrics.go:141.16,144.3 2 0 +github.com/muety/wakapi/routes/api/metrics.go:146.2,147.16 2 0 +github.com/muety/wakapi/routes/api/metrics.go:147.16,150.3 2 0 +github.com/muety/wakapi/routes/api/metrics.go:154.2,175.42 4 0 +github.com/muety/wakapi/routes/api/metrics.go:175.42,182.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:184.2,184.43 1 0 +github.com/muety/wakapi/routes/api/metrics.go:184.43,191.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:193.2,193.41 1 0 +github.com/muety/wakapi/routes/api/metrics.go:193.41,200.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:202.2,202.50 1 0 +github.com/muety/wakapi/routes/api/metrics.go:202.50,209.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:211.2,211.42 1 0 +github.com/muety/wakapi/routes/api/metrics.go:211.42,218.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:220.2,220.40 1 0 +github.com/muety/wakapi/routes/api/metrics.go:220.40,227.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:230.2,270.16 9 0 +github.com/muety/wakapi/routes/api/metrics.go:270.16,272.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:274.2,282.44 2 0 +github.com/muety/wakapi/routes/api/metrics.go:282.44,296.3 2 0 +github.com/muety/wakapi/routes/api/metrics.go:298.2,298.22 1 0 +github.com/muety/wakapi/routes/api/metrics.go:301.82,307.19 4 0 +github.com/muety/wakapi/routes/api/metrics.go:307.19,309.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:311.2,312.106 2 0 +github.com/muety/wakapi/routes/api/metrics.go:312.106,313.56 1 0 +github.com/muety/wakapi/routes/api/metrics.go:313.56,315.4 1 0 +github.com/muety/wakapi/routes/api/metrics.go:318.2,323.16 5 0 +github.com/muety/wakapi/routes/api/metrics.go:323.16,326.3 2 0 +github.com/muety/wakapi/routes/api/metrics.go:327.2,360.16 7 0 +github.com/muety/wakapi/routes/api/metrics.go:360.16,363.3 2 0 +github.com/muety/wakapi/routes/api/metrics.go:365.2,365.32 1 0 +github.com/muety/wakapi/routes/api/metrics.go:365.32,372.3 1 0 +github.com/muety/wakapi/routes/api/metrics.go:373.2,383.29 6 0 +github.com/muety/wakapi/routes/api/metrics.go:383.29,384.20 1 0 +github.com/muety/wakapi/routes/api/metrics.go:384.20,386.18 2 0 +github.com/muety/wakapi/routes/api/metrics.go:386.18,389.5 2 0 +github.com/muety/wakapi/routes/api/metrics.go:390.4,397.6 3 0 +github.com/muety/wakapi/routes/api/metrics.go:401.2,404.22 3 0 +github.com/muety/wakapi/routes/api/summary.go:20.122,26.2 1 0 +github.com/muety/wakapi/routes/api/summary.go:28.63,34.2 4 0 +github.com/muety/wakapi/routes/api/summary.go:53.73,55.16 2 0 +github.com/muety/wakapi/routes/api/summary.go:55.16,59.3 3 0 +github.com/muety/wakapi/routes/api/summary.go:61.2,61.51 1 0 github.com/muety/wakapi/models/alias.go:18.32,20.2 1 0 github.com/muety/wakapi/models/alias.go:22.37,23.35 1 0 github.com/muety/wakapi/models/alias.go:23.35,24.18 1 0 @@ -622,108 +768,111 @@ github.com/muety/wakapi/models/shared.go:85.45,87.2 1 1 github.com/muety/wakapi/models/shared.go:89.37,91.2 1 0 github.com/muety/wakapi/models/shared.go:93.35,95.2 1 1 github.com/muety/wakapi/models/shared.go:97.34,99.2 1 0 -github.com/muety/wakapi/models/summary.go:68.29,70.2 1 1 -github.com/muety/wakapi/models/summary.go:72.35,74.2 1 0 -github.com/muety/wakapi/models/summary.go:76.38,78.2 1 0 -github.com/muety/wakapi/models/summary.go:80.37,90.2 9 1 -github.com/muety/wakapi/models/summary.go:92.35,94.2 1 1 -github.com/muety/wakapi/models/summary.go:96.57,107.2 1 1 -github.com/muety/wakapi/models/summary.go:109.64,110.21 1 1 -github.com/muety/wakapi/models/summary.go:111.22,112.21 1 1 -github.com/muety/wakapi/models/summary.go:113.23,114.22 1 1 -github.com/muety/wakapi/models/summary.go:115.21,116.20 1 1 -github.com/muety/wakapi/models/summary.go:117.17,118.29 1 1 -github.com/muety/wakapi/models/summary.go:119.22,120.21 1 1 -github.com/muety/wakapi/models/summary.go:121.20,122.19 1 1 -github.com/muety/wakapi/models/summary.go:123.21,124.21 1 1 -github.com/muety/wakapi/models/summary.go:125.21,126.21 1 1 -github.com/muety/wakapi/models/summary.go:128.2,128.12 1 0 -github.com/muety/wakapi/models/summary.go:131.59,132.21 1 1 -github.com/muety/wakapi/models/summary.go:132.21,134.3 1 1 -github.com/muety/wakapi/models/summary.go:136.2,136.35 1 1 -github.com/muety/wakapi/models/summary.go:136.35,137.41 1 1 -github.com/muety/wakapi/models/summary.go:137.41,139.4 1 1 -github.com/muety/wakapi/models/summary.go:142.2,142.10 1 1 -github.com/muety/wakapi/models/summary.go:158.33,163.26 4 1 -github.com/muety/wakapi/models/summary.go:163.26,164.30 1 1 -github.com/muety/wakapi/models/summary.go:164.30,166.4 1 1 -github.com/muety/wakapi/models/summary.go:170.2,170.37 1 1 -github.com/muety/wakapi/models/summary.go:170.37,172.3 1 0 -github.com/muety/wakapi/models/summary.go:175.2,176.16 2 1 -github.com/muety/wakapi/models/summary.go:176.16,178.3 1 0 -github.com/muety/wakapi/models/summary.go:179.2,179.33 1 1 -github.com/muety/wakapi/models/summary.go:179.33,181.3 1 1 -github.com/muety/wakapi/models/summary.go:185.56,191.28 5 1 -github.com/muety/wakapi/models/summary.go:191.28,193.3 1 1 -github.com/muety/wakapi/models/summary.go:195.2,196.42 2 1 -github.com/muety/wakapi/models/summary.go:196.42,197.22 1 0 -github.com/muety/wakapi/models/summary.go:197.22,199.9 2 0 -github.com/muety/wakapi/models/summary.go:203.2,204.15 2 1 -github.com/muety/wakapi/models/summary.go:204.15,205.28 1 1 -github.com/muety/wakapi/models/summary.go:205.28,207.4 1 0 -github.com/muety/wakapi/models/summary.go:207.9,213.4 1 1 -github.com/muety/wakapi/models/summary.go:217.45,222.16 4 1 -github.com/muety/wakapi/models/summary.go:222.16,224.3 1 0 -github.com/muety/wakapi/models/summary.go:225.2,225.39 1 1 -github.com/muety/wakapi/models/summary.go:225.39,227.3 1 1 -github.com/muety/wakapi/models/summary.go:229.2,229.30 1 1 -github.com/muety/wakapi/models/summary.go:232.73,234.55 2 1 -github.com/muety/wakapi/models/summary.go:234.55,235.31 1 1 -github.com/muety/wakapi/models/summary.go:235.31,237.4 1 1 -github.com/muety/wakapi/models/summary.go:239.2,239.16 1 1 -github.com/muety/wakapi/models/summary.go:242.88,244.55 2 1 -github.com/muety/wakapi/models/summary.go:244.55,245.31 1 1 -github.com/muety/wakapi/models/summary.go:245.31,246.23 1 1 -github.com/muety/wakapi/models/summary.go:246.23,247.13 1 1 -github.com/muety/wakapi/models/summary.go:249.4,249.46 1 1 -github.com/muety/wakapi/models/summary.go:252.2,252.16 1 1 -github.com/muety/wakapi/models/summary.go:255.73,257.34 2 1 -github.com/muety/wakapi/models/summary.go:257.34,259.3 1 1 -github.com/muety/wakapi/models/summary.go:260.2,260.14 1 1 -github.com/muety/wakapi/models/summary.go:263.56,266.55 3 0 -github.com/muety/wakapi/models/summary.go:266.55,267.31 1 0 -github.com/muety/wakapi/models/summary.go:267.31,268.44 1 0 -github.com/muety/wakapi/models/summary.go:268.44,270.5 1 0 -github.com/muety/wakapi/models/summary.go:273.2,273.12 1 0 -github.com/muety/wakapi/models/summary.go:276.58,278.16 2 0 -github.com/muety/wakapi/models/summary.go:278.16,280.3 1 0 -github.com/muety/wakapi/models/summary.go:281.2,281.16 1 0 -github.com/muety/wakapi/models/summary.go:284.71,285.63 1 1 -github.com/muety/wakapi/models/summary.go:285.63,286.20 1 1 -github.com/muety/wakapi/models/summary.go:286.20,288.4 1 1 -github.com/muety/wakapi/models/summary.go:290.3,292.45 2 1 -github.com/muety/wakapi/models/summary.go:292.45,293.32 1 1 -github.com/muety/wakapi/models/summary.go:293.32,294.24 1 1 -github.com/muety/wakapi/models/summary.go:294.24,296.6 1 1 -github.com/muety/wakapi/models/summary.go:298.4,298.14 1 1 -github.com/muety/wakapi/models/summary.go:301.3,301.31 1 1 -github.com/muety/wakapi/models/summary.go:301.31,303.60 1 1 -github.com/muety/wakapi/models/summary.go:303.60,305.5 1 1 -github.com/muety/wakapi/models/summary.go:308.3,308.31 1 1 -github.com/muety/wakapi/models/summary.go:308.31,310.60 1 1 -github.com/muety/wakapi/models/summary.go:310.60,311.55 1 1 -github.com/muety/wakapi/models/summary.go:311.55,313.6 1 1 -github.com/muety/wakapi/models/summary.go:313.11,321.6 1 1 -github.com/muety/wakapi/models/summary.go:325.3,325.16 1 1 -github.com/muety/wakapi/models/summary.go:329.2,338.10 8 1 -github.com/muety/wakapi/models/summary.go:341.57,342.30 1 1 -github.com/muety/wakapi/models/summary.go:342.30,343.28 1 1 -github.com/muety/wakapi/models/summary.go:343.28,345.4 1 1 -github.com/muety/wakapi/models/summary.go:347.2,347.43 1 0 -github.com/muety/wakapi/models/summary.go:350.43,352.2 1 0 -github.com/muety/wakapi/models/summary.go:354.49,355.21 1 0 -github.com/muety/wakapi/models/summary.go:355.21,357.3 1 0 -github.com/muety/wakapi/models/summary.go:358.2,359.54 2 0 -github.com/muety/wakapi/models/summary.go:362.51,363.27 1 0 -github.com/muety/wakapi/models/summary.go:363.27,365.3 1 0 -github.com/muety/wakapi/models/summary.go:366.2,367.19 2 0 -github.com/muety/wakapi/models/summary.go:370.50,374.2 1 1 -github.com/muety/wakapi/models/summary.go:376.30,378.2 1 0 -github.com/muety/wakapi/models/summary.go:380.40,382.2 1 0 -github.com/muety/wakapi/models/summary.go:384.35,386.2 1 0 -github.com/muety/wakapi/models/summary.go:388.33,390.2 1 1 -github.com/muety/wakapi/models/summary.go:392.43,394.2 1 1 -github.com/muety/wakapi/models/summary.go:396.38,398.2 1 1 +github.com/muety/wakapi/models/summary.go:70.29,72.2 1 1 +github.com/muety/wakapi/models/summary.go:74.35,76.2 1 0 +github.com/muety/wakapi/models/summary.go:78.38,80.2 1 0 +github.com/muety/wakapi/models/summary.go:82.33,93.2 1 0 +github.com/muety/wakapi/models/summary.go:95.37,105.2 9 1 +github.com/muety/wakapi/models/summary.go:107.35,109.2 1 1 +github.com/muety/wakapi/models/summary.go:111.57,122.2 1 1 +github.com/muety/wakapi/models/summary.go:124.64,125.21 1 1 +github.com/muety/wakapi/models/summary.go:126.22,127.21 1 1 +github.com/muety/wakapi/models/summary.go:128.23,129.22 1 1 +github.com/muety/wakapi/models/summary.go:130.21,131.20 1 1 +github.com/muety/wakapi/models/summary.go:132.17,133.29 1 1 +github.com/muety/wakapi/models/summary.go:134.22,135.21 1 1 +github.com/muety/wakapi/models/summary.go:136.20,137.19 1 1 +github.com/muety/wakapi/models/summary.go:138.21,139.21 1 1 +github.com/muety/wakapi/models/summary.go:140.21,141.21 1 1 +github.com/muety/wakapi/models/summary.go:143.2,143.12 1 0 +github.com/muety/wakapi/models/summary.go:146.59,147.21 1 1 +github.com/muety/wakapi/models/summary.go:147.21,149.3 1 1 +github.com/muety/wakapi/models/summary.go:151.2,151.35 1 1 +github.com/muety/wakapi/models/summary.go:151.35,152.41 1 1 +github.com/muety/wakapi/models/summary.go:152.41,154.4 1 1 +github.com/muety/wakapi/models/summary.go:157.2,157.10 1 1 +github.com/muety/wakapi/models/summary.go:173.33,178.26 4 1 +github.com/muety/wakapi/models/summary.go:178.26,179.30 1 1 +github.com/muety/wakapi/models/summary.go:179.30,181.4 1 1 +github.com/muety/wakapi/models/summary.go:185.2,185.37 1 1 +github.com/muety/wakapi/models/summary.go:185.37,187.3 1 0 +github.com/muety/wakapi/models/summary.go:190.2,191.16 2 1 +github.com/muety/wakapi/models/summary.go:191.16,193.3 1 0 +github.com/muety/wakapi/models/summary.go:194.2,194.33 1 1 +github.com/muety/wakapi/models/summary.go:194.33,196.3 1 1 +github.com/muety/wakapi/models/summary.go:200.56,206.28 5 1 +github.com/muety/wakapi/models/summary.go:206.28,208.3 1 1 +github.com/muety/wakapi/models/summary.go:210.2,211.42 2 1 +github.com/muety/wakapi/models/summary.go:211.42,212.22 1 0 +github.com/muety/wakapi/models/summary.go:212.22,214.9 2 0 +github.com/muety/wakapi/models/summary.go:218.2,219.15 2 1 +github.com/muety/wakapi/models/summary.go:219.15,220.28 1 1 +github.com/muety/wakapi/models/summary.go:220.28,222.4 1 0 +github.com/muety/wakapi/models/summary.go:222.9,228.4 1 1 +github.com/muety/wakapi/models/summary.go:232.45,237.16 4 1 +github.com/muety/wakapi/models/summary.go:237.16,239.3 1 0 +github.com/muety/wakapi/models/summary.go:240.2,240.39 1 1 +github.com/muety/wakapi/models/summary.go:240.39,242.3 1 1 +github.com/muety/wakapi/models/summary.go:244.2,244.30 1 1 +github.com/muety/wakapi/models/summary.go:247.73,249.55 2 1 +github.com/muety/wakapi/models/summary.go:249.55,250.31 1 1 +github.com/muety/wakapi/models/summary.go:250.31,252.4 1 1 +github.com/muety/wakapi/models/summary.go:254.2,254.16 1 1 +github.com/muety/wakapi/models/summary.go:257.88,259.55 2 1 +github.com/muety/wakapi/models/summary.go:259.55,260.31 1 1 +github.com/muety/wakapi/models/summary.go:260.31,261.23 1 1 +github.com/muety/wakapi/models/summary.go:261.23,262.13 1 1 +github.com/muety/wakapi/models/summary.go:264.4,264.46 1 1 +github.com/muety/wakapi/models/summary.go:267.2,267.16 1 1 +github.com/muety/wakapi/models/summary.go:270.73,272.34 2 1 +github.com/muety/wakapi/models/summary.go:272.34,274.3 1 1 +github.com/muety/wakapi/models/summary.go:275.2,275.14 1 1 +github.com/muety/wakapi/models/summary.go:278.56,281.55 3 0 +github.com/muety/wakapi/models/summary.go:281.55,282.31 1 0 +github.com/muety/wakapi/models/summary.go:282.31,283.44 1 0 +github.com/muety/wakapi/models/summary.go:283.44,285.5 1 0 +github.com/muety/wakapi/models/summary.go:288.2,288.12 1 0 +github.com/muety/wakapi/models/summary.go:291.58,293.16 2 0 +github.com/muety/wakapi/models/summary.go:293.16,295.3 1 0 +github.com/muety/wakapi/models/summary.go:296.2,296.16 1 0 +github.com/muety/wakapi/models/summary.go:299.71,300.63 1 1 +github.com/muety/wakapi/models/summary.go:300.63,301.20 1 1 +github.com/muety/wakapi/models/summary.go:301.20,303.4 1 1 +github.com/muety/wakapi/models/summary.go:305.3,307.45 2 1 +github.com/muety/wakapi/models/summary.go:307.45,308.32 1 1 +github.com/muety/wakapi/models/summary.go:308.32,309.24 1 1 +github.com/muety/wakapi/models/summary.go:309.24,311.6 1 1 +github.com/muety/wakapi/models/summary.go:313.4,313.14 1 1 +github.com/muety/wakapi/models/summary.go:316.3,316.31 1 1 +github.com/muety/wakapi/models/summary.go:316.31,318.60 1 1 +github.com/muety/wakapi/models/summary.go:318.60,320.5 1 1 +github.com/muety/wakapi/models/summary.go:323.3,323.31 1 1 +github.com/muety/wakapi/models/summary.go:323.31,325.60 1 1 +github.com/muety/wakapi/models/summary.go:325.60,326.55 1 1 +github.com/muety/wakapi/models/summary.go:326.55,328.6 1 1 +github.com/muety/wakapi/models/summary.go:328.11,336.6 1 1 +github.com/muety/wakapi/models/summary.go:340.3,340.16 1 1 +github.com/muety/wakapi/models/summary.go:344.2,353.10 8 1 +github.com/muety/wakapi/models/summary.go:356.57,357.30 1 1 +github.com/muety/wakapi/models/summary.go:357.30,358.28 1 1 +github.com/muety/wakapi/models/summary.go:358.28,360.4 1 1 +github.com/muety/wakapi/models/summary.go:362.2,362.43 1 0 +github.com/muety/wakapi/models/summary.go:365.43,367.2 1 0 +github.com/muety/wakapi/models/summary.go:369.49,370.21 1 0 +github.com/muety/wakapi/models/summary.go:370.21,372.3 1 0 +github.com/muety/wakapi/models/summary.go:373.2,374.54 2 0 +github.com/muety/wakapi/models/summary.go:377.51,378.27 1 0 +github.com/muety/wakapi/models/summary.go:378.27,380.3 1 0 +github.com/muety/wakapi/models/summary.go:381.2,382.19 2 0 +github.com/muety/wakapi/models/summary.go:385.50,389.2 1 1 +github.com/muety/wakapi/models/summary.go:391.49,392.101 1 0 +github.com/muety/wakapi/models/summary.go:392.101,394.3 1 0 +github.com/muety/wakapi/models/summary.go:397.30,399.2 1 0 +github.com/muety/wakapi/models/summary.go:401.40,403.2 1 0 +github.com/muety/wakapi/models/summary.go:405.35,407.2 1 0 +github.com/muety/wakapi/models/summary.go:409.33,411.2 1 1 +github.com/muety/wakapi/models/summary.go:413.43,415.2 1 1 +github.com/muety/wakapi/models/summary.go:417.38,419.2 1 1 github.com/muety/wakapi/models/user.go:13.13,15.2 1 1 github.com/muety/wakapi/models/user.go:90.34,92.2 1 0 github.com/muety/wakapi/models/user.go:94.36,95.22 1 1 @@ -946,142 +1095,6 @@ github.com/muety/wakapi/routes/compat/wakatime/v1/users.go:51.2,52.72 2 1 github.com/muety/wakapi/routes/compat/wakatime/v1/users.go:52.72,54.3 1 1 github.com/muety/wakapi/routes/compat/wakatime/v1/users.go:54.8,56.3 1 0 github.com/muety/wakapi/routes/compat/wakatime/v1/users.go:58.2,58.72 1 1 -github.com/muety/wakapi/routes/api/avatar.go:18.40,20.16 2 0 -github.com/muety/wakapi/routes/api/avatar.go:20.16,21.13 1 0 -github.com/muety/wakapi/routes/api/avatar.go:24.2,27.3 1 0 -github.com/muety/wakapi/routes/api/avatar.go:30.59,32.2 1 0 -github.com/muety/wakapi/routes/api/avatar.go:34.69,37.37 2 0 -github.com/muety/wakapi/routes/api/avatar.go:37.37,39.3 1 0 -github.com/muety/wakapi/routes/api/avatar.go:41.2,41.29 1 0 -github.com/muety/wakapi/routes/api/avatar.go:41.29,43.3 1 0 -github.com/muety/wakapi/routes/api/avatar.go:44.2,49.32 5 0 -github.com/muety/wakapi/routes/api/badge.go:27.112,34.2 1 1 -github.com/muety/wakapi/routes/api/badge.go:36.58,38.2 1 1 -github.com/muety/wakapi/routes/api/badge.go:40.68,42.16 2 1 -github.com/muety/wakapi/routes/api/badge.go:42.16,45.3 2 0 -github.com/muety/wakapi/routes/api/badge.go:47.2,48.16 2 1 -github.com/muety/wakapi/routes/api/badge.go:48.16,52.3 3 1 -github.com/muety/wakapi/routes/api/badge.go:54.2,56.62 3 1 -github.com/muety/wakapi/routes/api/badge.go:56.62,59.3 2 0 -github.com/muety/wakapi/routes/api/badge.go:61.2,69.16 3 1 -github.com/muety/wakapi/routes/api/badge.go:69.16,73.3 3 0 -github.com/muety/wakapi/routes/api/badge.go:75.2,76.66 2 1 -github.com/muety/wakapi/routes/api/badge.go:76.66,78.3 1 0 -github.com/muety/wakapi/routes/api/badge.go:79.2,79.66 1 1 -github.com/muety/wakapi/routes/api/badge.go:79.66,81.3 1 0 -github.com/muety/wakapi/routes/api/badge.go:83.2,83.101 1 1 -github.com/muety/wakapi/routes/api/badge.go:83.101,85.3 1 1 -github.com/muety/wakapi/routes/api/badge.go:87.2,89.25 3 1 -github.com/muety/wakapi/routes/api/badge.go:92.53,97.2 4 1 -github.com/muety/wakapi/routes/api/diagnostics.go:20.138,26.2 1 0 -github.com/muety/wakapi/routes/api/diagnostics.go:28.67,30.2 1 0 -github.com/muety/wakapi/routes/api/diagnostics.go:39.78,42.69 2 0 -github.com/muety/wakapi/routes/api/diagnostics.go:42.69,47.3 4 0 -github.com/muety/wakapi/routes/api/diagnostics.go:49.2,49.66 1 0 -github.com/muety/wakapi/routes/api/diagnostics.go:49.66,54.3 4 0 -github.com/muety/wakapi/routes/api/diagnostics.go:56.2,56.59 1 0 -github.com/muety/wakapi/routes/api/health.go:15.57,17.2 1 0 -github.com/muety/wakapi/routes/api/health.go:19.62,21.2 1 0 -github.com/muety/wakapi/routes/api/health.go:29.72,31.41 2 0 -github.com/muety/wakapi/routes/api/health.go:31.41,32.38 1 0 -github.com/muety/wakapi/routes/api/health.go:32.38,34.4 1 0 -github.com/muety/wakapi/routes/api/health.go:37.2,38.56 2 0 -github.com/muety/wakapi/routes/api/heartbeat.go:26.187,33.2 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:39.65,40.34 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:40.34,54.3 9 0 -github.com/muety/wakapi/routes/api/heartbeat.go:65.76,67.16 2 0 -github.com/muety/wakapi/routes/api/heartbeat.go:67.16,69.3 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:71.2,73.16 3 0 -github.com/muety/wakapi/routes/api/heartbeat.go:73.16,78.3 4 0 -github.com/muety/wakapi/routes/api/heartbeat.go:80.2,84.32 4 0 -github.com/muety/wakapi/routes/api/heartbeat.go:84.32,85.16 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:85.16,89.4 3 0 -github.com/muety/wakapi/routes/api/heartbeat.go:92.3,92.25 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:92.25,97.4 4 0 -github.com/muety/wakapi/routes/api/heartbeat.go:98.3,98.23 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:98.23,100.4 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:102.3,109.65 7 0 -github.com/muety/wakapi/routes/api/heartbeat.go:109.65,113.4 3 0 -github.com/muety/wakapi/routes/api/heartbeat.go:115.3,115.14 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:118.2,118.64 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:118.64,123.3 4 0 -github.com/muety/wakapi/routes/api/heartbeat.go:125.2,125.19 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:125.19,127.52 2 0 -github.com/muety/wakapi/routes/api/heartbeat.go:127.52,132.4 4 0 -github.com/muety/wakapi/routes/api/heartbeat.go:135.2,135.15 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:135.16,135.17 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:137.2,137.90 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:146.59,149.25 2 0 -github.com/muety/wakapi/routes/api/heartbeat.go:149.25,154.3 4 0 -github.com/muety/wakapi/routes/api/heartbeat.go:156.2,158.3 1 0 -github.com/muety/wakapi/routes/api/heartbeat.go:172.45,172.46 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:183.45,183.46 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:194.45,194.46 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:204.45,204.46 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:215.45,215.46 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:226.45,226.46 0 0 -github.com/muety/wakapi/routes/api/heartbeat.go:237.45,237.46 0 0 -github.com/muety/wakapi/routes/api/metrics.go:64.249,73.2 1 0 -github.com/muety/wakapi/routes/api/metrics.go:75.60,76.38 1 0 -github.com/muety/wakapi/routes/api/metrics.go:76.38,78.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:80.2,86.29 5 0 -github.com/muety/wakapi/routes/api/metrics.go:89.70,91.20 2 0 -github.com/muety/wakapi/routes/api/metrics.go:91.20,95.3 3 0 -github.com/muety/wakapi/routes/api/metrics.go:97.2,99.63 2 0 -github.com/muety/wakapi/routes/api/metrics.go:99.63,104.3 4 0 -github.com/muety/wakapi/routes/api/metrics.go:104.8,105.34 1 0 -github.com/muety/wakapi/routes/api/metrics.go:105.34,107.4 1 0 -github.com/muety/wakapi/routes/api/metrics.go:110.2,110.21 1 0 -github.com/muety/wakapi/routes/api/metrics.go:110.21,111.66 1 0 -github.com/muety/wakapi/routes/api/metrics.go:111.66,116.4 4 0 -github.com/muety/wakapi/routes/api/metrics.go:116.9,117.36 1 0 -github.com/muety/wakapi/routes/api/metrics.go:117.36,119.5 1 0 -github.com/muety/wakapi/routes/api/metrics.go:123.2,126.34 3 0 -github.com/muety/wakapi/routes/api/metrics.go:129.81,133.16 3 0 -github.com/muety/wakapi/routes/api/metrics.go:133.16,136.3 2 0 -github.com/muety/wakapi/routes/api/metrics.go:138.2,141.16 3 0 -github.com/muety/wakapi/routes/api/metrics.go:141.16,144.3 2 0 -github.com/muety/wakapi/routes/api/metrics.go:146.2,147.16 2 0 -github.com/muety/wakapi/routes/api/metrics.go:147.16,150.3 2 0 -github.com/muety/wakapi/routes/api/metrics.go:154.2,175.42 4 0 -github.com/muety/wakapi/routes/api/metrics.go:175.42,182.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:184.2,184.43 1 0 -github.com/muety/wakapi/routes/api/metrics.go:184.43,191.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:193.2,193.41 1 0 -github.com/muety/wakapi/routes/api/metrics.go:193.41,200.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:202.2,202.50 1 0 -github.com/muety/wakapi/routes/api/metrics.go:202.50,209.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:211.2,211.42 1 0 -github.com/muety/wakapi/routes/api/metrics.go:211.42,218.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:220.2,220.40 1 0 -github.com/muety/wakapi/routes/api/metrics.go:220.40,227.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:230.2,270.16 9 0 -github.com/muety/wakapi/routes/api/metrics.go:270.16,272.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:274.2,282.44 2 0 -github.com/muety/wakapi/routes/api/metrics.go:282.44,296.3 2 0 -github.com/muety/wakapi/routes/api/metrics.go:298.2,298.22 1 0 -github.com/muety/wakapi/routes/api/metrics.go:301.82,307.19 4 0 -github.com/muety/wakapi/routes/api/metrics.go:307.19,309.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:311.2,312.106 2 0 -github.com/muety/wakapi/routes/api/metrics.go:312.106,313.56 1 0 -github.com/muety/wakapi/routes/api/metrics.go:313.56,315.4 1 0 -github.com/muety/wakapi/routes/api/metrics.go:318.2,323.16 5 0 -github.com/muety/wakapi/routes/api/metrics.go:323.16,326.3 2 0 -github.com/muety/wakapi/routes/api/metrics.go:327.2,360.16 7 0 -github.com/muety/wakapi/routes/api/metrics.go:360.16,363.3 2 0 -github.com/muety/wakapi/routes/api/metrics.go:365.2,365.32 1 0 -github.com/muety/wakapi/routes/api/metrics.go:365.32,372.3 1 0 -github.com/muety/wakapi/routes/api/metrics.go:373.2,383.29 6 0 -github.com/muety/wakapi/routes/api/metrics.go:383.29,384.20 1 0 -github.com/muety/wakapi/routes/api/metrics.go:384.20,386.18 2 0 -github.com/muety/wakapi/routes/api/metrics.go:386.18,389.5 2 0 -github.com/muety/wakapi/routes/api/metrics.go:390.4,397.6 3 0 -github.com/muety/wakapi/routes/api/metrics.go:401.2,404.22 3 0 -github.com/muety/wakapi/routes/api/summary.go:20.122,26.2 1 0 -github.com/muety/wakapi/routes/api/summary.go:28.63,34.2 4 0 -github.com/muety/wakapi/routes/api/summary.go:53.73,55.16 2 0 -github.com/muety/wakapi/routes/api/summary.go:55.16,59.3 3 0 -github.com/muety/wakapi/routes/api/summary.go:61.2,61.51 1 0 github.com/muety/wakapi/utils/auth.go:15.79,17.54 2 0 github.com/muety/wakapi/utils/auth.go:17.54,19.3 1 0 github.com/muety/wakapi/utils/auth.go:21.2,23.16 3 0 @@ -1114,10 +1127,16 @@ github.com/muety/wakapi/utils/collection.go:17.22,18.18 1 0 github.com/muety/wakapi/utils/collection.go:18.18,20.4 1 0 github.com/muety/wakapi/utils/collection.go:21.3,21.12 1 0 github.com/muety/wakapi/utils/collection.go:23.2,23.11 1 0 -github.com/muety/wakapi/utils/color.go:8.45,11.16 2 0 +github.com/muety/wakapi/utils/color.go:8.41,11.16 2 0 github.com/muety/wakapi/utils/color.go:12.9,13.51 1 0 github.com/muety/wakapi/utils/color.go:14.9,18.12 4 0 github.com/muety/wakapi/utils/color.go:20.2,20.8 1 0 +github.com/muety/wakapi/utils/color.go:23.37,25.2 1 0 +github.com/muety/wakapi/utils/color.go:27.70,28.15 1 0 +github.com/muety/wakapi/utils/color.go:28.15,30.3 1 0 +github.com/muety/wakapi/utils/color.go:30.8,30.22 1 0 +github.com/muety/wakapi/utils/color.go:30.22,32.3 1 0 +github.com/muety/wakapi/utils/color.go:34.2,39.43 5 0 github.com/muety/wakapi/utils/cron.go:5.44,7.21 2 0 github.com/muety/wakapi/utils/cron.go:7.21,9.3 1 0 github.com/muety/wakapi/utils/cron.go:10.2,10.20 1 0 @@ -1171,36 +1190,36 @@ github.com/muety/wakapi/utils/http.go:38.2,38.19 1 0 github.com/muety/wakapi/utils/http.go:41.35,42.21 1 0 github.com/muety/wakapi/utils/http.go:42.21,44.3 1 0 github.com/muety/wakapi/utils/http.go:45.2,45.34 1 0 -github.com/muety/wakapi/utils/http.go:48.62,50.48 2 0 -github.com/muety/wakapi/utils/http.go:50.48,52.3 1 0 -github.com/muety/wakapi/utils/http.go:53.2,53.93 1 0 -github.com/muety/wakapi/utils/http.go:53.93,54.89 1 0 -github.com/muety/wakapi/utils/http.go:54.89,56.4 1 0 -github.com/muety/wakapi/utils/http.go:58.2,58.14 1 0 -github.com/muety/wakapi/utils/http.go:61.51,65.46 4 0 -github.com/muety/wakapi/utils/http.go:65.46,67.3 1 0 -github.com/muety/wakapi/utils/http.go:68.2,68.73 1 0 -github.com/muety/wakapi/utils/http.go:68.73,70.3 1 0 -github.com/muety/wakapi/utils/http.go:71.2,71.19 1 0 -github.com/muety/wakapi/utils/http.go:74.78,76.26 2 0 -github.com/muety/wakapi/utils/http.go:76.26,78.3 1 0 -github.com/muety/wakapi/utils/http.go:79.2,79.30 1 0 -github.com/muety/wakapi/utils/http.go:79.30,81.3 1 0 -github.com/muety/wakapi/utils/http.go:82.2,82.19 1 0 -github.com/muety/wakapi/utils/http.go:85.56,88.88 2 1 -github.com/muety/wakapi/utils/http.go:88.88,89.28 1 1 -github.com/muety/wakapi/utils/http.go:89.28,91.4 1 1 -github.com/muety/wakapi/utils/http.go:92.3,92.61 1 1 -github.com/muety/wakapi/utils/http.go:95.2,95.79 1 1 -github.com/muety/wakapi/utils/http.go:95.79,97.3 1 1 -github.com/muety/wakapi/utils/http.go:98.2,98.64 1 1 -github.com/muety/wakapi/utils/http.go:101.76,102.16 1 0 -github.com/muety/wakapi/utils/http.go:102.16,104.3 1 0 -github.com/muety/wakapi/utils/http.go:105.2,105.27 1 0 -github.com/muety/wakapi/utils/http.go:105.27,108.100 3 0 -github.com/muety/wakapi/utils/http.go:108.100,113.4 4 0 -github.com/muety/wakapi/utils/http.go:114.3,114.139 1 0 -github.com/muety/wakapi/utils/http.go:116.2,116.17 1 0 +github.com/muety/wakapi/utils/http.go:49.62,51.48 2 0 +github.com/muety/wakapi/utils/http.go:51.48,53.3 1 0 +github.com/muety/wakapi/utils/http.go:54.2,54.93 1 0 +github.com/muety/wakapi/utils/http.go:54.93,55.89 1 0 +github.com/muety/wakapi/utils/http.go:55.89,57.4 1 0 +github.com/muety/wakapi/utils/http.go:59.2,59.14 1 0 +github.com/muety/wakapi/utils/http.go:62.51,66.46 4 0 +github.com/muety/wakapi/utils/http.go:66.46,68.3 1 0 +github.com/muety/wakapi/utils/http.go:69.2,69.73 1 0 +github.com/muety/wakapi/utils/http.go:69.73,71.3 1 0 +github.com/muety/wakapi/utils/http.go:72.2,72.19 1 0 +github.com/muety/wakapi/utils/http.go:75.78,77.26 2 0 +github.com/muety/wakapi/utils/http.go:77.26,79.3 1 0 +github.com/muety/wakapi/utils/http.go:80.2,80.30 1 0 +github.com/muety/wakapi/utils/http.go:80.30,82.3 1 0 +github.com/muety/wakapi/utils/http.go:83.2,83.19 1 0 +github.com/muety/wakapi/utils/http.go:86.56,89.88 2 1 +github.com/muety/wakapi/utils/http.go:89.88,90.28 1 1 +github.com/muety/wakapi/utils/http.go:90.28,92.4 1 1 +github.com/muety/wakapi/utils/http.go:93.3,93.61 1 1 +github.com/muety/wakapi/utils/http.go:96.2,96.79 1 1 +github.com/muety/wakapi/utils/http.go:96.79,98.3 1 1 +github.com/muety/wakapi/utils/http.go:99.2,99.64 1 1 +github.com/muety/wakapi/utils/http.go:102.76,103.16 1 0 +github.com/muety/wakapi/utils/http.go:103.16,105.3 1 0 +github.com/muety/wakapi/utils/http.go:106.2,106.27 1 0 +github.com/muety/wakapi/utils/http.go:106.27,109.100 3 0 +github.com/muety/wakapi/utils/http.go:109.100,114.4 4 0 +github.com/muety/wakapi/utils/http.go:115.3,115.139 1 0 +github.com/muety/wakapi/utils/http.go:117.2,117.17 1 0 github.com/muety/wakapi/utils/json.go:12.75,18.62 2 0 github.com/muety/wakapi/utils/json.go:18.62,20.3 1 0 github.com/muety/wakapi/utils/json.go:22.2,22.29 1 0 @@ -1245,6 +1264,24 @@ github.com/muety/wakapi/utils/template.go:52.3,55.17 3 0 github.com/muety/wakapi/utils/template.go:55.17,57.4 1 0 github.com/muety/wakapi/utils/template.go:59.3,59.27 1 0 github.com/muety/wakapi/utils/template.go:62.2,62.23 1 0 +github.com/muety/wakapi/services/activity.go:34.74,40.2 1 0 +github.com/muety/wakapi/services/activity.go:44.117,46.65 2 0 +github.com/muety/wakapi/services/activity.go:46.65,48.3 1 0 +github.com/muety/wakapi/services/activity.go:50.2,50.18 1 0 +github.com/muety/wakapi/services/activity.go:51.35,53.17 2 0 +github.com/muety/wakapi/services/activity.go:53.17,55.4 1 0 +github.com/muety/wakapi/services/activity.go:56.3,56.20 1 0 +github.com/muety/wakapi/services/activity.go:57.10,58.48 1 0 +github.com/muety/wakapi/services/activity.go:62.79,65.16 3 0 +github.com/muety/wakapi/services/activity.go:65.16,67.3 1 0 +github.com/muety/wakapi/services/activity.go:69.2,76.37 5 0 +github.com/muety/wakapi/services/activity.go:76.37,80.20 3 0 +github.com/muety/wakapi/services/activity.go:80.20,83.18 3 0 +github.com/muety/wakapi/services/activity.go:83.18,90.5 6 0 +github.com/muety/wakapi/services/activity.go:91.4,93.16 3 0 +github.com/muety/wakapi/services/activity.go:97.2,110.30 7 0 +github.com/muety/wakapi/services/activity.go:110.30,117.3 6 0 +github.com/muety/wakapi/services/activity.go:118.2,120.26 2 0 github.com/muety/wakapi/services/aggregation.go:31.142,41.2 1 0 github.com/muety/wakapi/services/aggregation.go:50.43,53.52 2 0 github.com/muety/wakapi/services/aggregation.go:53.52,54.80 1 0 @@ -1884,59 +1921,69 @@ github.com/muety/wakapi/services/summary.go:486.33,488.5 1 1 github.com/muety/wakapi/services/summary.go:490.3,491.28 2 1 github.com/muety/wakapi/services/summary.go:491.28,493.4 1 1 github.com/muety/wakapi/services/summary.go:494.3,494.24 1 1 -github.com/muety/wakapi/services/user.go:26.99,36.33 3 0 -github.com/muety/wakapi/services/user.go:36.33,37.31 1 0 -github.com/muety/wakapi/services/user.go:37.31,43.73 4 0 -github.com/muety/wakapi/services/user.go:43.73,45.5 1 0 -github.com/muety/wakapi/services/user.go:47.4,47.24 1 0 -github.com/muety/wakapi/services/user.go:47.24,48.80 1 0 -github.com/muety/wakapi/services/user.go:48.80,50.6 1 0 -github.com/muety/wakapi/services/user.go:50.11,52.6 1 0 -github.com/muety/wakapi/services/user.go:57.2,57.12 1 0 -github.com/muety/wakapi/services/user.go:60.74,61.40 1 0 -github.com/muety/wakapi/services/user.go:61.40,63.3 1 0 -github.com/muety/wakapi/services/user.go:65.2,66.16 2 0 -github.com/muety/wakapi/services/user.go:66.16,68.3 1 0 -github.com/muety/wakapi/services/user.go:70.2,71.15 2 0 -github.com/muety/wakapi/services/user.go:74.72,75.37 1 0 -github.com/muety/wakapi/services/user.go:75.37,77.3 1 0 -github.com/muety/wakapi/services/user.go:79.2,80.16 2 0 -github.com/muety/wakapi/services/user.go:80.16,82.3 1 0 -github.com/muety/wakapi/services/user.go:84.2,85.15 2 0 -github.com/muety/wakapi/services/user.go:88.76,90.2 1 0 -github.com/muety/wakapi/services/user.go:92.86,94.2 1 0 -github.com/muety/wakapi/services/user.go:96.92,98.2 1 0 -github.com/muety/wakapi/services/user.go:100.58,102.2 1 0 -github.com/muety/wakapi/services/user.go:104.71,106.2 1 0 -github.com/muety/wakapi/services/user.go:108.86,110.16 2 0 -github.com/muety/wakapi/services/user.go:110.16,112.3 1 0 -github.com/muety/wakapi/services/user.go:113.2,113.112 1 0 -github.com/muety/wakapi/services/user.go:113.112,115.3 1 0 -github.com/muety/wakapi/services/user.go:118.86,120.2 1 0 -github.com/muety/wakapi/services/user.go:122.94,124.2 1 0 -github.com/muety/wakapi/services/user.go:126.71,128.12 2 0 -github.com/muety/wakapi/services/user.go:128.12,130.3 1 0 -github.com/muety/wakapi/services/user.go:132.2,133.42 2 0 -github.com/muety/wakapi/services/user.go:133.42,135.3 1 0 -github.com/muety/wakapi/services/user.go:137.2,138.16 2 0 -github.com/muety/wakapi/services/user.go:138.16,140.3 1 0 -github.com/muety/wakapi/services/user.go:142.2,143.21 2 0 -github.com/muety/wakapi/services/user.go:146.48,148.2 1 0 -github.com/muety/wakapi/services/user.go:150.102,160.95 2 0 -github.com/muety/wakapi/services/user.go:160.95,162.3 1 0 -github.com/muety/wakapi/services/user.go:162.8,164.3 1 0 -github.com/muety/wakapi/services/user.go:166.2,166.38 1 0 -github.com/muety/wakapi/services/user.go:169.73,173.2 3 0 -github.com/muety/wakapi/services/user.go:175.78,179.2 3 0 -github.com/muety/wakapi/services/user.go:181.122,184.35 2 0 -github.com/muety/wakapi/services/user.go:184.35,185.89 1 0 -github.com/muety/wakapi/services/user.go:185.89,187.4 1 0 -github.com/muety/wakapi/services/user.go:190.2,190.35 1 0 -github.com/muety/wakapi/services/user.go:190.35,192.3 1 0 -github.com/muety/wakapi/services/user.go:194.2,194.18 1 0 -github.com/muety/wakapi/services/user.go:197.85,199.2 1 0 -github.com/muety/wakapi/services/user.go:201.57,209.2 5 0 -github.com/muety/wakapi/services/user.go:211.38,213.2 1 0 -github.com/muety/wakapi/services/user.go:215.55,217.2 1 0 -github.com/muety/wakapi/services/user.go:219.57,224.2 1 0 -github.com/muety/wakapi/services/user.go:226.57,231.2 1 0 +github.com/muety/wakapi/services/user.go:27.99,37.33 3 0 +github.com/muety/wakapi/services/user.go:37.33,38.31 1 0 +github.com/muety/wakapi/services/user.go:38.31,44.73 4 0 +github.com/muety/wakapi/services/user.go:44.73,46.5 1 0 +github.com/muety/wakapi/services/user.go:48.4,48.24 1 0 +github.com/muety/wakapi/services/user.go:48.24,49.80 1 0 +github.com/muety/wakapi/services/user.go:49.80,51.6 1 0 +github.com/muety/wakapi/services/user.go:51.11,53.6 1 0 +github.com/muety/wakapi/services/user.go:58.2,58.12 1 0 +github.com/muety/wakapi/services/user.go:61.74,62.18 1 0 +github.com/muety/wakapi/services/user.go:62.18,64.3 1 0 +github.com/muety/wakapi/services/user.go:66.2,66.40 1 0 +github.com/muety/wakapi/services/user.go:66.40,68.3 1 0 +github.com/muety/wakapi/services/user.go:70.2,71.16 2 0 +github.com/muety/wakapi/services/user.go:71.16,73.3 1 0 +github.com/muety/wakapi/services/user.go:75.2,76.15 2 0 +github.com/muety/wakapi/services/user.go:79.72,80.15 1 0 +github.com/muety/wakapi/services/user.go:80.15,82.3 1 0 +github.com/muety/wakapi/services/user.go:84.2,84.37 1 0 +github.com/muety/wakapi/services/user.go:84.37,86.3 1 0 +github.com/muety/wakapi/services/user.go:88.2,89.16 2 0 +github.com/muety/wakapi/services/user.go:89.16,91.3 1 0 +github.com/muety/wakapi/services/user.go:93.2,94.15 2 0 +github.com/muety/wakapi/services/user.go:97.76,98.17 1 0 +github.com/muety/wakapi/services/user.go:98.17,100.3 1 0 +github.com/muety/wakapi/services/user.go:101.2,101.58 1 0 +github.com/muety/wakapi/services/user.go:104.86,105.22 1 0 +github.com/muety/wakapi/services/user.go:105.22,107.3 1 0 +github.com/muety/wakapi/services/user.go:108.2,108.68 1 0 +github.com/muety/wakapi/services/user.go:111.92,112.22 1 0 +github.com/muety/wakapi/services/user.go:112.22,114.3 1 0 +github.com/muety/wakapi/services/user.go:115.2,115.74 1 0 +github.com/muety/wakapi/services/user.go:118.58,120.2 1 0 +github.com/muety/wakapi/services/user.go:122.71,124.2 1 0 +github.com/muety/wakapi/services/user.go:126.86,128.16 2 0 +github.com/muety/wakapi/services/user.go:128.16,130.3 1 0 +github.com/muety/wakapi/services/user.go:131.2,131.112 1 0 +github.com/muety/wakapi/services/user.go:131.112,133.3 1 0 +github.com/muety/wakapi/services/user.go:136.86,138.2 1 0 +github.com/muety/wakapi/services/user.go:140.94,142.2 1 0 +github.com/muety/wakapi/services/user.go:144.71,146.12 2 0 +github.com/muety/wakapi/services/user.go:146.12,148.3 1 0 +github.com/muety/wakapi/services/user.go:150.2,151.42 2 0 +github.com/muety/wakapi/services/user.go:151.42,153.3 1 0 +github.com/muety/wakapi/services/user.go:155.2,156.16 2 0 +github.com/muety/wakapi/services/user.go:156.16,158.3 1 0 +github.com/muety/wakapi/services/user.go:160.2,161.21 2 0 +github.com/muety/wakapi/services/user.go:164.48,166.2 1 0 +github.com/muety/wakapi/services/user.go:168.102,178.95 2 0 +github.com/muety/wakapi/services/user.go:178.95,180.3 1 0 +github.com/muety/wakapi/services/user.go:180.8,182.3 1 0 +github.com/muety/wakapi/services/user.go:184.2,184.38 1 0 +github.com/muety/wakapi/services/user.go:187.73,191.2 3 0 +github.com/muety/wakapi/services/user.go:193.78,197.2 3 0 +github.com/muety/wakapi/services/user.go:199.122,202.35 2 0 +github.com/muety/wakapi/services/user.go:202.35,203.89 1 0 +github.com/muety/wakapi/services/user.go:203.89,205.4 1 0 +github.com/muety/wakapi/services/user.go:208.2,208.35 1 0 +github.com/muety/wakapi/services/user.go:208.35,210.3 1 0 +github.com/muety/wakapi/services/user.go:212.2,212.18 1 0 +github.com/muety/wakapi/services/user.go:215.85,217.2 1 0 +github.com/muety/wakapi/services/user.go:219.57,227.2 5 0 +github.com/muety/wakapi/services/user.go:229.38,231.2 1 0 +github.com/muety/wakapi/services/user.go:233.55,235.2 1 0 +github.com/muety/wakapi/services/user.go:237.57,242.2 1 0 +github.com/muety/wakapi/services/user.go:244.57,249.2 1 0 diff --git a/go.mod b/go.mod index f1a548e5..4aad7a9b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( codeberg.org/Codeberg/avatars v1.0.0 + github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736 github.com/alitto/pond v1.8.3 github.com/duke-git/lancet/v2 v2.2.5 @@ -33,7 +34,6 @@ require ( github.com/swaggo/swag v1.16.2 go.uber.org/atomic v1.11.0 golang.org/x/crypto v0.12.0 - golang.org/x/sync v0.3.0 gorm.io/driver/mysql v1.5.1 gorm.io/driver/postgres v1.5.2 gorm.io/driver/sqlite v1.5.3 diff --git a/go.sum b/go.sum index 59c70094..61373c0c 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,10 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736 h1:qZaEtLxnqY5mJ0fVKbk31NVhlgi0yrKm51Pq/I5wcz4= github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736/go.mod h1:mTeFRcTdnpzOlRjMoFYC/80HwVUreupyAiqPkCZQOXc= github.com/alitto/pond v1.8.3 h1:ydIqygCLVPqIX/USe5EaV/aSRXTRXDEI9JwuDdu+/xs= @@ -81,6 +85,7 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43 h1:Pdirg1gwhEcGjMLyuSxGn9664p+P8J9SrfMgpFwrDyg= github.com/kevinpollet/nego v0.0.0-20211010160919-a65cd48cee43/go.mod h1:ahLMuLCUyDdXqtqGyuwGev7/PGtO7r7ocvdwDuEN/3E= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= @@ -145,10 +150,13 @@ github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64 github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= github.com/swaggo/swag v1.16.2 h1:28Pp+8DkQoV+HLzLx8RGJZXNGKbFqnuvSbAAtoxiY04= github.com/swaggo/swag v1.16.2/go.mod h1:6YzXnDcpr0767iOejs318CwYkCQqyGer6BizOg03f+E= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= @@ -157,10 +165,13 @@ golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= golang.org/x/image v0.11.0 h1:ds2RoQvBvYTiJkwpSFDwCcDFNX7DqjL2WsUgTNk0Ooo= golang.org/x/image v0.11.0/go.mod h1:bglhjqbqVuEb9e9+eNR45Jfu7D+T4Qan+NhQk8Ck2P8= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -170,12 +181,14 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -198,11 +211,14 @@ golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -224,6 +240,7 @@ gorm.io/driver/sqlite v1.5.3/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= gorm.io/gorm v1.25.4 h1:iyNd8fNAe8W9dvtlgeRI5zSVZPsq3OpcTu37cYcpCmw= gorm.io/gorm v1.25.4/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= diff --git a/main.go b/main.go index 8e2efda1..5c8db365 100644 --- a/main.go +++ b/main.go @@ -80,6 +80,7 @@ var ( mailService services.IMailService keyValueService services.IKeyValueService reportService services.IReportService + activityService services.IActivityService diagnosticsService services.IDiagnosticsService housekeepingService services.IHousekeepingService miscService services.IMiscService @@ -189,6 +190,7 @@ func main() { aggregationService = services.NewAggregationService(userService, summaryService, heartbeatService) keyValueService = services.NewKeyValueService(keyValueRepository) reportService = services.NewReportService(summaryService, userService, mailService) + activityService = services.NewActivityService(summaryService) diagnosticsService = services.NewDiagnosticsService(diagnosticsRepository) housekeepingService = services.NewHousekeepingService(userService, heartbeatService, summaryService) miscService = services.NewMiscService(userService, heartbeatService, summaryService, keyValueService, mailService) @@ -210,6 +212,7 @@ func main() { metricsHandler := api.NewMetricsHandler(userService, summaryService, heartbeatService, keyValueService, metricsRepository) diagnosticsHandler := api.NewDiagnosticsApiHandler(userService, diagnosticsService) avatarHandler := api.NewAvatarHandler() + activityHandler := api.NewActivityApiHandler(userService, activityService) badgeHandler := api.NewBadgeHandler(userService, summaryService) // Compat Handlers @@ -282,6 +285,7 @@ func main() { metricsHandler.RegisterRoutes(apiRouter) diagnosticsHandler.RegisterRoutes(apiRouter) avatarHandler.RegisterRoutes(apiRouter) + activityHandler.RegisterRoutes(apiRouter) badgeHandler.RegisterRoutes(apiRouter) wakatimeV1StatusBarHandler.RegisterRoutes(apiRouter) wakatimeV1AllHandler.RegisterRoutes(apiRouter) diff --git a/models/summary.go b/models/summary.go index 407b4f65..1003f349 100644 --- a/models/summary.go +++ b/models/summary.go @@ -2,6 +2,8 @@ package models import ( "errors" + "github.com/duke-git/lancet/v2/mathutil" + "github.com/duke-git/lancet/v2/slice" "sort" "time" ) @@ -77,6 +79,19 @@ func PersistedSummaryTypes() []uint8 { return []uint8{SummaryProject, SummaryLanguage, SummaryEditor, SummaryOS, SummaryMachine} } +func NewEmptySummary() *Summary { + return &Summary{ + Projects: SummaryItems{}, + Languages: SummaryItems{}, + Editors: SummaryItems{}, + OperatingSystems: SummaryItems{}, + Machines: SummaryItems{}, + Labels: SummaryItems{}, + Branches: SummaryItems{}, + Entities: SummaryItems{}, + } +} + func (s *Summary) Sorted() *Summary { sort.Sort(sort.Reverse(s.Projects)) sort.Sort(sort.Reverse(s.Machines)) @@ -373,6 +388,12 @@ func (s *SummaryItem) TotalFixed() time.Duration { return s.Total * time.Second } +func (s Summaries) MaxTotalTime() time.Duration { + return mathutil.Max(slice.Map[*Summary, time.Duration](s, func(i int, item *Summary) time.Duration { + return item.TotalTime() + })...) +} + func (s Summaries) Len() int { return len(s) } diff --git a/models/view/projects.go b/models/view/projects.go index 828b6839..f5db97d0 100644 --- a/models/view/projects.go +++ b/models/view/projects.go @@ -48,7 +48,7 @@ func (s *ProjectsViewModel) getMaxCount() int64 { } func fadeColorToTransparent(colorHex string, transparency float64) string { - left := utils.ParseHexColor(colorHex) + left := utils.HexToRGBA(colorHex) right := &color.RGBA{R: left.R, G: left.G, B: left.B, A: uint8(transparency * 255)} return fmt.Sprintf("background: transparent; background: linear-gradient(90deg, rgba(%d, %d, %d, 0) 0%%, rgba(%d, %d, %d, 0) 50%%, rgba(%d, %d, %d, %.2f) 100%%);", left.R, left.G, left.B, diff --git a/routes/api/activity.go b/routes/api/activity.go new file mode 100644 index 00000000..ef29a114 --- /dev/null +++ b/routes/api/activity.go @@ -0,0 +1,67 @@ +package api + +import ( + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" + conf "github.com/muety/wakapi/config" + "github.com/muety/wakapi/helpers" + "github.com/muety/wakapi/middlewares" + "github.com/muety/wakapi/models" + "github.com/muety/wakapi/services" + "github.com/muety/wakapi/utils" + "net/http" + "time" +) + +type ActivityApiHandler struct { + config *conf.Config + userService services.IUserService + activityService services.IActivityService +} + +func NewActivityApiHandler(userService services.IUserService, activityService services.IActivityService) *ActivityApiHandler { + return &ActivityApiHandler{ + activityService: activityService, + userService: userService, + config: conf.Get(), + } +} + +func (h *ActivityApiHandler) RegisterRoutes(router chi.Router) { + r := chi.NewRouter() + r.Use( + middlewares.NewAuthenticateMiddleware(h.userService).WithOptionalFor([]string{"/api/activity/chart/"}).Handler, + middleware.Compress(9, "image/svg+xml"), + ) + r.Get("/chart/{user}.svg", h.GetActivityChart) + + router.Mount("/activity", r) +} + +func (h *ActivityApiHandler) GetActivityChart(w http.ResponseWriter, r *http.Request) { + authorizedUser := middlewares.GetPrincipal(r) + requestedUser, err := h.userService.GetUserById(chi.URLParam(r, "user")) + if err != nil { + w.WriteHeader(http.StatusNotFound) + return + } + + if authorizedUser == nil || authorizedUser.ID != requestedUser.ID { + if _, userRange := helpers.ResolveMaximumRange(requestedUser.ShareDataMaxDays); userRange != models.IntervalPast12Months && userRange != models.IntervalAny { // TODO: build "hierarchy" of intervals to easily check if one is contained in another + w.WriteHeader(http.StatusForbidden) + return + } + } + + chart, err := h.activityService.GetChart(requestedUser, models.IntervalPast12Months, utils.IsNoCache(r, 6*time.Hour)) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + conf.Log().Request(r).Error("failed to get activity chart for user %s - %v", err) + return + } + + w.Header().Set("Content-Type", "image/svg+xml") + w.Header().Set("Cache-Control", "max-age=43200") // 12 hours + w.WriteHeader(http.StatusOK) + w.Write([]byte(chart)) +} diff --git a/routes/api/avatar.go b/routes/api/avatar.go index 4b08f64b..bfd74f50 100644 --- a/routes/api/avatar.go +++ b/routes/api/avatar.go @@ -3,6 +3,7 @@ package api import ( "codeberg.org/Codeberg/avatars" "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" lru "github.com/hashicorp/golang-lru" conf "github.com/muety/wakapi/config" "github.com/muety/wakapi/utils" @@ -28,7 +29,10 @@ func NewAvatarHandler() *AvatarHandler { } func (h *AvatarHandler) RegisterRoutes(router chi.Router) { - router.Get("/avatar/{hash}.svg", h.Get) + r := chi.NewRouter() + r.Use(middleware.Compress(9, "image/svg+xml")) + r.Get("/avatar/{hash}.svg", h.Get) + router.Mount("/", r) } func (h *AvatarHandler) Get(w http.ResponseWriter, r *http.Request) { diff --git a/services/activity.go b/services/activity.go new file mode 100644 index 00000000..2956dc49 --- /dev/null +++ b/services/activity.go @@ -0,0 +1,121 @@ +package services + +import ( + "bytes" + "errors" + "fmt" + svg "github.com/ajstarks/svgo/float" + "github.com/alitto/pond" + "github.com/duke-git/lancet/v2/datetime" + "github.com/muety/wakapi/config" + "github.com/muety/wakapi/helpers" + "github.com/muety/wakapi/models" + "github.com/muety/wakapi/utils" + "github.com/patrickmn/go-cache" + "math" + "sync" + "time" +) + +const ( + gridRows = 7 + cellWidth = 20 + cellHeight = 20 + colorMin = "#dce3e1" + colorMax = "#047857" +) + +type ActivityService struct { + config *config.Config + cache *cache.Cache + summaryService ISummaryService +} + +func NewActivityService(summaryService ISummaryService) *ActivityService { + return &ActivityService{ + config: config.Get(), + cache: cache.New(6*time.Hour, 6*time.Hour), + summaryService: summaryService, + } +} + +// GetChart generates an activity chart for a given user and the given time interval, similar to GitHub's contribution timeline. See https://github.com/muety/wakapi/issues/12. +// Please note: currently, only yearly charts ("last_12_months") are supported. However, we could fairly easily restructure this to support dynamic intervals. +func (s *ActivityService) GetChart(user *models.User, interval *models.IntervalKey, skipCache bool) (string, error) { + cacheKey := fmt.Sprintf("chart_%s_%s", user.ID, (*interval)[0]) + if result, found := s.cache.Get(cacheKey); found && !skipCache { + return result.(string), nil + } + + switch interval { + case models.IntervalPast12Months: + chart, err := s.getChartPastYear(user) + if err == nil { + s.cache.SetDefault(cacheKey, chart) // TODO: cache compressed? + } + return chart, err + default: + return "", errors.New("unsupported interval") + } +} + +func (s *ActivityService) getChartPastYear(user *models.User) (string, error) { + err, from, to := helpers.ResolveIntervalTZ(models.IntervalPast12Months, user.TZ()) + from = datetime.BeginOfWeek(from, time.Monday) + if err != nil { + return "", err + } + + intervals := utils.SplitRangeByDays(from, to) + summaries := make([]*models.Summary, len(intervals)) + + wp := pond.New(utils.HalfCPUs(), 0) + mut := sync.RWMutex{} + + // fetch summaries + for i, interval := range intervals { + i := i // https://github.com/golang/go/wiki/CommonMistakes#using-reference-to-loop-iterator-variable + interval := interval + + wp.Submit(func() { + summary, err := s.summaryService.Retrieve(interval[0], interval[1], user, nil) + fmt.Println(summary == nil) + if err != nil { + config.Log().Warn("failed to retrieve summary for '%s' between %v and %v for activity chart", user.ID, from, to) + summary = models.NewEmptySummary() + summary.FromTime = models.CustomTime(from) + summary.ToTime = models.CustomTime(to) + summary.UserID = user.ID + summary.User = user + } + mut.Lock() + summaries[i] = summary + mut.Unlock() + }) + } + + wp.StopAndWait() + + maxTotal := models.Summaries(summaries).MaxTotalTime() + + var ( + colorRGBAMin = utils.HexToRGBA(colorMin) + colorRGBAMax = utils.HexToRGBA(colorMax) + ) + + // generate svg + buf := &bytes.Buffer{} + canvas := svg.New(buf) + canvas.Start(math.Ceil(float64(len(summaries))/float64(gridRows))*cellWidth, gridRows*cellHeight) + for i, s := range summaries { + total := s.TotalTime() + fillColor := utils.RGBAToHex(utils.FadeColors(colorRGBAMin, colorRGBAMax, float64(total)/float64(maxTotal))) + canvas.Group() + canvas.Title(fmt.Sprintf("%s on %s", helpers.FmtWakatimeDuration(total), helpers.FormatDateHuman(s.FromTime.T()))) + canvas.Rect(float64(i/gridRows)*cellWidth, float64((i%gridRows)*cellHeight), cellWidth, cellHeight, fmt.Sprintf("fill: %s; fill-opacity: 1; stroke: #fff; stroke-width: 1; stroke-linecap: square; stroke-opacity: 1", fillColor)) + canvas.Gend() + } + canvas.End() + + return buf.String(), nil +} diff --git a/services/imports/wakatime_heartbeats.go b/services/imports/wakatime_heartbeats.go index f88418ff..b1076d77 100644 --- a/services/imports/wakatime_heartbeats.go +++ b/services/imports/wakatime_heartbeats.go @@ -88,6 +88,8 @@ func (w *WakatimeHeartbeatsImporter) Import(user *models.User, minFrom time.Time wp := pond.New(maxWorkers, 0) for _, d := range days { + d := d // https://github.com/golang/go/wiki/CommonMistakes#using-reference-to-loop-iterator-variable + wp.Submit(func() { defer time.Sleep(throttleDelay) diff --git a/services/services.go b/services/services.go index f8ef3cc7..df5962ca 100644 --- a/services/services.go +++ b/services/services.go @@ -99,6 +99,10 @@ type ISummaryService interface { Insert(*models.Summary) error } +type IActivityService interface { + GetChart(*models.User, *models.IntervalKey, bool) (string, error) +} + type IReportService interface { Schedule() SendReport(*models.User, time.Duration) error diff --git a/services/user.go b/services/user.go index 8dc15714..29de6285 100644 --- a/services/user.go +++ b/services/user.go @@ -1,6 +1,7 @@ package services import ( + "errors" "fmt" "github.com/duke-git/lancet/v2/convertor" "github.com/duke-git/lancet/v2/datetime" @@ -58,6 +59,10 @@ func NewUserService(mailService IMailService, userRepo repositories.IUserReposit } func (srv *UserService) GetUserById(userId string) (*models.User, error) { + if userId == "" { + return nil, errors.New("user id must not be empty") + } + if u, ok := srv.cache.Get(userId); ok { return u.(*models.User), nil } @@ -72,6 +77,10 @@ func (srv *UserService) GetUserById(userId string) (*models.User, error) { } func (srv *UserService) GetUserByKey(key string) (*models.User, error) { + if key == "" { + return nil, errors.New("key must not be empty") + } + if u, ok := srv.cache.Get(key); ok { return u.(*models.User), nil } @@ -86,14 +95,23 @@ func (srv *UserService) GetUserByKey(key string) (*models.User, error) { } func (srv *UserService) GetUserByEmail(email string) (*models.User, error) { + if email == "" { + return nil, errors.New("email must not be empty") + } return srv.repository.FindOne(models.User{Email: email}) } func (srv *UserService) GetUserByResetToken(resetToken string) (*models.User, error) { + if resetToken == "" { + return nil, errors.New("reset token must not be empty") + } return srv.repository.FindOne(models.User{ResetToken: resetToken}) } func (srv *UserService) GetUserByStripeCustomerId(customerId string) (*models.User, error) { + if customerId == "" { + return nil, errors.New("customer id must not be empty") + } return srv.repository.FindOne(models.User{StripeCustomerId: customerId}) } diff --git a/utils/color.go b/utils/color.go index 408a2136..c8d586fe 100644 --- a/utils/color.go +++ b/utils/color.go @@ -5,7 +5,7 @@ import ( "image/color" ) -func ParseHexColor(s string) (c color.RGBA) { +func HexToRGBA(s string) (c color.RGBA) { // https://stackoverflow.com/questions/54197913/parse-hex-string-to-image-color c.A = 0xff switch len(s) { @@ -19,3 +19,22 @@ func ParseHexColor(s string) (c color.RGBA) { } return } + +func RGBAToHex(c color.RGBA) string { + return fmt.Sprintf("#%02X%02X%02X", c.R, c.G, c.B) +} + +func FadeColors(color1, color2 color.RGBA, ratio float64) color.RGBA { + if ratio < 0 { + ratio = 0 + } else if ratio > 1 { + ratio = 1 + } + + r := uint8(float64(color1.R)*(1-ratio) + float64(color2.R)*ratio) + g := uint8(float64(color1.G)*(1-ratio) + float64(color2.G)*ratio) + b := uint8(float64(color1.B)*(1-ratio) + float64(color2.B)*ratio) + a := uint8(float64(color1.A)*(1-ratio) + float64(color2.A)*ratio) + + return color.RGBA{R: r, G: g, B: b, A: a} +} diff --git a/utils/http.go b/utils/http.go index b5e90685..2e56111a 100644 --- a/utils/http.go +++ b/utils/http.go @@ -45,6 +45,7 @@ func (p *PageParams) Offset() int { return (p.Page - 1) * p.PageSize } +// IsNoCache checks whether returning a cached resource no older than cacheTtl is allowed given the incoming request func IsNoCache(r *http.Request, cacheTtl time.Duration) bool { cacheControl := r.Header.Get("cache-control") if strings.Contains(cacheControl, "no-cache") {