From d57c02af7c52ef2fc84cb2ac1dc25c2cc98fda00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ferdinand=20M=C3=BCtsch?= Date: Thu, 21 Jan 2021 00:26:52 +0100 Subject: [PATCH] feat: add ui for managing aliases (resolve #91) --- README.md | 18 -- coverage/coverage.out | 548 +++++++++++++++++++---------------- main.go | 4 +- mocks/alias_repository.go | 30 ++ mocks/alias_service.go | 32 +- models/alias.go | 13 + models/view/settings.go | 7 + repositories/alias.go | 65 +++++ repositories/key_value.go | 3 +- repositories/repositories.go | 6 + routes/routes.go | 34 ++- routes/settings.go | 83 +++++- services/alias.go | 79 ++++- services/language_mapping.go | 6 +- services/services.go | 9 +- services/summary.go | 2 +- services/summary_test.go | 2 +- utils/common.go | 4 + version.txt | 2 +- views/settings.tpl.html | 283 +++++++++++++----- 20 files changed, 865 insertions(+), 365 deletions(-) diff --git a/README.md b/README.md index f67d0ac..e50a76f 100644 --- a/README.md +++ b/README.md @@ -114,24 +114,6 @@ You can view your API Key after logging in to the web interface. See the [advanced setup instructions](docs/advanced_setup.md). -## 🔵 Customization - -### Aliases -There is an option to add aliases for project names, editors, operating systems and languages. For instance, if you want to map two projects – `myapp-frontend` and `myapp-backend` – two a common project name – `myapp-web` – in your statistics, you can add project aliases. - -At the moment, this can only be done via raw database queries. For the above example, you would need to add two aliases, like this: - -```sql -INSERT INTO aliases (`type`, `user_id`, `key`, `value`) VALUES (0, 'your_username', 'myapp-web', 'myapp-frontend'); -``` - -#### Types -* Project ~ type **0** -* Language ~ type **1** -* Editor ~ type **2** -* OS ~ type **3** -* Machine ~ type **4** - ## 🔧 API Endpoints The following API endpoints are available. A more detailed Swagger documentation is about to come ([#40](https://github.com/muety/wakapi/issues/40)). diff --git a/coverage/coverage.out b/coverage/coverage.out index be5589a..edacd1b 100644 --- a/coverage/coverage.out +++ b/coverage/coverage.out @@ -1,18 +1,4 @@ mode: set -github.com/muety/wakapi/models/shared.go:34.52,37.16 3 0 -github.com/muety/wakapi/models/shared.go:40.2,42.12 3 0 -github.com/muety/wakapi/models/shared.go:37.16,39.3 1 0 -github.com/muety/wakapi/models/shared.go:46.52,52.22 2 0 -github.com/muety/wakapi/models/shared.go:68.2,71.12 3 0 -github.com/muety/wakapi/models/shared.go:53.14,55.17 2 0 -github.com/muety/wakapi/models/shared.go:58.13,60.8 2 0 -github.com/muety/wakapi/models/shared.go:61.17,63.8 2 0 -github.com/muety/wakapi/models/shared.go:64.10,65.64 1 0 -github.com/muety/wakapi/models/shared.go:55.17,57.4 1 0 -github.com/muety/wakapi/models/shared.go:74.51,77.2 2 0 -github.com/muety/wakapi/models/shared.go:79.37,82.2 2 0 -github.com/muety/wakapi/models/shared.go:84.35,86.2 1 0 -github.com/muety/wakapi/models/shared.go:88.34,90.2 1 0 github.com/muety/wakapi/models/filters.go:16.56,17.16 1 0 github.com/muety/wakapi/models/filters.go:29.2,29.19 1 0 github.com/muety/wakapi/models/filters.go:18.22,19.32 1 0 @@ -42,34 +28,6 @@ github.com/muety/wakapi/models/filters.go:53.20,55.3 1 0 github.com/muety/wakapi/models/filters.go:56.22,58.3 1 1 github.com/muety/wakapi/models/filters.go:59.21,61.3 1 0 github.com/muety/wakapi/models/filters.go:62.16,64.3 1 0 -github.com/muety/wakapi/models/heartbeats.go:7.31,9.2 1 0 -github.com/muety/wakapi/models/heartbeats.go:11.41,13.2 1 0 -github.com/muety/wakapi/models/heartbeats.go:15.36,17.2 1 0 -github.com/muety/wakapi/models/heartbeats.go:19.43,22.2 2 0 -github.com/muety/wakapi/models/heartbeats.go:24.41,26.18 1 0 -github.com/muety/wakapi/models/heartbeats.go:29.2,29.16 1 0 -github.com/muety/wakapi/models/heartbeats.go:26.18,28.3 1 0 -github.com/muety/wakapi/models/heartbeats.go:32.40,34.18 1 0 -github.com/muety/wakapi/models/heartbeats.go:37.2,37.24 1 0 -github.com/muety/wakapi/models/heartbeats.go:34.18,36.3 1 0 -github.com/muety/wakapi/models/models.go:3.14,5.2 0 1 -github.com/muety/wakapi/models/heartbeat.go:26.34,28.2 1 1 -github.com/muety/wakapi/models/heartbeat.go:30.65,31.28 1 1 -github.com/muety/wakapi/models/heartbeat.go:34.2,35.45 2 1 -github.com/muety/wakapi/models/heartbeat.go:38.2,39.44 2 1 -github.com/muety/wakapi/models/heartbeat.go:42.2,42.42 1 1 -github.com/muety/wakapi/models/heartbeat.go:31.28,33.3 1 1 -github.com/muety/wakapi/models/heartbeat.go:35.45,37.3 1 0 -github.com/muety/wakapi/models/heartbeat.go:39.44,41.3 1 0 -github.com/muety/wakapi/models/heartbeat.go:45.50,46.11 1 1 -github.com/muety/wakapi/models/heartbeat.go:59.2,59.15 1 1 -github.com/muety/wakapi/models/heartbeat.go:63.2,63.12 1 1 -github.com/muety/wakapi/models/heartbeat.go:47.22,48.18 1 1 -github.com/muety/wakapi/models/heartbeat.go:49.21,50.17 1 1 -github.com/muety/wakapi/models/heartbeat.go:51.23,52.19 1 1 -github.com/muety/wakapi/models/heartbeat.go:53.17,54.26 1 1 -github.com/muety/wakapi/models/heartbeat.go:55.22,56.18 1 1 -github.com/muety/wakapi/models/heartbeat.go:59.15,61.3 1 1 github.com/muety/wakapi/models/language_mapping.go:11.42,13.2 1 0 github.com/muety/wakapi/models/language_mapping.go:15.51,17.2 1 0 github.com/muety/wakapi/models/language_mapping.go:19.52,21.2 1 0 @@ -127,89 +85,81 @@ github.com/muety/wakapi/models/user.go:34.43,37.2 1 0 github.com/muety/wakapi/models/user.go:39.33,43.2 1 0 github.com/muety/wakapi/models/user.go:45.45,47.2 1 0 github.com/muety/wakapi/models/user.go:49.45,51.2 1 0 -github.com/muety/wakapi/config/config.go:77.70,79.2 1 0 -github.com/muety/wakapi/config/config.go:81.65,83.2 1 0 -github.com/muety/wakapi/config/config.go:85.82,95.2 1 0 -github.com/muety/wakapi/config/config.go:97.31,99.2 1 0 -github.com/muety/wakapi/config/config.go:101.32,103.2 1 0 -github.com/muety/wakapi/config/config.go:105.74,106.19 1 0 -github.com/muety/wakapi/config/config.go:107.10,108.34 1 0 -github.com/muety/wakapi/config/config.go:108.34,117.4 8 0 -github.com/muety/wakapi/config/config.go:121.73,122.33 1 0 -github.com/muety/wakapi/config/config.go:122.33,130.17 5 0 -github.com/muety/wakapi/config/config.go:134.3,135.13 2 0 -github.com/muety/wakapi/config/config.go:130.17,132.4 1 0 -github.com/muety/wakapi/config/config.go:139.50,140.19 1 0 -github.com/muety/wakapi/config/config.go:153.2,153.12 1 0 -github.com/muety/wakapi/config/config.go:141.23,145.5 1 0 -github.com/muety/wakapi/config/config.go:146.26,149.5 1 0 -github.com/muety/wakapi/config/config.go:150.24,151.48 1 0 -github.com/muety/wakapi/config/config.go:156.53,166.2 1 1 -github.com/muety/wakapi/config/config.go:168.56,176.2 1 1 -github.com/muety/wakapi/config/config.go:178.54,180.2 1 1 -github.com/muety/wakapi/config/config.go:182.60,184.2 1 0 -github.com/muety/wakapi/config/config.go:186.59,188.2 1 0 -github.com/muety/wakapi/config/config.go:190.29,192.2 1 1 -github.com/muety/wakapi/config/config.go:194.27,196.16 2 0 -github.com/muety/wakapi/config/config.go:199.2,202.16 3 0 -github.com/muety/wakapi/config/config.go:206.2,206.22 1 0 -github.com/muety/wakapi/config/config.go:196.16,198.3 1 0 -github.com/muety/wakapi/config/config.go:202.16,204.3 1 0 -github.com/muety/wakapi/config/config.go:209.45,219.16 4 0 -github.com/muety/wakapi/config/config.go:223.2,223.57 1 0 -github.com/muety/wakapi/config/config.go:227.2,227.30 1 0 -github.com/muety/wakapi/config/config.go:231.2,231.15 1 0 -github.com/muety/wakapi/config/config.go:219.16,221.3 1 0 -github.com/muety/wakapi/config/config.go:223.57,225.3 1 0 -github.com/muety/wakapi/config/config.go:227.30,229.3 1 0 -github.com/muety/wakapi/config/config.go:234.38,235.43 1 0 -github.com/muety/wakapi/config/config.go:239.2,239.15 1 0 -github.com/muety/wakapi/config/config.go:235.43,237.3 1 0 -github.com/muety/wakapi/config/config.go:242.26,244.2 1 0 -github.com/muety/wakapi/config/config.go:246.20,248.2 1 0 -github.com/muety/wakapi/config/config.go:250.21,257.96 4 0 -github.com/muety/wakapi/config/config.go:261.2,268.52 4 0 -github.com/muety/wakapi/config/config.go:272.2,272.47 1 0 -github.com/muety/wakapi/config/config.go:278.2,278.70 1 0 -github.com/muety/wakapi/config/config.go:282.2,283.14 2 0 -github.com/muety/wakapi/config/config.go:257.96,259.3 1 0 -github.com/muety/wakapi/config/config.go:268.52,270.3 1 0 -github.com/muety/wakapi/config/config.go:272.47,273.14 1 0 -github.com/muety/wakapi/config/config.go:273.14,275.4 1 0 -github.com/muety/wakapi/config/config.go:278.70,280.3 1 0 -github.com/muety/wakapi/config/legacy.go:13.33,14.57 1 0 -github.com/muety/wakapi/config/legacy.go:14.57,16.3 1 0 -github.com/muety/wakapi/config/legacy.go:16.8,16.16 1 0 -github.com/muety/wakapi/config/legacy.go:16.16,18.47 2 0 -github.com/muety/wakapi/config/legacy.go:21.3,21.128 1 0 -github.com/muety/wakapi/config/legacy.go:18.47,20.4 1 0 -github.com/muety/wakapi/config/legacy.go:25.48,26.54 1 0 -github.com/muety/wakapi/config/legacy.go:31.2,31.18 1 0 -github.com/muety/wakapi/config/legacy.go:26.54,28.3 1 0 -github.com/muety/wakapi/config/legacy.go:28.8,28.32 1 0 -github.com/muety/wakapi/config/legacy.go:28.32,30.3 1 0 -github.com/muety/wakapi/config/legacy.go:34.34,37.16 2 0 -github.com/muety/wakapi/config/legacy.go:40.2,41.16 2 0 -github.com/muety/wakapi/config/legacy.go:45.2,57.16 11 0 -github.com/muety/wakapi/config/legacy.go:61.2,61.18 1 0 -github.com/muety/wakapi/config/legacy.go:65.2,69.16 5 0 -github.com/muety/wakapi/config/legacy.go:73.2,75.23 3 0 -github.com/muety/wakapi/config/legacy.go:80.2,82.33 3 0 -github.com/muety/wakapi/config/legacy.go:87.2,114.16 3 0 -github.com/muety/wakapi/config/legacy.go:119.2,119.78 1 0 -github.com/muety/wakapi/config/legacy.go:123.2,123.12 1 0 -github.com/muety/wakapi/config/legacy.go:37.16,39.3 1 0 -github.com/muety/wakapi/config/legacy.go:41.16,43.3 1 0 -github.com/muety/wakapi/config/legacy.go:57.16,59.3 1 0 -github.com/muety/wakapi/config/legacy.go:61.18,63.3 1 0 -github.com/muety/wakapi/config/legacy.go:69.16,71.3 1 0 -github.com/muety/wakapi/config/legacy.go:75.23,77.3 1 0 -github.com/muety/wakapi/config/legacy.go:82.33,84.3 1 0 -github.com/muety/wakapi/config/legacy.go:114.16,116.3 1 0 -github.com/muety/wakapi/config/legacy.go:119.78,121.3 1 0 -github.com/muety/wakapi/config/utils.go:3.60,5.22 2 0 -github.com/muety/wakapi/config/utils.go:8.2,8.11 1 0 -github.com/muety/wakapi/config/utils.go:5.22,7.3 1 0 +github.com/muety/wakapi/models/alias.go:12.32,14.2 1 0 +github.com/muety/wakapi/models/alias.go:16.37,17.35 1 0 +github.com/muety/wakapi/models/alias.go:22.2,22.14 1 0 +github.com/muety/wakapi/models/alias.go:17.35,18.18 1 0 +github.com/muety/wakapi/models/alias.go:18.18,20.4 1 0 +github.com/muety/wakapi/models/heartbeat.go:26.34,28.2 1 1 +github.com/muety/wakapi/models/heartbeat.go:30.65,31.28 1 1 +github.com/muety/wakapi/models/heartbeat.go:34.2,35.45 2 1 +github.com/muety/wakapi/models/heartbeat.go:38.2,39.44 2 1 +github.com/muety/wakapi/models/heartbeat.go:42.2,42.42 1 1 +github.com/muety/wakapi/models/heartbeat.go:31.28,33.3 1 1 +github.com/muety/wakapi/models/heartbeat.go:35.45,37.3 1 0 +github.com/muety/wakapi/models/heartbeat.go:39.44,41.3 1 0 +github.com/muety/wakapi/models/heartbeat.go:45.50,46.11 1 1 +github.com/muety/wakapi/models/heartbeat.go:59.2,59.15 1 1 +github.com/muety/wakapi/models/heartbeat.go:63.2,63.12 1 1 +github.com/muety/wakapi/models/heartbeat.go:47.22,48.18 1 1 +github.com/muety/wakapi/models/heartbeat.go:49.21,50.17 1 1 +github.com/muety/wakapi/models/heartbeat.go:51.23,52.19 1 1 +github.com/muety/wakapi/models/heartbeat.go:53.17,54.26 1 1 +github.com/muety/wakapi/models/heartbeat.go:55.22,56.18 1 1 +github.com/muety/wakapi/models/heartbeat.go:59.15,61.3 1 1 +github.com/muety/wakapi/models/heartbeats.go:7.31,9.2 1 0 +github.com/muety/wakapi/models/heartbeats.go:11.41,13.2 1 0 +github.com/muety/wakapi/models/heartbeats.go:15.36,17.2 1 0 +github.com/muety/wakapi/models/heartbeats.go:19.43,22.2 2 0 +github.com/muety/wakapi/models/heartbeats.go:24.41,26.18 1 0 +github.com/muety/wakapi/models/heartbeats.go:29.2,29.16 1 0 +github.com/muety/wakapi/models/heartbeats.go:26.18,28.3 1 0 +github.com/muety/wakapi/models/heartbeats.go:32.40,34.18 1 0 +github.com/muety/wakapi/models/heartbeats.go:37.2,37.24 1 0 +github.com/muety/wakapi/models/heartbeats.go:34.18,36.3 1 0 +github.com/muety/wakapi/models/models.go:3.14,5.2 0 1 +github.com/muety/wakapi/models/shared.go:34.52,37.16 3 0 +github.com/muety/wakapi/models/shared.go:40.2,42.12 3 0 +github.com/muety/wakapi/models/shared.go:37.16,39.3 1 0 +github.com/muety/wakapi/models/shared.go:46.52,52.22 2 0 +github.com/muety/wakapi/models/shared.go:68.2,71.12 3 0 +github.com/muety/wakapi/models/shared.go:53.14,55.17 2 0 +github.com/muety/wakapi/models/shared.go:58.13,60.8 2 0 +github.com/muety/wakapi/models/shared.go:61.17,63.8 2 0 +github.com/muety/wakapi/models/shared.go:64.10,65.64 1 0 +github.com/muety/wakapi/models/shared.go:55.17,57.4 1 0 +github.com/muety/wakapi/models/shared.go:74.51,77.2 2 0 +github.com/muety/wakapi/models/shared.go:79.37,82.2 2 0 +github.com/muety/wakapi/models/shared.go:84.35,86.2 1 0 +github.com/muety/wakapi/models/shared.go:88.34,90.2 1 0 +github.com/muety/wakapi/utils/template.go:8.41,10.16 2 0 +github.com/muety/wakapi/utils/template.go:13.2,13.23 1 0 +github.com/muety/wakapi/utils/template.go:10.16,12.3 1 0 +github.com/muety/wakapi/utils/template.go:16.37,17.30 1 0 +github.com/muety/wakapi/utils/template.go:20.2,20.10 1 0 +github.com/muety/wakapi/utils/template.go:17.30,19.3 1 0 +github.com/muety/wakapi/utils/auth.go:18.79,20.54 2 0 +github.com/muety/wakapi/utils/auth.go:24.2,26.16 3 0 +github.com/muety/wakapi/utils/auth.go:30.2,32.45 3 0 +github.com/muety/wakapi/utils/auth.go:35.2,36.32 2 0 +github.com/muety/wakapi/utils/auth.go:20.54,22.3 1 0 +github.com/muety/wakapi/utils/auth.go:26.16,28.3 1 0 +github.com/muety/wakapi/utils/auth.go:32.45,34.3 1 0 +github.com/muety/wakapi/utils/auth.go:39.65,41.54 2 0 +github.com/muety/wakapi/utils/auth.go:45.2,46.30 2 0 +github.com/muety/wakapi/utils/auth.go:41.54,43.3 1 0 +github.com/muety/wakapi/utils/auth.go:49.97,51.16 2 0 +github.com/muety/wakapi/utils/auth.go:55.2,55.104 1 0 +github.com/muety/wakapi/utils/auth.go:59.2,59.19 1 0 +github.com/muety/wakapi/utils/auth.go:51.16,53.3 1 0 +github.com/muety/wakapi/utils/auth.go:55.104,57.3 1 0 +github.com/muety/wakapi/utils/auth.go:62.30,64.2 1 0 +github.com/muety/wakapi/utils/auth.go:66.56,70.2 3 0 +github.com/muety/wakapi/utils/auth.go:73.53,75.2 1 0 +github.com/muety/wakapi/utils/auth.go:77.55,80.16 3 0 +github.com/muety/wakapi/utils/auth.go:83.2,83.16 1 0 +github.com/muety/wakapi/utils/auth.go:80.16,82.3 1 0 +github.com/muety/wakapi/utils/auth.go:86.43,91.2 4 0 github.com/muety/wakapi/utils/color.go:8.93,10.41 2 0 github.com/muety/wakapi/utils/color.go:15.2,15.15 1 0 github.com/muety/wakapi/utils/color.go:10.41,11.50 1 0 @@ -217,9 +167,10 @@ github.com/muety/wakapi/utils/color.go:11.50,13.4 1 0 github.com/muety/wakapi/utils/common.go:9.48,11.2 1 0 github.com/muety/wakapi/utils/common.go:13.40,15.2 1 0 github.com/muety/wakapi/utils/common.go:17.45,19.2 1 0 -github.com/muety/wakapi/utils/common.go:21.56,24.45 3 1 -github.com/muety/wakapi/utils/common.go:27.2,27.40 1 1 -github.com/muety/wakapi/utils/common.go:24.45,26.3 1 1 +github.com/muety/wakapi/utils/common.go:21.24,23.2 1 0 +github.com/muety/wakapi/utils/common.go:25.56,28.45 3 1 +github.com/muety/wakapi/utils/common.go:31.2,31.40 1 1 +github.com/muety/wakapi/utils/common.go:28.45,30.3 1 1 github.com/muety/wakapi/utils/date.go:8.31,10.2 1 0 github.com/muety/wakapi/utils/date.go:12.43,14.2 1 0 github.com/muety/wakapi/utils/date.go:16.30,20.2 3 0 @@ -264,31 +215,96 @@ github.com/muety/wakapi/utils/summary.go:49.8,51.17 2 0 github.com/muety/wakapi/utils/summary.go:55.3,56.17 2 0 github.com/muety/wakapi/utils/summary.go:51.17,53.4 1 0 github.com/muety/wakapi/utils/summary.go:56.17,58.4 1 0 -github.com/muety/wakapi/utils/template.go:8.41,10.16 2 0 -github.com/muety/wakapi/utils/template.go:13.2,13.23 1 0 -github.com/muety/wakapi/utils/template.go:10.16,12.3 1 0 -github.com/muety/wakapi/utils/auth.go:18.79,20.54 2 0 -github.com/muety/wakapi/utils/auth.go:24.2,26.16 3 0 -github.com/muety/wakapi/utils/auth.go:30.2,32.45 3 0 -github.com/muety/wakapi/utils/auth.go:35.2,36.32 2 0 -github.com/muety/wakapi/utils/auth.go:20.54,22.3 1 0 -github.com/muety/wakapi/utils/auth.go:26.16,28.3 1 0 -github.com/muety/wakapi/utils/auth.go:32.45,34.3 1 0 -github.com/muety/wakapi/utils/auth.go:39.65,41.54 2 0 -github.com/muety/wakapi/utils/auth.go:45.2,46.30 2 0 -github.com/muety/wakapi/utils/auth.go:41.54,43.3 1 0 -github.com/muety/wakapi/utils/auth.go:49.97,51.16 2 0 -github.com/muety/wakapi/utils/auth.go:55.2,55.104 1 0 -github.com/muety/wakapi/utils/auth.go:59.2,59.19 1 0 -github.com/muety/wakapi/utils/auth.go:51.16,53.3 1 0 -github.com/muety/wakapi/utils/auth.go:55.104,57.3 1 0 -github.com/muety/wakapi/utils/auth.go:62.30,64.2 1 0 -github.com/muety/wakapi/utils/auth.go:66.56,70.2 3 0 -github.com/muety/wakapi/utils/auth.go:73.53,75.2 1 0 -github.com/muety/wakapi/utils/auth.go:77.55,80.16 3 0 -github.com/muety/wakapi/utils/auth.go:83.2,83.16 1 0 -github.com/muety/wakapi/utils/auth.go:80.16,82.3 1 0 -github.com/muety/wakapi/utils/auth.go:86.43,91.2 4 0 +github.com/muety/wakapi/config/config.go:83.70,85.2 1 0 +github.com/muety/wakapi/config/config.go:87.65,89.2 1 0 +github.com/muety/wakapi/config/config.go:91.82,101.2 1 0 +github.com/muety/wakapi/config/config.go:103.31,105.2 1 0 +github.com/muety/wakapi/config/config.go:107.32,109.2 1 0 +github.com/muety/wakapi/config/config.go:111.74,112.19 1 0 +github.com/muety/wakapi/config/config.go:113.10,114.34 1 0 +github.com/muety/wakapi/config/config.go:114.34,123.4 8 0 +github.com/muety/wakapi/config/config.go:127.73,128.33 1 0 +github.com/muety/wakapi/config/config.go:128.33,136.17 5 0 +github.com/muety/wakapi/config/config.go:140.3,141.13 2 0 +github.com/muety/wakapi/config/config.go:136.17,138.4 1 0 +github.com/muety/wakapi/config/config.go:145.50,146.19 1 0 +github.com/muety/wakapi/config/config.go:159.2,159.12 1 0 +github.com/muety/wakapi/config/config.go:147.23,151.5 1 0 +github.com/muety/wakapi/config/config.go:152.26,155.5 1 0 +github.com/muety/wakapi/config/config.go:156.24,157.48 1 0 +github.com/muety/wakapi/config/config.go:162.53,172.2 1 1 +github.com/muety/wakapi/config/config.go:174.56,176.16 2 1 +github.com/muety/wakapi/config/config.go:180.2,187.3 1 1 +github.com/muety/wakapi/config/config.go:176.16,178.3 1 0 +github.com/muety/wakapi/config/config.go:190.54,192.2 1 1 +github.com/muety/wakapi/config/config.go:194.60,196.2 1 0 +github.com/muety/wakapi/config/config.go:198.59,200.2 1 0 +github.com/muety/wakapi/config/config.go:202.29,204.2 1 1 +github.com/muety/wakapi/config/config.go:206.27,208.16 2 0 +github.com/muety/wakapi/config/config.go:211.2,214.16 3 0 +github.com/muety/wakapi/config/config.go:218.2,218.22 1 0 +github.com/muety/wakapi/config/config.go:208.16,210.3 1 0 +github.com/muety/wakapi/config/config.go:214.16,216.3 1 0 +github.com/muety/wakapi/config/config.go:221.45,231.16 4 0 +github.com/muety/wakapi/config/config.go:235.2,235.57 1 0 +github.com/muety/wakapi/config/config.go:239.2,239.30 1 0 +github.com/muety/wakapi/config/config.go:243.2,243.15 1 0 +github.com/muety/wakapi/config/config.go:231.16,233.3 1 0 +github.com/muety/wakapi/config/config.go:235.57,237.3 1 0 +github.com/muety/wakapi/config/config.go:239.30,241.3 1 0 +github.com/muety/wakapi/config/config.go:246.38,247.43 1 0 +github.com/muety/wakapi/config/config.go:251.2,251.15 1 0 +github.com/muety/wakapi/config/config.go:247.43,249.3 1 0 +github.com/muety/wakapi/config/config.go:254.45,255.27 1 0 +github.com/muety/wakapi/config/config.go:258.2,258.15 1 0 +github.com/muety/wakapi/config/config.go:255.27,257.3 1 0 +github.com/muety/wakapi/config/config.go:261.26,263.2 1 0 +github.com/muety/wakapi/config/config.go:265.20,267.2 1 0 +github.com/muety/wakapi/config/config.go:269.21,276.96 4 0 +github.com/muety/wakapi/config/config.go:280.2,288.52 5 0 +github.com/muety/wakapi/config/config.go:292.2,292.47 1 0 +github.com/muety/wakapi/config/config.go:298.2,298.70 1 0 +github.com/muety/wakapi/config/config.go:302.2,303.14 2 0 +github.com/muety/wakapi/config/config.go:276.96,278.3 1 0 +github.com/muety/wakapi/config/config.go:288.52,290.3 1 0 +github.com/muety/wakapi/config/config.go:292.47,293.14 1 0 +github.com/muety/wakapi/config/config.go:293.14,295.4 1 0 +github.com/muety/wakapi/config/config.go:298.70,300.3 1 0 +github.com/muety/wakapi/config/legacy.go:13.33,14.57 1 0 +github.com/muety/wakapi/config/legacy.go:14.57,16.3 1 0 +github.com/muety/wakapi/config/legacy.go:16.8,16.16 1 0 +github.com/muety/wakapi/config/legacy.go:16.16,18.47 2 0 +github.com/muety/wakapi/config/legacy.go:21.3,21.128 1 0 +github.com/muety/wakapi/config/legacy.go:18.47,20.4 1 0 +github.com/muety/wakapi/config/legacy.go:25.48,26.54 1 0 +github.com/muety/wakapi/config/legacy.go:31.2,31.18 1 0 +github.com/muety/wakapi/config/legacy.go:26.54,28.3 1 0 +github.com/muety/wakapi/config/legacy.go:28.8,28.32 1 0 +github.com/muety/wakapi/config/legacy.go:28.32,30.3 1 0 +github.com/muety/wakapi/config/legacy.go:34.34,37.16 2 0 +github.com/muety/wakapi/config/legacy.go:40.2,41.16 2 0 +github.com/muety/wakapi/config/legacy.go:45.2,57.16 11 0 +github.com/muety/wakapi/config/legacy.go:61.2,61.18 1 0 +github.com/muety/wakapi/config/legacy.go:65.2,69.16 5 0 +github.com/muety/wakapi/config/legacy.go:73.2,75.23 3 0 +github.com/muety/wakapi/config/legacy.go:80.2,82.33 3 0 +github.com/muety/wakapi/config/legacy.go:87.2,114.16 3 0 +github.com/muety/wakapi/config/legacy.go:119.2,119.78 1 0 +github.com/muety/wakapi/config/legacy.go:123.2,123.12 1 0 +github.com/muety/wakapi/config/legacy.go:37.16,39.3 1 0 +github.com/muety/wakapi/config/legacy.go:41.16,43.3 1 0 +github.com/muety/wakapi/config/legacy.go:57.16,59.3 1 0 +github.com/muety/wakapi/config/legacy.go:61.18,63.3 1 0 +github.com/muety/wakapi/config/legacy.go:69.16,71.3 1 0 +github.com/muety/wakapi/config/legacy.go:75.23,77.3 1 0 +github.com/muety/wakapi/config/legacy.go:82.33,84.3 1 0 +github.com/muety/wakapi/config/legacy.go:114.16,116.3 1 0 +github.com/muety/wakapi/config/legacy.go:119.78,121.3 1 0 +github.com/muety/wakapi/config/utils.go:3.60,5.22 2 0 +github.com/muety/wakapi/config/utils.go:8.2,8.11 1 0 +github.com/muety/wakapi/config/utils.go:5.22,7.3 1 0 +github.com/muety/wakapi/middlewares/logging.go:11.48,13.2 1 0 +github.com/muety/wakapi/middlewares/logging.go:15.66,17.2 1 0 github.com/muety/wakapi/middlewares/authenticate.go:27.116,34.2 1 1 github.com/muety/wakapi/middlewares/authenticate.go:36.71,37.71 1 0 github.com/muety/wakapi/middlewares/authenticate.go:37.71,39.3 1 0 @@ -324,104 +340,38 @@ github.com/muety/wakapi/middlewares/authenticate.go:127.2,127.65 1 0 github.com/muety/wakapi/middlewares/authenticate.go:119.32,120.58 1 0 github.com/muety/wakapi/middlewares/authenticate.go:125.3,125.15 1 0 github.com/muety/wakapi/middlewares/authenticate.go:120.58,124.4 3 0 -github.com/muety/wakapi/middlewares/logging.go:11.48,13.2 1 0 -github.com/muety/wakapi/middlewares/logging.go:15.66,17.2 1 0 -github.com/muety/wakapi/services/aggregation.go:24.142,31.2 1 0 -github.com/muety/wakapi/services/aggregation.go:40.43,42.37 1 0 -github.com/muety/wakapi/services/aggregation.go:46.2,48.19 3 0 -github.com/muety/wakapi/services/aggregation.go:42.37,44.3 1 0 -github.com/muety/wakapi/services/aggregation.go:51.67,55.40 3 0 -github.com/muety/wakapi/services/aggregation.go:59.2,59.50 1 0 -github.com/muety/wakapi/services/aggregation.go:64.2,64.60 1 0 -github.com/muety/wakapi/services/aggregation.go:70.2,70.35 1 0 -github.com/muety/wakapi/services/aggregation.go:55.40,57.3 1 0 -github.com/muety/wakapi/services/aggregation.go:59.50,61.3 1 0 -github.com/muety/wakapi/services/aggregation.go:64.60,68.3 3 0 -github.com/muety/wakapi/services/aggregation.go:73.109,74.24 1 0 -github.com/muety/wakapi/services/aggregation.go:74.24,75.111 1 0 -github.com/muety/wakapi/services/aggregation.go:75.111,77.4 1 0 -github.com/muety/wakapi/services/aggregation.go:77.9,80.4 2 0 -github.com/muety/wakapi/services/aggregation.go:84.80,85.33 1 0 -github.com/muety/wakapi/services/aggregation.go:85.33,86.60 1 0 -github.com/muety/wakapi/services/aggregation.go:86.60,88.4 1 0 -github.com/muety/wakapi/services/aggregation.go:92.100,96.59 3 0 -github.com/muety/wakapi/services/aggregation.go:111.2,112.16 2 0 -github.com/muety/wakapi/services/aggregation.go:118.2,119.16 2 0 -github.com/muety/wakapi/services/aggregation.go:125.2,126.44 2 0 -github.com/muety/wakapi/services/aggregation.go:131.2,131.41 1 0 -github.com/muety/wakapi/services/aggregation.go:145.2,145.12 1 0 -github.com/muety/wakapi/services/aggregation.go:96.59,99.3 2 0 -github.com/muety/wakapi/services/aggregation.go:99.8,99.47 1 0 -github.com/muety/wakapi/services/aggregation.go:99.47,101.30 2 0 -github.com/muety/wakapi/services/aggregation.go:101.30,102.43 1 0 -github.com/muety/wakapi/services/aggregation.go:102.43,104.5 1 0 -github.com/muety/wakapi/services/aggregation.go:106.8,108.3 1 0 -github.com/muety/wakapi/services/aggregation.go:112.16,115.3 2 0 -github.com/muety/wakapi/services/aggregation.go:119.16,122.3 2 0 -github.com/muety/wakapi/services/aggregation.go:126.44,128.3 1 0 -github.com/muety/wakapi/services/aggregation.go:131.41,132.21 1 0 -github.com/muety/wakapi/services/aggregation.go:132.21,136.4 1 0 -github.com/muety/wakapi/services/aggregation.go:136.9,136.62 1 0 -github.com/muety/wakapi/services/aggregation.go:136.62,140.4 1 0 -github.com/muety/wakapi/services/aggregation.go:148.83,163.41 5 0 -github.com/muety/wakapi/services/aggregation.go:163.41,173.3 3 0 -github.com/muety/wakapi/services/aggregation.go:176.34,179.2 2 0 -github.com/muety/wakapi/services/alias.go:16.77,21.2 1 1 -github.com/muety/wakapi/services/alias.go:25.63,27.16 2 1 -github.com/muety/wakapi/services/alias.go:30.2,30.12 1 1 -github.com/muety/wakapi/services/alias.go:27.16,29.3 1 1 -github.com/muety/wakapi/services/alias.go:33.108,34.32 1 1 -github.com/muety/wakapi/services/alias.go:40.2,41.46 2 1 -github.com/muety/wakapi/services/alias.go:46.2,46.19 1 1 -github.com/muety/wakapi/services/alias.go:34.32,35.53 1 1 -github.com/muety/wakapi/services/alias.go:35.53,37.4 1 1 -github.com/muety/wakapi/services/alias.go:41.46,42.48 1 1 -github.com/muety/wakapi/services/alias.go:42.48,44.4 1 1 -github.com/muety/wakapi/services/alias.go:49.60,50.43 1 1 -github.com/muety/wakapi/services/alias.go:53.2,53.14 1 1 -github.com/muety/wakapi/services/alias.go:50.43,52.3 1 1 -github.com/muety/wakapi/services/heartbeat.go:17.141,23.2 1 0 -github.com/muety/wakapi/services/heartbeat.go:25.80,27.2 1 0 -github.com/muety/wakapi/services/heartbeat.go:29.111,31.16 2 0 -github.com/muety/wakapi/services/heartbeat.go:34.2,34.43 1 0 -github.com/muety/wakapi/services/heartbeat.go:31.16,33.3 1 0 -github.com/muety/wakapi/services/heartbeat.go:37.78,39.2 1 0 -github.com/muety/wakapi/services/heartbeat.go:41.62,43.2 1 0 -github.com/muety/wakapi/services/heartbeat.go:45.116,47.16 2 0 -github.com/muety/wakapi/services/heartbeat.go:51.2,51.28 1 0 -github.com/muety/wakapi/services/heartbeat.go:55.2,55.24 1 0 -github.com/muety/wakapi/services/heartbeat.go:47.16,49.3 1 0 -github.com/muety/wakapi/services/heartbeat.go:51.28,53.3 1 0 -github.com/muety/wakapi/services/key_value.go:14.89,19.2 1 0 -github.com/muety/wakapi/services/key_value.go:21.83,23.2 1 0 -github.com/muety/wakapi/services/key_value.go:25.72,27.2 1 0 -github.com/muety/wakapi/services/key_value.go:29.60,31.2 1 0 -github.com/muety/wakapi/services/language_mapping.go:17.118,23.2 1 0 -github.com/muety/wakapi/services/language_mapping.go:25.86,27.2 1 0 -github.com/muety/wakapi/services/language_mapping.go:29.96,30.53 1 0 -github.com/muety/wakapi/services/language_mapping.go:34.2,35.16 2 0 -github.com/muety/wakapi/services/language_mapping.go:38.2,39.22 2 0 -github.com/muety/wakapi/services/language_mapping.go:30.53,32.3 1 0 -github.com/muety/wakapi/services/language_mapping.go:35.16,37.3 1 0 -github.com/muety/wakapi/services/language_mapping.go:42.92,45.16 3 0 -github.com/muety/wakapi/services/language_mapping.go:49.2,49.33 1 0 -github.com/muety/wakapi/services/language_mapping.go:52.2,52.22 1 0 -github.com/muety/wakapi/services/language_mapping.go:45.16,47.3 1 0 -github.com/muety/wakapi/services/language_mapping.go:49.33,51.3 1 0 -github.com/muety/wakapi/services/language_mapping.go:55.109,57.16 2 0 -github.com/muety/wakapi/services/language_mapping.go:61.2,62.20 2 0 -github.com/muety/wakapi/services/language_mapping.go:57.16,59.3 1 0 -github.com/muety/wakapi/services/language_mapping.go:65.82,69.2 3 0 -github.com/muety/wakapi/services/language_mapping.go:71.74,74.2 1 0 +github.com/muety/wakapi/services/misc.go:23.126,30.2 1 0 +github.com/muety/wakapi/services/misc.go:42.50,44.48 1 0 +github.com/muety/wakapi/services/misc.go:48.2,50.19 3 0 +github.com/muety/wakapi/services/misc.go:44.48,46.3 1 0 +github.com/muety/wakapi/services/misc.go:53.51,59.40 4 0 +github.com/muety/wakapi/services/misc.go:63.2,66.56 2 0 +github.com/muety/wakapi/services/misc.go:77.2,77.12 1 0 +github.com/muety/wakapi/services/misc.go:59.40,61.3 1 0 +github.com/muety/wakapi/services/misc.go:66.56,67.27 1 0 +github.com/muety/wakapi/services/misc.go:67.27,72.4 1 0 +github.com/muety/wakapi/services/misc.go:73.8,75.3 1 0 +github.com/muety/wakapi/services/misc.go:80.116,81.24 1 0 +github.com/muety/wakapi/services/misc.go:81.24,82.144 1 0 +github.com/muety/wakapi/services/misc.go:91.3,91.48 1 0 +github.com/muety/wakapi/services/misc.go:82.144,84.4 1 0 +github.com/muety/wakapi/services/misc.go:84.9,90.4 2 0 +github.com/muety/wakapi/services/misc.go:91.48,94.4 2 0 +github.com/muety/wakapi/services/misc.go:98.86,101.30 3 0 +github.com/muety/wakapi/services/misc.go:106.2,109.17 1 0 +github.com/muety/wakapi/services/misc.go:113.2,116.17 1 0 +github.com/muety/wakapi/services/misc.go:101.30,104.3 2 0 +github.com/muety/wakapi/services/misc.go:109.17,111.3 1 0 +github.com/muety/wakapi/services/misc.go:116.17,118.3 1 0 github.com/muety/wakapi/services/summary.go:27.149,35.2 1 1 github.com/muety/wakapi/services/summary.go:39.120,42.52 2 1 github.com/muety/wakapi/services/summary.go:47.2,47.44 1 1 -github.com/muety/wakapi/services/summary.go:53.2,53.66 1 1 +github.com/muety/wakapi/services/summary.go:53.2,53.65 1 1 github.com/muety/wakapi/services/summary.go:58.2,59.16 2 1 github.com/muety/wakapi/services/summary.go:64.2,66.30 3 1 github.com/muety/wakapi/services/summary.go:42.52,44.3 1 0 github.com/muety/wakapi/services/summary.go:47.44,50.3 2 1 -github.com/muety/wakapi/services/summary.go:53.66,55.3 1 0 +github.com/muety/wakapi/services/summary.go:53.65,55.3 1 0 github.com/muety/wakapi/services/summary.go:59.16,61.3 1 0 github.com/muety/wakapi/services/summary.go:69.101,72.52 2 1 github.com/muety/wakapi/services/summary.go:77.2,78.16 2 1 @@ -517,3 +467,113 @@ github.com/muety/wakapi/services/user.go:64.106,66.96 2 0 github.com/muety/wakapi/services/user.go:71.2,71.68 1 0 github.com/muety/wakapi/services/user.go:66.96,68.3 1 0 github.com/muety/wakapi/services/user.go:68.8,70.3 1 0 +github.com/muety/wakapi/services/alias.go:17.77,22.2 1 1 +github.com/muety/wakapi/services/alias.go:26.60,27.43 1 1 +github.com/muety/wakapi/services/alias.go:30.2,30.14 1 1 +github.com/muety/wakapi/services/alias.go:27.43,29.3 1 1 +github.com/muety/wakapi/services/alias.go:33.62,35.16 2 1 +github.com/muety/wakapi/services/alias.go:38.2,38.12 1 1 +github.com/muety/wakapi/services/alias.go:35.16,37.3 1 1 +github.com/muety/wakapi/services/alias.go:41.76,43.16 2 0 +github.com/muety/wakapi/services/alias.go:46.2,46.21 1 0 +github.com/muety/wakapi/services/alias.go:43.16,45.3 1 0 +github.com/muety/wakapi/services/alias.go:49.113,51.16 2 0 +github.com/muety/wakapi/services/alias.go:54.2,54.21 1 0 +github.com/muety/wakapi/services/alias.go:51.16,53.3 1 0 +github.com/muety/wakapi/services/alias.go:57.108,58.32 1 1 +github.com/muety/wakapi/services/alias.go:64.2,65.46 2 1 +github.com/muety/wakapi/services/alias.go:70.2,70.19 1 1 +github.com/muety/wakapi/services/alias.go:58.32,59.52 1 1 +github.com/muety/wakapi/services/alias.go:59.52,61.4 1 1 +github.com/muety/wakapi/services/alias.go:65.46,66.48 1 1 +github.com/muety/wakapi/services/alias.go:66.48,68.4 1 1 +github.com/muety/wakapi/services/alias.go:73.77,75.16 2 0 +github.com/muety/wakapi/services/alias.go:78.2,79.20 2 0 +github.com/muety/wakapi/services/alias.go:75.16,77.3 1 0 +github.com/muety/wakapi/services/alias.go:82.60,83.24 1 0 +github.com/muety/wakapi/services/alias.go:86.2,88.12 3 0 +github.com/muety/wakapi/services/alias.go:83.24,85.3 1 0 +github.com/muety/wakapi/services/alias.go:91.69,94.28 3 0 +github.com/muety/wakapi/services/alias.go:102.2,104.31 2 0 +github.com/muety/wakapi/services/alias.go:108.2,108.12 1 0 +github.com/muety/wakapi/services/alias.go:94.28,95.21 1 0 +github.com/muety/wakapi/services/alias.go:98.3,99.16 2 0 +github.com/muety/wakapi/services/alias.go:95.21,97.4 1 0 +github.com/muety/wakapi/services/alias.go:104.31,106.3 1 0 +github.com/muety/wakapi/services/alias.go:111.52,112.51 1 0 +github.com/muety/wakapi/services/alias.go:112.51,114.3 1 0 +github.com/muety/wakapi/services/key_value.go:14.89,19.2 1 0 +github.com/muety/wakapi/services/key_value.go:21.83,23.2 1 0 +github.com/muety/wakapi/services/key_value.go:25.72,27.2 1 0 +github.com/muety/wakapi/services/key_value.go:29.60,31.2 1 0 +github.com/muety/wakapi/services/language_mapping.go:18.118,24.2 1 0 +github.com/muety/wakapi/services/language_mapping.go:26.86,28.2 1 0 +github.com/muety/wakapi/services/language_mapping.go:30.96,31.53 1 0 +github.com/muety/wakapi/services/language_mapping.go:35.2,36.16 2 0 +github.com/muety/wakapi/services/language_mapping.go:39.2,40.22 2 0 +github.com/muety/wakapi/services/language_mapping.go:31.53,33.3 1 0 +github.com/muety/wakapi/services/language_mapping.go:36.16,38.3 1 0 +github.com/muety/wakapi/services/language_mapping.go:43.92,46.16 3 0 +github.com/muety/wakapi/services/language_mapping.go:50.2,50.33 1 0 +github.com/muety/wakapi/services/language_mapping.go:53.2,53.22 1 0 +github.com/muety/wakapi/services/language_mapping.go:46.16,48.3 1 0 +github.com/muety/wakapi/services/language_mapping.go:50.33,52.3 1 0 +github.com/muety/wakapi/services/language_mapping.go:56.109,58.16 2 0 +github.com/muety/wakapi/services/language_mapping.go:62.2,63.20 2 0 +github.com/muety/wakapi/services/language_mapping.go:58.16,60.3 1 0 +github.com/muety/wakapi/services/language_mapping.go:66.82,67.26 1 0 +github.com/muety/wakapi/services/language_mapping.go:70.2,72.12 3 0 +github.com/muety/wakapi/services/language_mapping.go:67.26,69.3 1 0 +github.com/muety/wakapi/services/language_mapping.go:75.74,78.2 1 0 +github.com/muety/wakapi/services/aggregation.go:24.142,31.2 1 0 +github.com/muety/wakapi/services/aggregation.go:40.43,42.37 1 0 +github.com/muety/wakapi/services/aggregation.go:46.2,48.19 3 0 +github.com/muety/wakapi/services/aggregation.go:42.37,44.3 1 0 +github.com/muety/wakapi/services/aggregation.go:51.67,55.40 3 0 +github.com/muety/wakapi/services/aggregation.go:59.2,59.50 1 0 +github.com/muety/wakapi/services/aggregation.go:64.2,64.60 1 0 +github.com/muety/wakapi/services/aggregation.go:70.2,70.35 1 0 +github.com/muety/wakapi/services/aggregation.go:55.40,57.3 1 0 +github.com/muety/wakapi/services/aggregation.go:59.50,61.3 1 0 +github.com/muety/wakapi/services/aggregation.go:64.60,68.3 3 0 +github.com/muety/wakapi/services/aggregation.go:73.109,74.24 1 0 +github.com/muety/wakapi/services/aggregation.go:74.24,75.111 1 0 +github.com/muety/wakapi/services/aggregation.go:75.111,77.4 1 0 +github.com/muety/wakapi/services/aggregation.go:77.9,80.4 2 0 +github.com/muety/wakapi/services/aggregation.go:84.80,85.33 1 0 +github.com/muety/wakapi/services/aggregation.go:85.33,86.60 1 0 +github.com/muety/wakapi/services/aggregation.go:86.60,88.4 1 0 +github.com/muety/wakapi/services/aggregation.go:92.100,96.59 3 0 +github.com/muety/wakapi/services/aggregation.go:111.2,112.16 2 0 +github.com/muety/wakapi/services/aggregation.go:118.2,119.16 2 0 +github.com/muety/wakapi/services/aggregation.go:125.2,126.44 2 0 +github.com/muety/wakapi/services/aggregation.go:131.2,131.41 1 0 +github.com/muety/wakapi/services/aggregation.go:145.2,145.12 1 0 +github.com/muety/wakapi/services/aggregation.go:96.59,99.3 2 0 +github.com/muety/wakapi/services/aggregation.go:99.8,99.47 1 0 +github.com/muety/wakapi/services/aggregation.go:99.47,101.30 2 0 +github.com/muety/wakapi/services/aggregation.go:101.30,102.43 1 0 +github.com/muety/wakapi/services/aggregation.go:102.43,104.5 1 0 +github.com/muety/wakapi/services/aggregation.go:106.8,108.3 1 0 +github.com/muety/wakapi/services/aggregation.go:112.16,115.3 2 0 +github.com/muety/wakapi/services/aggregation.go:119.16,122.3 2 0 +github.com/muety/wakapi/services/aggregation.go:126.44,128.3 1 0 +github.com/muety/wakapi/services/aggregation.go:131.41,132.21 1 0 +github.com/muety/wakapi/services/aggregation.go:132.21,136.4 1 0 +github.com/muety/wakapi/services/aggregation.go:136.9,136.62 1 0 +github.com/muety/wakapi/services/aggregation.go:136.62,140.4 1 0 +github.com/muety/wakapi/services/aggregation.go:148.83,163.41 5 0 +github.com/muety/wakapi/services/aggregation.go:163.41,173.3 3 0 +github.com/muety/wakapi/services/aggregation.go:176.34,179.2 2 0 +github.com/muety/wakapi/services/heartbeat.go:17.141,23.2 1 0 +github.com/muety/wakapi/services/heartbeat.go:25.80,27.2 1 0 +github.com/muety/wakapi/services/heartbeat.go:29.111,31.16 2 0 +github.com/muety/wakapi/services/heartbeat.go:34.2,34.43 1 0 +github.com/muety/wakapi/services/heartbeat.go:31.16,33.3 1 0 +github.com/muety/wakapi/services/heartbeat.go:37.78,39.2 1 0 +github.com/muety/wakapi/services/heartbeat.go:41.62,43.2 1 0 +github.com/muety/wakapi/services/heartbeat.go:45.116,47.16 2 0 +github.com/muety/wakapi/services/heartbeat.go:51.2,51.28 1 0 +github.com/muety/wakapi/services/heartbeat.go:55.2,55.24 1 0 +github.com/muety/wakapi/services/heartbeat.go:47.16,49.3 1 0 +github.com/muety/wakapi/services/heartbeat.go:51.28,53.3 1 0 diff --git a/main.go b/main.go index e1e3165..9a83615 100644 --- a/main.go +++ b/main.go @@ -112,7 +112,7 @@ func main() { summaryHandler := routes.NewSummaryHandler(summaryService) healthHandler := routes.NewHealthHandler(db) heartbeatHandler := routes.NewHeartbeatHandler(heartbeatService, languageMappingService) - settingsHandler := routes.NewSettingsHandler(userService, summaryService, aggregationService, languageMappingService) + settingsHandler := routes.NewSettingsHandler(userService, summaryService, aliasService, aggregationService, languageMappingService) homeHandler := routes.NewHomeHandler(keyValueService) loginHandler := routes.NewLoginHandler(userService) imprintHandler := routes.NewImprintHandler(keyValueService) @@ -160,6 +160,8 @@ func main() { // Settings Routes settingsRouter.Methods(http.MethodGet).HandlerFunc(settingsHandler.GetIndex) settingsRouter.Path("/credentials").Methods(http.MethodPost).HandlerFunc(settingsHandler.PostCredentials) + settingsRouter.Path("/aliases").Methods(http.MethodPost).HandlerFunc(settingsHandler.PostAlias) + settingsRouter.Path("/aliases/delete").Methods(http.MethodPost).HandlerFunc(settingsHandler.DeleteAlias) settingsRouter.Path("/language_mappings").Methods(http.MethodPost).HandlerFunc(settingsHandler.PostLanguageMapping) settingsRouter.Path("/language_mappings/delete").Methods(http.MethodPost).HandlerFunc(settingsHandler.DeleteLanguageMapping) settingsRouter.Path("/reset").Methods(http.MethodPost).HandlerFunc(settingsHandler.PostResetApiKey) diff --git a/mocks/alias_repository.go b/mocks/alias_repository.go index 1ccd800..8b3114f 100644 --- a/mocks/alias_repository.go +++ b/mocks/alias_repository.go @@ -13,3 +13,33 @@ func (m *AliasRepositoryMock) GetByUser(s string) ([]*models.Alias, error) { args := m.Called(s) return args.Get(0).([]*models.Alias), args.Error(1) } + +func (m *AliasRepositoryMock) GetByUserAndKey(s string, s2 string) ([]*models.Alias, error) { + args := m.Called(s, s2) + return args.Get(0).([]*models.Alias), args.Error(1) +} + +func (m *AliasRepositoryMock) GetByUserAndKeyAndType(s string, s2 string, u uint8) ([]*models.Alias, error) { + args := m.Called(s, s2, u) + return args.Get(0).([]*models.Alias), args.Error(1) +} + +func (m *AliasRepositoryMock) GetByUserAndTypeAndValue(s string, u uint8, s2 string) (*models.Alias, error) { + args := m.Called(s, u, s2) + return args.Get(0).(*models.Alias), args.Error(1) +} + +func (m *AliasRepositoryMock) Insert(s *models.Alias) (*models.Alias, error) { + args := m.Called(s) + return args.Get(0).(*models.Alias), args.Error(1) +} + +func (m *AliasRepositoryMock) Delete(u uint) error { + args := m.Called(u) + return args.Error(0) +} + +func (m *AliasRepositoryMock) DeleteBatch(u []uint) error { + args := m.Called(u) + return args.Error(0) +} diff --git a/mocks/alias_service.go b/mocks/alias_service.go index 1e8223b..332ecb1 100644 --- a/mocks/alias_service.go +++ b/mocks/alias_service.go @@ -1,6 +1,7 @@ package mocks import ( + "github.com/muety/wakapi/models" "github.com/stretchr/testify/mock" ) @@ -8,7 +9,12 @@ type AliasServiceMock struct { mock.Mock } -func (m *AliasServiceMock) LoadUserAliases(s string) error { +func (m *AliasServiceMock) IsInitialized(s string) bool { + args := m.Called(s) + return args.Bool(0) +} + +func (m *AliasServiceMock) InitializeUser(s string) error { args := m.Called(s) return args.Error(0) } @@ -18,7 +24,27 @@ func (m *AliasServiceMock) GetAliasOrDefault(s string, u uint8, s2 string) (stri return args.String(0), args.Error(1) } -func (m *AliasServiceMock) IsInitialized(s string) bool { +func (m *AliasServiceMock) GetByUser(s string) ([]*models.Alias, error) { args := m.Called(s) - return args.Bool(0) + return args.Get(0).([]*models.Alias), args.Error(1) +} + +func (m *AliasServiceMock) GetByUserAndKeyAndType(s string, s2 string, u uint8) ([]*models.Alias, error) { + args := m.Called(s, s2, u) + return args.Get(0).([]*models.Alias), args.Error(1) +} + +func (m *AliasServiceMock) Create(a *models.Alias) (*models.Alias, error) { + args := m.Called(a) + return args.Get(0).(*models.Alias), args.Error(1) +} + +func (m *AliasServiceMock) Delete(s *models.Alias) error { + args := m.Called(s) + return args.Error(0) +} + +func (m *AliasServiceMock) DeleteMulti(a []*models.Alias) error { + args := m.Called(a) + return args.Error(0) } diff --git a/models/alias.go b/models/alias.go index a6136ba..316745b 100644 --- a/models/alias.go +++ b/models/alias.go @@ -8,3 +8,16 @@ type Alias struct { Key string `gorm:"not null; index:idx_alias_type_key"` Value string `gorm:"not null"` } + +func (a *Alias) IsValid() bool { + return a.Key != "" && a.Value != "" && a.validateType() +} + +func (a *Alias) validateType() bool { + for _, t := range SummaryTypes() { + if a.Type == t { + return true + } + } + return false +} diff --git a/models/view/settings.go b/models/view/settings.go index cbcd281..02dd846 100644 --- a/models/view/settings.go +++ b/models/view/settings.go @@ -5,10 +5,17 @@ import "github.com/muety/wakapi/models" type SettingsViewModel struct { User *models.User LanguageMappings []*models.LanguageMapping + Aliases []*SettingsVMCombinedAlias Success string Error string } +type SettingsVMCombinedAlias struct { + Key string + Type uint8 + Values []string +} + func (s *SettingsViewModel) WithSuccess(m string) *SettingsViewModel { s.Success = m return s diff --git a/repositories/alias.go b/repositories/alias.go index c905828..cc2faf6 100644 --- a/repositories/alias.go +++ b/repositories/alias.go @@ -1,6 +1,7 @@ package repositories import ( + "errors" "github.com/muety/wakapi/models" "gorm.io/gorm" ) @@ -22,3 +23,67 @@ func (r *AliasRepository) GetByUser(userId string) ([]*models.Alias, error) { } return aliases, nil } + +func (r *AliasRepository) GetByUserAndKey(userId, key string) ([]*models.Alias, error) { + var aliases []*models.Alias + if err := r.db. + Where(&models.Alias{ + UserID: userId, + Key: key, + }). + Find(&aliases).Error; err != nil { + return nil, err + } + return aliases, nil +} + +func (r *AliasRepository) GetByUserAndKeyAndType(userId, key string, summaryType uint8) ([]*models.Alias, error) { + var aliases []*models.Alias + if err := r.db. + Where(&models.Alias{ + UserID: userId, + Key: key, + Type: summaryType, + }). + Find(&aliases).Error; err != nil { + return nil, err + } + return aliases, nil +} + +func (r *AliasRepository) GetByUserAndTypeAndValue(userId string, summaryType uint8, value string) (*models.Alias, error) { + alias := &models.Alias{} + if err := r.db. + Where(&models.Alias{ + UserID: userId, + Type: summaryType, + Value: value, + }). + First(alias).Error; err != nil { + return nil, err + } + return alias, nil +} + +func (r *AliasRepository) Insert(alias *models.Alias) (*models.Alias, error) { + if !alias.IsValid() { + return nil, errors.New("invalid alias") + } + result := r.db.Create(alias) + if err := result.Error; err != nil { + return nil, err + } + return alias, nil +} + +func (r *AliasRepository) Delete(id uint) error { + return r.db. + Where("id = ?", id). + Delete(models.Alias{}).Error +} + +func (r *AliasRepository) DeleteBatch(ids []uint) error { + return r.db. + Where("id IN ?", ids). + Delete(models.Alias{}).Error +} diff --git a/repositories/key_value.go b/repositories/key_value.go index d66d01a..70c24fc 100644 --- a/repositories/key_value.go +++ b/repositories/key_value.go @@ -5,6 +5,7 @@ import ( "github.com/muety/wakapi/models" "gorm.io/gorm" "gorm.io/gorm/clause" + "log" ) type KeyValueRepository struct { @@ -40,7 +41,7 @@ func (r *KeyValueRepository) PutString(kv *models.KeyStringValue) error { } if result.RowsAffected != 1 { - return errors.New("nothing updated") + log.Printf("warning: did not insert key '%s', maybe just updated?\n", kv.Key) } return nil diff --git a/repositories/repositories.go b/repositories/repositories.go index 1564763..a05408d 100644 --- a/repositories/repositories.go +++ b/repositories/repositories.go @@ -6,7 +6,13 @@ import ( ) type IAliasRepository interface { + Insert(*models.Alias) (*models.Alias, error) + Delete(uint) error + DeleteBatch([]uint) error GetByUser(string) ([]*models.Alias, error) + GetByUserAndKey(string, string) ([]*models.Alias, error) + GetByUserAndKeyAndType(string, string, uint8) ([]*models.Alias, error) + GetByUserAndTypeAndValue(string, uint8, string) (*models.Alias, error) } type IHeartbeatRepository interface { diff --git a/routes/routes.go b/routes/routes.go index 576a995..6c5534d 100644 --- a/routes/routes.go +++ b/routes/routes.go @@ -3,6 +3,7 @@ package routes import ( "fmt" "github.com/muety/wakapi/config" + "github.com/muety/wakapi/models" "github.com/muety/wakapi/utils" "html/template" "io/ioutil" @@ -19,11 +20,15 @@ var templates map[string]*template.Template func loadTemplates() { tplPath := "views" tpls := template.New("").Funcs(template.FuncMap{ - "json": utils.Json, - "date": utils.FormatDateHuman, - "title": strings.Title, - "capitalize": utils.Capitalize, - "toRunes": utils.ToRunes, + "json": utils.Json, + "date": utils.FormatDateHuman, + "title": strings.Title, + "join": strings.Join, + "add": utils.Add, + "capitalize": utils.Capitalize, + "toRunes": utils.ToRunes, + "entityTypes": models.SummaryTypes, + "typeName": typeName, "getBasePath": func() string { return config.Get().Server.BasePath }, @@ -58,3 +63,22 @@ func loadTemplates() { templates[tplName] = tpl } } + +func typeName(t uint8) string { + if t == models.SummaryProject { + return "project" + } + if t == models.SummaryLanguage { + return "language" + } + if t == models.SummaryEditor { + return "editor" + } + if t == models.SummaryOS { + return "operating system" + } + if t == models.SummaryMachine { + return "machine" + } + return "unknown" +} diff --git a/routes/settings.go b/routes/settings.go index 9b2b5b2..4e4d115 100644 --- a/routes/settings.go +++ b/routes/settings.go @@ -17,16 +17,18 @@ type SettingsHandler struct { config *conf.Config userSrvc services.IUserService summarySrvc services.ISummaryService + aliasSrvc services.IAliasService aggregationSrvc services.IAggregationService languageMappingSrvc services.ILanguageMappingService } var credentialsDecoder = schema.NewDecoder() -func NewSettingsHandler(userService services.IUserService, summaryService services.ISummaryService, aggregationService services.IAggregationService, languageMappingService services.ILanguageMappingService) *SettingsHandler { +func NewSettingsHandler(userService services.IUserService, summaryService services.ISummaryService, aliasService services.IAliasService, aggregationService services.IAggregationService, languageMappingService services.ILanguageMappingService) *SettingsHandler { return &SettingsHandler{ config: conf.Get(), summarySrvc: summaryService, + aliasSrvc: aliasService, aggregationSrvc: aggregationService, languageMappingSrvc: languageMappingService, userSrvc: userService, @@ -161,6 +163,60 @@ func (h *SettingsHandler) PostLanguageMapping(w http.ResponseWriter, r *http.Req templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping added successfully")) } +func (h *SettingsHandler) DeleteAlias(w http.ResponseWriter, r *http.Request) { + if h.config.IsDev() { + loadTemplates() + } + + user := r.Context().Value(models.UserKey).(*models.User) + aliasKey := r.PostFormValue("key") + aliasType, err := strconv.Atoi(r.PostFormValue("type")) + if err != nil { + aliasType = 99 // nothing will be found later on + } + + if aliases, err := h.aliasSrvc.GetByUserAndKeyAndType(user.ID, aliasKey, uint8(aliasType)); err != nil { + w.WriteHeader(http.StatusNotFound) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("aliases not found")) + return + } else if err := h.aliasSrvc.DeleteMulti(aliases); err != nil { + w.WriteHeader(http.StatusInternalServerError) + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete aliases")) + return + } + + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("aliases deleted successfully")) +} + +func (h *SettingsHandler) PostAlias(w http.ResponseWriter, r *http.Request) { + if h.config.IsDev() { + loadTemplates() + } + user := r.Context().Value(models.UserKey).(*models.User) + aliasKey := r.PostFormValue("key") + aliasValue := r.PostFormValue("value") + aliasType, err := strconv.Atoi(r.PostFormValue("type")) + if err != nil { + aliasType = 99 // Alias.IsValid() will return false later on + } + + alias := &models.Alias{ + UserID: user.ID, + Key: aliasKey, + Value: aliasValue, + Type: uint8(aliasType), + } + + if _, err := h.aliasSrvc.Create(alias); err != nil { + w.WriteHeader(http.StatusBadRequest) + // TODO: distinguish between bad request, conflict and server error + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid input")) + return + } + + templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("alias added successfully")) +} + func (h *SettingsHandler) PostResetApiKey(w http.ResponseWriter, r *http.Request) { if h.config.IsDev() { loadTemplates() @@ -220,9 +276,34 @@ func (h *SettingsHandler) PostRegenerateSummaries(w http.ResponseWriter, r *http func (h *SettingsHandler) buildViewModel(r *http.Request) *view.SettingsViewModel { user := r.Context().Value(models.UserKey).(*models.User) mappings, _ := h.languageMappingSrvc.GetByUser(user.ID) + aliases, _ := h.aliasSrvc.GetByUser(user.ID) + aliasMap := make(map[string][]*models.Alias) + for _, a := range aliases { + k := fmt.Sprintf("%s_%d", a.Key, a.Type) + if _, ok := aliasMap[k]; !ok { + aliasMap[k] = []*models.Alias{a} + } else { + aliasMap[k] = append(aliasMap[k], a) + } + } + + combinedAliases := make([]*view.SettingsVMCombinedAlias, 0) + for _, l := range aliasMap { + ca := &view.SettingsVMCombinedAlias{ + Key: l[0].Key, + Type: l[0].Type, + Values: make([]string, len(l)), + } + for i, a := range l { + ca.Values[i] = a.Value + } + combinedAliases = append(combinedAliases, ca) + } + return &view.SettingsViewModel{ User: user, LanguageMappings: mappings, + Aliases: combinedAliases, Success: r.URL.Query().Get("success"), Error: r.URL.Query().Get("error"), } diff --git a/services/alias.go b/services/alias.go index 3ee0797..02b78da 100644 --- a/services/alias.go +++ b/services/alias.go @@ -1,11 +1,12 @@ package services import ( + "errors" "github.com/muety/wakapi/config" - "github.com/muety/wakapi/repositories" - "sync" - "github.com/muety/wakapi/models" + "github.com/muety/wakapi/repositories" + "log" + "sync" ) type AliasService struct { @@ -22,7 +23,14 @@ func NewAliasService(aliasRepo repositories.IAliasRepository) *AliasService { var userAliases sync.Map -func (srv *AliasService) LoadUserAliases(userId string) error { +func (srv *AliasService) IsInitialized(userId string) bool { + if _, ok := userAliases.Load(userId); ok { + return true + } + return false +} + +func (srv *AliasService) InitializeUser(userId string) error { aliases, err := srv.repository.GetByUser(userId) if err == nil { userAliases.Store(userId, aliases) @@ -30,9 +38,25 @@ func (srv *AliasService) LoadUserAliases(userId string) error { return err } +func (srv *AliasService) GetByUser(userId string) ([]*models.Alias, error) { + aliases, err := srv.repository.GetByUser(userId) + if err != nil { + return nil, err + } + return aliases, nil +} + +func (srv *AliasService) GetByUserAndKeyAndType(userId, key string, summaryType uint8) ([]*models.Alias, error) { + aliases, err := srv.repository.GetByUserAndKeyAndType(userId, key, summaryType) + if err != nil { + return nil, err + } + return aliases, nil +} + func (srv *AliasService) GetAliasOrDefault(userId string, summaryType uint8, value string) (string, error) { if !srv.IsInitialized(userId) { - if err := srv.LoadUserAliases(userId); err != nil { + if err := srv.InitializeUser(userId); err != nil { return "", err } } @@ -46,9 +70,46 @@ func (srv *AliasService) GetAliasOrDefault(userId string, summaryType uint8, val return value, nil } -func (srv *AliasService) IsInitialized(userId string) bool { - if _, ok := userAliases.Load(userId); ok { - return true +func (srv *AliasService) Create(alias *models.Alias) (*models.Alias, error) { + result, err := srv.repository.Insert(alias) + if err != nil { + return nil, err + } + go srv.reinitUser(alias.UserID) + return result, nil +} + +func (srv *AliasService) Delete(alias *models.Alias) error { + if alias.UserID == "" { + return errors.New("no user id specified") + } + err := srv.repository.Delete(alias.ID) + go srv.reinitUser(alias.UserID) + return err +} + +func (srv *AliasService) DeleteMulti(aliases []*models.Alias) error { + ids := make([]uint, len(aliases)) + affectedUsers := make(map[string]bool) + for i, a := range aliases { + if a.UserID == "" { + return errors.New("no user id specified") + } + affectedUsers[a.UserID] = true + ids[i] = a.ID + } + + err := srv.repository.DeleteBatch(ids) + + for k := range affectedUsers { + go srv.reinitUser(k) + } + + return err +} + +func (srv *AliasService) reinitUser(userId string) { + if err := srv.InitializeUser(userId); err != nil { + log.Printf("error initializing user aliases – %v\n", err) } - return false } diff --git a/services/language_mapping.go b/services/language_mapping.go index acc251d..7324118 100644 --- a/services/language_mapping.go +++ b/services/language_mapping.go @@ -1,6 +1,7 @@ package services import ( + "errors" "github.com/muety/wakapi/config" "github.com/muety/wakapi/models" "github.com/muety/wakapi/repositories" @@ -18,7 +19,7 @@ func NewLanguageMappingService(languageMappingsRepo repositories.ILanguageMappin return &LanguageMappingService{ config: config.Get(), repository: languageMappingsRepo, - cache: cache.New(1*time.Hour, 2*time.Hour), + cache: cache.New(24*time.Hour, 24*time.Hour), } } @@ -63,6 +64,9 @@ func (srv *LanguageMappingService) Create(mapping *models.LanguageMapping) (*mod } func (srv *LanguageMappingService) Delete(mapping *models.LanguageMapping) error { + if mapping.UserID == "" { + return errors.New("no user id specified") + } err := srv.repository.Delete(mapping.ID) srv.cache.Delete(mapping.UserID) return err diff --git a/services/services.go b/services/services.go index d81c791..7ae92f5 100644 --- a/services/services.go +++ b/services/services.go @@ -15,9 +15,14 @@ type IMiscService interface { } type IAliasService interface { - LoadUserAliases(string) error - GetAliasOrDefault(string, uint8, string) (string, error) + Create(*models.Alias) (*models.Alias, error) + Delete(*models.Alias) error + DeleteMulti([]*models.Alias) error IsInitialized(string) bool + InitializeUser(string) error + GetByUser(string) ([]*models.Alias, error) + GetByUserAndKeyAndType(string, string, uint8) ([]*models.Alias, error) + GetAliasOrDefault(string, uint8, string) (string, error) } type IHeartbeatService interface { diff --git a/services/summary.go b/services/summary.go index adb1ea5..2c3f5a3 100644 --- a/services/summary.go +++ b/services/summary.go @@ -50,7 +50,7 @@ func (srv *SummaryService) Aliased(from, to time.Time, user *models.User, f Summ } // Initialize alias resolver service - if err := srv.aliasService.LoadUserAliases(user.ID); err != nil { + if err := srv.aliasService.InitializeUser(user.ID); err != nil { return nil, err } diff --git a/services/summary_test.go b/services/summary_test.go index ab02105..3d276a8 100644 --- a/services/summary_test.go +++ b/services/summary_test.go @@ -249,7 +249,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Aliased() { from, to = suite.TestStartTime, suite.TestStartTime.Add(1*time.Hour) suite.HeartbeatService.On("GetAllWithin", from, to, suite.TestUser).Return(filter(from, to, suite.TestHeartbeats), nil) - suite.AliasService.On("LoadUserAliases", TestUserId).Return(nil) + suite.AliasService.On("InitializeUser", TestUserId).Return(nil) suite.AliasService.On("GetAliasOrDefault", TestUserId, models.SummaryProject, TestProject1).Return(TestProject2, nil) suite.AliasService.On("GetAliasOrDefault", TestUserId, mock.Anything, mock.Anything).Return("", nil) diff --git a/utils/common.go b/utils/common.go index f46d92d..dd0a829 100644 --- a/utils/common.go +++ b/utils/common.go @@ -18,6 +18,10 @@ func FormatDateHuman(date time.Time) string { return date.Format("Mon, 02 Jan 2006 15:04") } +func Add(i, j int) int { + return i + j +} + func ParseUserAgent(ua string) (string, string, error) { re := regexp.MustCompile(`(?iU)^wakatime\/[\d+.]+\s\((\w+)-.*\)\s.+\s([^\/\s]+)-wakatime\/.+$`) groups := re.FindAllStringSubmatch(ua, -1) diff --git a/version.txt b/version.txt index b9fb27a..815d5ca 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.18.3 +1.19.0 diff --git a/views/settings.tpl.html b/views/settings.tpl.html index 29d7295..3c1ab8c 100644 --- a/views/settings.tpl.html +++ b/views/settings.tpl.html @@ -5,6 +5,18 @@ + + {{ template "header.tpl.html" . }}
@@ -19,8 +31,31 @@
+ +
-
+
Change Password
@@ -52,13 +87,15 @@
-
+
Reset API Key
- ⚠️ Caution: Resetting your API key requires you to update your .wakatime.cfg files on all of your computers to make the WakaTime client send heartbeats again. + ⚠️ Caution: Resetting your API key requires you to update your .wakatime.cfg files on all of your computers to make the WakaTime + client send heartbeats again.
@@ -69,112 +106,197 @@
-
+
- Language Mappings + Aliases
- +
- You can specify custom mapping from file extensions to programming languages (e.g. a .jsx file could be mapped to React.) + You can specify aliases for any type of entity. For instance, you can define a rule, that both myapp-frontend and myapp-backend are combined under a + project called myapp.
- {{ if .LanguageMappings }} - {{ range $i, $mapping := .LanguageMappings }} -
- - {{ $mapping.Extension }} - - {{ $mapping.Language }} - -
- -
{{end}} - {{else}} -
- No rules. -
+
{{end}} -
-
- - -
-
- - -
-
- +

Add Rule

+ +
+ Map + + named + + to + +
+ +
-
-
+
+ Languages & File Extensions +
+ +
+ You can specify custom mapping from file extensions to programming languages, for instance a .jsx file could be mapped to the React language. +
+ + {{ if .LanguageMappings }} +

Rules

+ {{ range $i, $mapping := .LanguageMappings }} +
+
+ ▸  When filename ends in {{ $mapping.Extension }} + then change the language to {{ $mapping.Language }} +
+
+ + +
+
+ {{end}} +
+ {{end}} + +

Add Rule

+
+
+ When filename ends in + + change language to + +
+ +
+
+
+
+ +
+
Badges
{{ if .User.BadgesEnabled }} -

Badges are currently enabled. You can disable the feature by deactivating the respective API endpoint.

+

Badges are currently enabled. You can disable the feature by deactivating the respective API + endpoint.

-
- GET /api/compat/shields/v1 - -
+
+ GET /api/compat/shields/v1 + +
-

Examples

-
-
-
- Shields.io badge -
- +

Examples

+
+
+
+ Shields.io badge +
+ https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=blue&label=today +
+
+
+ Shields.io badge
-
-
- Shields.io badge -
- + https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=blue&label=last 30d -
+
-

You can also add /project:your-cool-project to the URL to filter by project.

+

You can also add /project:your-cool-project + to the URL to filter by project.

{{ else }} -

You have the ability to create badges from your coding statistics using Shields.io. To do so, you need to grant public, unauthorized access to the respective endpoint.

-
- GET /api/compat/shields/v1 - -
+

You have the ability to create badges from your coding statistics using Shields.io. To do so, you need to grant public, unauthorized + access to the respective endpoint.

+
+ GET /api/compat/shields/v1 + +
{{ end }}
-
+
⚠️ Danger Zone
@@ -182,19 +304,26 @@ Regenerate summaries

- Wakapi improves its efficiency and speed by automatically aggregating individual heartbeats to summaries on a per-day basis. - That is, historic summaries, i.e. such from past days, are generated once and only fetched from the database in a static fashion afterwards, unless you pass &recompute=true with your request. + Wakapi improves its efficiency and speed by automatically aggregating individual heartbeats to + summaries on a per-day basis. + That is, historic summaries, i.e. such from past days, are generated once and only fetched from the + database in a static fashion afterwards, unless you pass &recompute=true + with your request.

- If, for some reason, these aggregated summaries are faulty or preconditions have change (e.g. you modified language mappings retrospectively), you may want to re-generate them from raw heartbeats. + If, for some reason, these aggregated summaries are faulty or preconditions have change (e.g. you + modified language mappings retrospectively), you may want to re-generate them from raw heartbeats.

- Note: Only run this action if you know what you are doing. Data might be lost is case heartbeats were deleted after the respective summaries had been generated. + Note: Only run this action if you know what you are doing. Data might be lost is + case heartbeats were deleted after the respective summaries had been generated.

-
@@ -214,7 +343,7 @@ e.classList.remove('hidden') }) - const btnRegenerate = document.querySelector("#btn-regenerate-summaries") + const btnRegenerate = document.querySelector('#btn-regenerate-summaries') const formRegenerate = document.querySelector('#form-regenerate-summaries') btnRegenerate.addEventListener('click', () => { if (confirm('Are you sure?')) {