feat: email reports (resolve #124)

This commit is contained in:
Ferdinand Mütsch 2021-04-30 14:07:14 +02:00
parent 1beca82875
commit 29c04c3ac5
23 changed files with 913 additions and 468 deletions

View File

@ -11,6 +11,7 @@ server:
app:
aggregation_time: '02:15' # time at which to run daily aggregation batch jobs
report_time_weekly: 'fri,18:00' # time at which to fan out weekly reports (format: '<weekday)>,<daytime>')
inactive_days: 7 # time of previous days within a user must have logged in to be considered active
custom_languages:
vue: Vue
@ -45,14 +46,14 @@ sentry:
mail:
enabled: true # whether to enable mails (used for password resets, reports, etc.)
provider: smtp # method for sending mails, currently one of ['smtp', 'mailwhale']
smtp: # smtp settings when sending mails via smtp
host:
port:
username:
password:
tls:
sender: Wakapi <noreply@wakapi.dev>
mailwhale: # mailwhale.dev settings when using mailwhale as sending service
smtp: # smtp settings when sending mails via smtp
host:
port:
username:
password:
tls:
sender: Wakapi <noreply@wakapi.dev>
mailwhale: # mailwhale.dev settings when using mailwhale as sending service
url:
client_id:
client_secret:

View File

@ -8,6 +8,7 @@ import (
"net/http"
"os"
"strings"
"time"
"github.com/emvi/logbuch"
"github.com/gorilla/securecookie"
@ -61,6 +62,7 @@ var env string
type appConfig struct {
AggregationTime string `yaml:"aggregation_time" default:"02:15" env:"WAKAPI_AGGREGATION_TIME"`
ReportTimeWeekly string `yaml:"report_time_weekly" default:"fri,18:00" env:"WAKAPI_REPORT_TIME_WEEKLY"`
ImportBackoffMin int `yaml:"import_backoff_min" default:"5" env:"WAKAPI_IMPORT_BACKOFF_MIN"`
ImportBatchSize int `yaml:"import_batch_size" default:"100" env:"WAKAPI_IMPORT_BATCH_SIZE"`
InactiveDays int `yaml:"inactive_days" default:"7" env:"WAKAPI_INACTIVE_DAYS"`
@ -216,6 +218,15 @@ func (c *appConfig) GetOSColors() map[string]string {
return cloneStringMap(c.Colors["operating_systems"], true)
}
func (c *appConfig) GetWeeklyReportDay() time.Weekday {
s := strings.Split(c.ReportTimeWeekly, ",")[0]
return parseWeekday(s)
}
func (c *appConfig) GetWeeklyReportTime() string {
return strings.Split(c.ReportTimeWeekly, ",")[1]
}
func (c *serverConfig) GetPublicUrl() string {
return strings.TrimSuffix(c.PublicUrl, "/")
}
@ -274,6 +285,26 @@ func findString(needle string, haystack []string, defaultVal string) string {
return defaultVal
}
func parseWeekday(s string) time.Weekday {
switch strings.ToLower(s) {
case "mon", strings.ToLower(time.Monday.String()):
return time.Monday
case "tue", strings.ToLower(time.Tuesday.String()):
return time.Tuesday
case "wed", strings.ToLower(time.Wednesday.String()):
return time.Wednesday
case "thu", strings.ToLower(time.Thursday.String()):
return time.Thursday
case "fri", strings.ToLower(time.Friday.String()):
return time.Friday
case "sat", strings.ToLower(time.Saturday.String()):
return time.Saturday
case "sun", strings.ToLower(time.Sunday.String()):
return time.Sunday
}
return time.Monday
}
func Set(config *Config) {
cfg = config
}

View File

@ -1,4 +1,81 @@
mode: set
github.com/muety/wakapi/models/heartbeat.go:32.34,34.2 1 1
github.com/muety/wakapi/models/heartbeat.go:36.65,38.46 2 1
github.com/muety/wakapi/models/heartbeat.go:38.46,39.108 1 1
github.com/muety/wakapi/models/heartbeat.go:39.108,42.4 2 1
github.com/muety/wakapi/models/heartbeat.go:46.50,47.11 1 1
github.com/muety/wakapi/models/heartbeat.go:60.2,60.15 1 1
github.com/muety/wakapi/models/heartbeat.go:64.2,64.12 1 1
github.com/muety/wakapi/models/heartbeat.go:48.22,49.18 1 1
github.com/muety/wakapi/models/heartbeat.go:50.21,51.17 1 1
github.com/muety/wakapi/models/heartbeat.go:52.23,53.19 1 1
github.com/muety/wakapi/models/heartbeat.go:54.17,55.26 1 1
github.com/muety/wakapi/models/heartbeat.go:56.22,57.18 1 1
github.com/muety/wakapi/models/heartbeat.go:60.15,62.3 1 1
github.com/muety/wakapi/models/heartbeat.go:67.37,83.2 1 0
github.com/muety/wakapi/models/heartbeat.go:91.41,93.16 2 0
github.com/muety/wakapi/models/heartbeat.go:96.2,97.10 2 0
github.com/muety/wakapi/models/heartbeat.go:93.16,95.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/mail.go:16.44,20.2 3 0
github.com/muety/wakapi/models/mail.go:22.44,26.2 3 0
github.com/muety/wakapi/models/mail.go:28.32,41.2 1 0
github.com/muety/wakapi/models/mail.go:43.41,45.2 1 0
github.com/muety/wakapi/models/models.go:3.14,5.2 0 1
github.com/muety/wakapi/models/shared.go:35.52,37.2 1 0
github.com/muety/wakapi/models/shared.go:39.52,42.16 3 0
github.com/muety/wakapi/models/shared.go:45.2,47.12 3 0
github.com/muety/wakapi/models/shared.go:42.16,44.3 1 0
github.com/muety/wakapi/models/shared.go:50.52,56.22 2 0
github.com/muety/wakapi/models/shared.go:71.2,74.12 3 0
github.com/muety/wakapi/models/shared.go:57.14,61.17 2 0
github.com/muety/wakapi/models/shared.go:64.17,66.8 2 0
github.com/muety/wakapi/models/shared.go:67.10,68.64 1 0
github.com/muety/wakapi/models/shared.go:61.17,63.4 1 0
github.com/muety/wakapi/models/shared.go:77.51,80.2 2 0
github.com/muety/wakapi/models/shared.go:82.45,84.2 1 0
github.com/muety/wakapi/models/shared.go:86.37,88.2 1 0
github.com/muety/wakapi/models/shared.go:90.35,92.2 1 0
github.com/muety/wakapi/models/shared.go:94.34,96.2 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/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
github.com/muety/wakapi/models/filters.go:20.17,21.27 1 0
github.com/muety/wakapi/models/filters.go:22.23,23.33 1 0
github.com/muety/wakapi/models/filters.go:24.21,25.31 1 0
github.com/muety/wakapi/models/filters.go:26.22,27.32 1 0
github.com/muety/wakapi/models/filters.go:32.47,33.21 1 1
github.com/muety/wakapi/models/filters.go:44.2,44.21 1 1
github.com/muety/wakapi/models/filters.go:33.21,35.3 1 1
github.com/muety/wakapi/models/filters.go:35.8,35.23 1 1
github.com/muety/wakapi/models/filters.go:35.23,37.3 1 0
github.com/muety/wakapi/models/filters.go:37.8,37.29 1 1
github.com/muety/wakapi/models/filters.go:37.29,39.3 1 1
github.com/muety/wakapi/models/filters.go:39.8,39.27 1 1
github.com/muety/wakapi/models/filters.go:39.27,41.3 1 0
github.com/muety/wakapi/models/filters.go:41.8,41.28 1 1
github.com/muety/wakapi/models/filters.go:41.28,43.3 1 0
github.com/muety/wakapi/models/interval.go:39.47,40.23 1 0
github.com/muety/wakapi/models/interval.go:45.2,45.14 1 0
github.com/muety/wakapi/models/interval.go:40.23,41.13 1 0
github.com/muety/wakapi/models/interval.go:41.13,43.4 1 0
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
github.com/muety/wakapi/models/mail_address.go:15.13,18.2 2 1
github.com/muety/wakapi/models/mail_address.go:24.38,26.2 1 0
github.com/muety/wakapi/models/mail_address.go:28.35,30.21 2 1
@ -17,66 +94,6 @@ github.com/muety/wakapi/models/mail_address.go:59.40,60.22 1 1
github.com/muety/wakapi/models/mail_address.go:65.2,65.13 1 1
github.com/muety/wakapi/models/mail_address.go:60.22,61.17 1 1
github.com/muety/wakapi/models/mail_address.go:61.17,63.4 1 1
github.com/muety/wakapi/models/models.go:3.14,5.2 0 1
github.com/muety/wakapi/models/user.go:8.13,10.2 1 1
github.com/muety/wakapi/models/user.go:76.36,77.22 1 1
github.com/muety/wakapi/models/user.go:80.2,81.16 2 1
github.com/muety/wakapi/models/user.go:84.2,84.11 1 1
github.com/muety/wakapi/models/user.go:77.22,79.3 1 1
github.com/muety/wakapi/models/user.go:81.16,83.3 1 0
github.com/muety/wakapi/models/user.go:87.41,90.2 2 1
github.com/muety/wakapi/models/user.go:92.43,95.2 1 0
github.com/muety/wakapi/models/user.go:97.45,100.2 1 0
github.com/muety/wakapi/models/user.go:102.33,107.2 1 0
github.com/muety/wakapi/models/user.go:109.41,111.2 1 0
github.com/muety/wakapi/models/user.go:113.45,115.2 1 0
github.com/muety/wakapi/models/user.go:117.45,119.2 1 0
github.com/muety/wakapi/models/user.go:121.39,123.2 1 0
github.com/muety/wakapi/models/user.go:125.39,128.2 2 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:32.34,34.2 1 1
github.com/muety/wakapi/models/heartbeat.go:36.65,38.46 2 1
github.com/muety/wakapi/models/heartbeat.go:38.46,39.108 1 1
github.com/muety/wakapi/models/heartbeat.go:39.108,42.4 2 1
github.com/muety/wakapi/models/heartbeat.go:46.50,47.11 1 1
github.com/muety/wakapi/models/heartbeat.go:60.2,60.15 1 1
github.com/muety/wakapi/models/heartbeat.go:64.2,64.12 1 1
github.com/muety/wakapi/models/heartbeat.go:48.22,49.18 1 1
github.com/muety/wakapi/models/heartbeat.go:50.21,51.17 1 1
github.com/muety/wakapi/models/heartbeat.go:52.23,53.19 1 1
github.com/muety/wakapi/models/heartbeat.go:54.17,55.26 1 1
github.com/muety/wakapi/models/heartbeat.go:56.22,57.18 1 1
github.com/muety/wakapi/models/heartbeat.go:60.15,62.3 1 1
github.com/muety/wakapi/models/heartbeat.go:67.37,83.2 1 0
github.com/muety/wakapi/models/heartbeat.go:91.41,93.16 2 0
github.com/muety/wakapi/models/heartbeat.go:96.2,97.10 2 0
github.com/muety/wakapi/models/heartbeat.go:93.16,95.3 1 0
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
github.com/muety/wakapi/models/mail.go:16.44,20.2 3 0
github.com/muety/wakapi/models/mail.go:22.44,26.2 3 0
github.com/muety/wakapi/models/mail.go:28.32,41.2 1 0
github.com/muety/wakapi/models/mail.go:43.41,45.2 1 0
github.com/muety/wakapi/models/shared.go:35.52,37.2 1 0
github.com/muety/wakapi/models/shared.go:39.52,42.16 3 0
github.com/muety/wakapi/models/shared.go:45.2,47.12 3 0
github.com/muety/wakapi/models/shared.go:42.16,44.3 1 0
github.com/muety/wakapi/models/shared.go:50.52,56.22 2 0
github.com/muety/wakapi/models/shared.go:71.2,74.12 3 0
github.com/muety/wakapi/models/shared.go:57.14,61.17 2 0
github.com/muety/wakapi/models/shared.go:64.17,66.8 2 0
github.com/muety/wakapi/models/shared.go:67.10,68.64 1 0
github.com/muety/wakapi/models/shared.go:61.17,63.4 1 0
github.com/muety/wakapi/models/shared.go:77.51,80.2 2 0
github.com/muety/wakapi/models/shared.go:82.45,84.2 1 0
github.com/muety/wakapi/models/shared.go:86.37,88.2 1 0
github.com/muety/wakapi/models/shared.go:90.35,92.2 1 0
github.com/muety/wakapi/models/shared.go:94.34,96.2 1 0
github.com/muety/wakapi/models/summary.go:70.29,72.2 1 1
github.com/muety/wakapi/models/summary.go:74.37,81.2 6 1
github.com/muety/wakapi/models/summary.go:83.35,85.2 1 1
@ -124,41 +141,98 @@ github.com/muety/wakapi/models/summary.go:208.31,210.60 1 1
github.com/muety/wakapi/models/summary.go:210.60,211.55 1 1
github.com/muety/wakapi/models/summary.go:211.55,213.6 1 1
github.com/muety/wakapi/models/summary.go:213.11,221.6 1 1
github.com/muety/wakapi/models/summary.go:238.33,240.2 1 1
github.com/muety/wakapi/models/summary.go:242.43,244.2 1 1
github.com/muety/wakapi/models/summary.go:246.38,248.2 1 1
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
github.com/muety/wakapi/models/filters.go:20.17,21.27 1 0
github.com/muety/wakapi/models/filters.go:22.23,23.33 1 0
github.com/muety/wakapi/models/filters.go:24.21,25.31 1 0
github.com/muety/wakapi/models/filters.go:26.22,27.32 1 0
github.com/muety/wakapi/models/filters.go:32.47,33.21 1 1
github.com/muety/wakapi/models/filters.go:44.2,44.21 1 1
github.com/muety/wakapi/models/filters.go:33.21,35.3 1 1
github.com/muety/wakapi/models/filters.go:35.8,35.23 1 1
github.com/muety/wakapi/models/filters.go:35.23,37.3 1 0
github.com/muety/wakapi/models/filters.go:37.8,37.29 1 1
github.com/muety/wakapi/models/filters.go:37.29,39.3 1 1
github.com/muety/wakapi/models/filters.go:39.8,39.27 1 1
github.com/muety/wakapi/models/filters.go:39.27,41.3 1 0
github.com/muety/wakapi/models/filters.go:41.8,41.28 1 1
github.com/muety/wakapi/models/filters.go:41.28,43.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/interval.go:39.47,40.23 1 0
github.com/muety/wakapi/models/interval.go:45.2,45.14 1 0
github.com/muety/wakapi/models/interval.go:40.23,41.13 1 0
github.com/muety/wakapi/models/interval.go:41.13,43.4 1 0
github.com/muety/wakapi/models/summary.go:238.50,242.2 1 0
github.com/muety/wakapi/models/summary.go:244.33,246.2 1 1
github.com/muety/wakapi/models/summary.go:248.43,250.2 1 1
github.com/muety/wakapi/models/summary.go:252.38,254.2 1 1
github.com/muety/wakapi/models/user.go:8.13,10.2 1 1
github.com/muety/wakapi/models/user.go:77.36,78.22 1 1
github.com/muety/wakapi/models/user.go:81.2,82.16 2 1
github.com/muety/wakapi/models/user.go:85.2,85.11 1 1
github.com/muety/wakapi/models/user.go:78.22,80.3 1 1
github.com/muety/wakapi/models/user.go:82.16,84.3 1 0
github.com/muety/wakapi/models/user.go:88.41,91.2 2 1
github.com/muety/wakapi/models/user.go:93.43,96.2 1 0
github.com/muety/wakapi/models/user.go:98.45,101.2 1 0
github.com/muety/wakapi/models/user.go:103.33,108.2 1 0
github.com/muety/wakapi/models/user.go:110.41,112.2 1 0
github.com/muety/wakapi/models/user.go:114.45,116.2 1 0
github.com/muety/wakapi/models/user.go:118.45,120.2 1 0
github.com/muety/wakapi/models/user.go:122.39,124.2 1 0
github.com/muety/wakapi/models/user.go:126.39,129.2 2 0
github.com/muety/wakapi/config/config.go:147.70,149.2 1 0
github.com/muety/wakapi/config/config.go:151.65,153.2 1 0
github.com/muety/wakapi/config/config.go:155.82,165.2 1 0
github.com/muety/wakapi/config/config.go:167.31,169.2 1 0
github.com/muety/wakapi/config/config.go:171.32,173.2 1 0
github.com/muety/wakapi/config/config.go:175.74,176.19 1 0
github.com/muety/wakapi/config/config.go:177.10,178.34 1 0
github.com/muety/wakapi/config/config.go:178.34,179.90 1 0
github.com/muety/wakapi/config/config.go:182.4,182.100 1 0
github.com/muety/wakapi/config/config.go:185.4,185.91 1 0
github.com/muety/wakapi/config/config.go:188.4,188.95 1 0
github.com/muety/wakapi/config/config.go:191.4,191.93 1 0
github.com/muety/wakapi/config/config.go:194.4,194.97 1 0
github.com/muety/wakapi/config/config.go:197.4,197.101 1 0
github.com/muety/wakapi/config/config.go:200.4,200.14 1 0
github.com/muety/wakapi/config/config.go:179.90,181.5 1 0
github.com/muety/wakapi/config/config.go:182.100,184.5 1 0
github.com/muety/wakapi/config/config.go:185.91,187.5 1 0
github.com/muety/wakapi/config/config.go:188.95,190.5 1 0
github.com/muety/wakapi/config/config.go:191.93,193.5 1 0
github.com/muety/wakapi/config/config.go:194.97,196.5 1 0
github.com/muety/wakapi/config/config.go:197.101,199.5 1 0
github.com/muety/wakapi/config/config.go:205.60,207.2 1 0
github.com/muety/wakapi/config/config.go:209.59,211.2 1 0
github.com/muety/wakapi/config/config.go:213.57,215.2 1 0
github.com/muety/wakapi/config/config.go:217.53,219.2 1 0
github.com/muety/wakapi/config/config.go:221.55,224.2 2 0
github.com/muety/wakapi/config/config.go:226.50,228.2 1 0
github.com/muety/wakapi/config/config.go:230.46,232.2 1 0
github.com/muety/wakapi/config/config.go:234.43,236.2 1 0
github.com/muety/wakapi/config/config.go:238.29,240.2 1 1
github.com/muety/wakapi/config/config.go:242.48,253.16 2 0
github.com/muety/wakapi/config/config.go:257.2,258.53 2 0
github.com/muety/wakapi/config/config.go:262.2,262.15 1 0
github.com/muety/wakapi/config/config.go:253.16,255.3 1 0
github.com/muety/wakapi/config/config.go:258.53,260.3 1 0
github.com/muety/wakapi/config/config.go:265.38,266.43 1 0
github.com/muety/wakapi/config/config.go:269.2,269.15 1 0
github.com/muety/wakapi/config/config.go:266.43,268.3 1 0
github.com/muety/wakapi/config/config.go:272.45,273.27 1 0
github.com/muety/wakapi/config/config.go:276.2,276.15 1 0
github.com/muety/wakapi/config/config.go:273.27,275.3 1 0
github.com/muety/wakapi/config/config.go:279.77,280.29 1 0
github.com/muety/wakapi/config/config.go:285.2,285.19 1 0
github.com/muety/wakapi/config/config.go:280.29,281.18 1 0
github.com/muety/wakapi/config/config.go:281.18,283.4 1 0
github.com/muety/wakapi/config/config.go:288.42,289.28 1 0
github.com/muety/wakapi/config/config.go:305.2,305.20 1 0
github.com/muety/wakapi/config/config.go:290.52,291.21 1 0
github.com/muety/wakapi/config/config.go:292.53,293.22 1 0
github.com/muety/wakapi/config/config.go:294.55,295.24 1 0
github.com/muety/wakapi/config/config.go:296.54,297.23 1 0
github.com/muety/wakapi/config/config.go:298.52,299.21 1 0
github.com/muety/wakapi/config/config.go:300.54,301.23 1 0
github.com/muety/wakapi/config/config.go:302.52,303.21 1 0
github.com/muety/wakapi/config/config.go:308.26,310.2 1 0
github.com/muety/wakapi/config/config.go:312.20,314.2 1 0
github.com/muety/wakapi/config/config.go:316.35,321.96 3 0
github.com/muety/wakapi/config/config.go:325.2,334.52 6 0
github.com/muety/wakapi/config/config.go:338.2,338.47 1 0
github.com/muety/wakapi/config/config.go:344.2,344.70 1 0
github.com/muety/wakapi/config/config.go:348.2,348.28 1 0
github.com/muety/wakapi/config/config.go:352.2,352.29 1 0
github.com/muety/wakapi/config/config.go:357.2,357.94 1 0
github.com/muety/wakapi/config/config.go:361.2,362.14 2 0
github.com/muety/wakapi/config/config.go:321.96,323.3 1 0
github.com/muety/wakapi/config/config.go:334.52,336.3 1 0
github.com/muety/wakapi/config/config.go:338.47,339.14 1 0
github.com/muety/wakapi/config/config.go:339.14,341.4 1 0
github.com/muety/wakapi/config/config.go:344.70,346.3 1 0
github.com/muety/wakapi/config/config.go:348.28,350.3 1 0
github.com/muety/wakapi/config/config.go:352.29,355.3 2 0
github.com/muety/wakapi/config/config.go:357.94,359.3 1 0
github.com/muety/wakapi/config/db.go:39.50,40.19 1 0
github.com/muety/wakapi/config/db.go:53.2,53.12 1 0
github.com/muety/wakapi/config/db.go:41.23,45.5 1 0
@ -210,68 +284,17 @@ github.com/muety/wakapi/config/utils.go:13.2,13.11 1 0
github.com/muety/wakapi/config/utils.go:7.22,8.18 1 0
github.com/muety/wakapi/config/utils.go:11.3,11.12 1 0
github.com/muety/wakapi/config/utils.go:8.18,10.4 1 0
github.com/muety/wakapi/config/config.go:145.70,147.2 1 0
github.com/muety/wakapi/config/config.go:149.65,151.2 1 0
github.com/muety/wakapi/config/config.go:153.82,163.2 1 0
github.com/muety/wakapi/config/config.go:165.31,167.2 1 0
github.com/muety/wakapi/config/config.go:169.32,171.2 1 0
github.com/muety/wakapi/config/config.go:173.74,174.19 1 0
github.com/muety/wakapi/config/config.go:175.10,176.34 1 0
github.com/muety/wakapi/config/config.go:176.34,177.90 1 0
github.com/muety/wakapi/config/config.go:180.4,180.100 1 0
github.com/muety/wakapi/config/config.go:183.4,183.91 1 0
github.com/muety/wakapi/config/config.go:186.4,186.95 1 0
github.com/muety/wakapi/config/config.go:189.4,189.93 1 0
github.com/muety/wakapi/config/config.go:192.4,192.97 1 0
github.com/muety/wakapi/config/config.go:195.4,195.101 1 0
github.com/muety/wakapi/config/config.go:198.4,198.14 1 0
github.com/muety/wakapi/config/config.go:177.90,179.5 1 0
github.com/muety/wakapi/config/config.go:180.100,182.5 1 0
github.com/muety/wakapi/config/config.go:183.91,185.5 1 0
github.com/muety/wakapi/config/config.go:186.95,188.5 1 0
github.com/muety/wakapi/config/config.go:189.93,191.5 1 0
github.com/muety/wakapi/config/config.go:192.97,194.5 1 0
github.com/muety/wakapi/config/config.go:195.101,197.5 1 0
github.com/muety/wakapi/config/config.go:203.60,205.2 1 0
github.com/muety/wakapi/config/config.go:207.59,209.2 1 0
github.com/muety/wakapi/config/config.go:211.57,213.2 1 0
github.com/muety/wakapi/config/config.go:215.53,217.2 1 0
github.com/muety/wakapi/config/config.go:219.46,221.2 1 0
github.com/muety/wakapi/config/config.go:223.43,225.2 1 0
github.com/muety/wakapi/config/config.go:227.29,229.2 1 1
github.com/muety/wakapi/config/config.go:231.48,242.16 2 0
github.com/muety/wakapi/config/config.go:246.2,247.53 2 0
github.com/muety/wakapi/config/config.go:251.2,251.15 1 0
github.com/muety/wakapi/config/config.go:242.16,244.3 1 0
github.com/muety/wakapi/config/config.go:247.53,249.3 1 0
github.com/muety/wakapi/config/config.go:254.38,255.43 1 0
github.com/muety/wakapi/config/config.go:258.2,258.15 1 0
github.com/muety/wakapi/config/config.go:255.43,257.3 1 0
github.com/muety/wakapi/config/config.go:261.45,262.27 1 0
github.com/muety/wakapi/config/config.go:265.2,265.15 1 0
github.com/muety/wakapi/config/config.go:262.27,264.3 1 0
github.com/muety/wakapi/config/config.go:268.77,269.29 1 0
github.com/muety/wakapi/config/config.go:274.2,274.19 1 0
github.com/muety/wakapi/config/config.go:269.29,270.18 1 0
github.com/muety/wakapi/config/config.go:270.18,272.4 1 0
github.com/muety/wakapi/config/config.go:277.26,279.2 1 0
github.com/muety/wakapi/config/config.go:281.20,283.2 1 0
github.com/muety/wakapi/config/config.go:285.35,290.96 3 0
github.com/muety/wakapi/config/config.go:294.2,303.52 6 0
github.com/muety/wakapi/config/config.go:307.2,307.47 1 0
github.com/muety/wakapi/config/config.go:313.2,313.70 1 0
github.com/muety/wakapi/config/config.go:317.2,317.28 1 0
github.com/muety/wakapi/config/config.go:321.2,321.29 1 0
github.com/muety/wakapi/config/config.go:326.2,326.94 1 0
github.com/muety/wakapi/config/config.go:330.2,331.14 2 0
github.com/muety/wakapi/config/config.go:290.96,292.3 1 0
github.com/muety/wakapi/config/config.go:303.52,305.3 1 0
github.com/muety/wakapi/config/config.go:307.47,308.14 1 0
github.com/muety/wakapi/config/config.go:308.14,310.4 1 0
github.com/muety/wakapi/config/config.go:313.70,315.3 1 0
github.com/muety/wakapi/config/config.go:317.28,319.3 1 0
github.com/muety/wakapi/config/config.go:321.29,324.3 2 0
github.com/muety/wakapi/config/config.go:326.94,328.3 1 0
github.com/muety/wakapi/middlewares/security.go:19.62,20.43 1 0
github.com/muety/wakapi/middlewares/security.go:20.43,22.3 1 0
github.com/muety/wakapi/middlewares/security.go:25.80,26.36 1 0
github.com/muety/wakapi/middlewares/security.go:31.2,31.27 1 0
github.com/muety/wakapi/middlewares/security.go:26.36,27.30 1 0
github.com/muety/wakapi/middlewares/security.go:27.30,29.4 1 0
github.com/muety/wakapi/middlewares/sentry.go:15.60,16.43 1 0
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/middlewares/authenticate.go:19.91,25.2 1 1
github.com/muety/wakapi/middlewares/authenticate.go:27.90,30.2 2 0
github.com/muety/wakapi/middlewares/authenticate.go:32.90,35.2 2 0
@ -344,98 +367,6 @@ github.com/muety/wakapi/middlewares/principal.go:54.52,56.3 1 0
github.com/muety/wakapi/middlewares/principal.go:59.49,60.52 1 0
github.com/muety/wakapi/middlewares/principal.go:63.2,63.12 1 0
github.com/muety/wakapi/middlewares/principal.go:60.52,62.3 1 0
github.com/muety/wakapi/middlewares/security.go:19.62,20.43 1 0
github.com/muety/wakapi/middlewares/security.go:20.43,22.3 1 0
github.com/muety/wakapi/middlewares/security.go:25.80,26.36 1 0
github.com/muety/wakapi/middlewares/security.go:31.2,31.27 1 0
github.com/muety/wakapi/middlewares/security.go:26.36,27.30 1 0
github.com/muety/wakapi/middlewares/security.go:27.30,29.4 1 0
github.com/muety/wakapi/middlewares/sentry.go:15.60,16.43 1 0
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/utils/common.go:18.73,19.58 1 0
github.com/muety/wakapi/utils/common.go:22.2,22.87 1 0
github.com/muety/wakapi/utils/common.go:25.2,25.64 1 0
github.com/muety/wakapi/utils/common.go:19.58,21.3 1 0
github.com/muety/wakapi/utils/common.go:22.87,24.3 1 0
github.com/muety/wakapi/utils/common.go:28.40,30.2 1 0
github.com/muety/wakapi/utils/common.go:32.44,34.2 1 0
github.com/muety/wakapi/utils/common.go:36.45,38.2 1 0
github.com/muety/wakapi/utils/common.go:40.24,42.2 1 0
github.com/muety/wakapi/utils/common.go:44.56,47.45 3 1
github.com/muety/wakapi/utils/common.go:50.2,50.40 1 1
github.com/muety/wakapi/utils/common.go:47.45,49.3 1 1
github.com/muety/wakapi/utils/strings.go:8.34,10.2 1 0
github.com/muety/wakapi/utils/strings.go:12.77,13.29 1 0
github.com/muety/wakapi/utils/strings.go:18.2,18.19 1 0
github.com/muety/wakapi/utils/strings.go:13.29,14.18 1 0
github.com/muety/wakapi/utils/strings.go:14.18,16.4 1 0
github.com/muety/wakapi/utils/auth.go:16.79,18.54 2 0
github.com/muety/wakapi/utils/auth.go:22.2,24.16 3 0
github.com/muety/wakapi/utils/auth.go:28.2,30.45 3 0
github.com/muety/wakapi/utils/auth.go:33.2,34.32 2 0
github.com/muety/wakapi/utils/auth.go:18.54,20.3 1 0
github.com/muety/wakapi/utils/auth.go:24.16,26.3 1 0
github.com/muety/wakapi/utils/auth.go:30.45,32.3 1 0
github.com/muety/wakapi/utils/auth.go:37.65,39.85 2 0
github.com/muety/wakapi/utils/auth.go:43.2,44.30 2 0
github.com/muety/wakapi/utils/auth.go:39.85,41.3 1 0
github.com/muety/wakapi/utils/auth.go:47.94,49.16 2 0
github.com/muety/wakapi/utils/auth.go:53.2,53.107 1 0
github.com/muety/wakapi/utils/auth.go:57.2,57.22 1 0
github.com/muety/wakapi/utils/auth.go:49.16,51.3 1 0
github.com/muety/wakapi/utils/auth.go:53.107,55.3 1 0
github.com/muety/wakapi/utils/auth.go:60.56,64.2 3 0
github.com/muety/wakapi/utils/auth.go:66.55,69.16 3 0
github.com/muety/wakapi/utils/auth.go:72.2,72.16 1 0
github.com/muety/wakapi/utils/auth.go:69.16,71.3 1 0
github.com/muety/wakapi/utils/color.go:8.90,10.32 2 0
github.com/muety/wakapi/utils/color.go:15.2,15.15 1 0
github.com/muety/wakapi/utils/color.go:10.32,11.50 1 0
github.com/muety/wakapi/utils/color.go:11.50,13.4 1 0
github.com/muety/wakapi/utils/date.go:8.43,10.2 1 1
github.com/muety/wakapi/utils/date.go:12.48,14.2 1 0
github.com/muety/wakapi/utils/date.go:16.41,18.21 2 1
github.com/muety/wakapi/utils/date.go:21.2,21.23 1 1
github.com/muety/wakapi/utils/date.go:18.21,20.3 1 0
github.com/muety/wakapi/utils/date.go:24.46,26.2 1 0
github.com/muety/wakapi/utils/date.go:28.51,30.2 1 0
github.com/muety/wakapi/utils/date.go:32.44,35.2 2 1
github.com/muety/wakapi/utils/date.go:37.52,39.2 1 0
github.com/muety/wakapi/utils/date.go:41.45,43.2 1 0
github.com/muety/wakapi/utils/date.go:45.51,47.2 1 0
github.com/muety/wakapi/utils/date.go:49.44,51.2 1 0
github.com/muety/wakapi/utils/date.go:54.42,56.2 1 1
github.com/muety/wakapi/utils/date.go:59.41,61.21 2 1
github.com/muety/wakapi/utils/date.go:64.2,64.36 1 1
github.com/muety/wakapi/utils/date.go:61.21,63.3 1 1
github.com/muety/wakapi/utils/date.go:68.63,70.2 1 0
github.com/muety/wakapi/utils/date.go:73.62,79.2 5 0
github.com/muety/wakapi/utils/date.go:82.67,85.33 2 1
github.com/muety/wakapi/utils/date.go:94.2,94.18 1 1
github.com/muety/wakapi/utils/date.go:85.33,87.19 2 1
github.com/muety/wakapi/utils/date.go:90.3,91.10 2 1
github.com/muety/wakapi/utils/date.go:87.19,89.4 1 1
github.com/muety/wakapi/utils/date.go:97.50,103.2 5 0
github.com/muety/wakapi/utils/date.go:106.79,109.36 3 1
github.com/muety/wakapi/utils/date.go:113.2,113.21 1 1
github.com/muety/wakapi/utils/date.go:117.2,117.21 1 1
github.com/muety/wakapi/utils/date.go:121.2,121.13 1 1
github.com/muety/wakapi/utils/date.go:109.36,112.3 2 0
github.com/muety/wakapi/utils/date.go:113.21,116.3 2 1
github.com/muety/wakapi/utils/date.go:117.21,120.3 2 1
github.com/muety/wakapi/utils/filesystem.go:14.68,16.16 2 0
github.com/muety/wakapi/utils/filesystem.go:20.2,21.15 2 0
github.com/muety/wakapi/utils/filesystem.go:33.2,33.15 1 0
github.com/muety/wakapi/utils/filesystem.go:16.16,18.3 1 0
github.com/muety/wakapi/utils/filesystem.go:21.15,23.47 2 0
github.com/muety/wakapi/utils/filesystem.go:23.47,25.23 2 0
github.com/muety/wakapi/utils/filesystem.go:29.4,29.19 1 0
github.com/muety/wakapi/utils/filesystem.go:25.23,27.5 1 0
github.com/muety/wakapi/utils/http.go:9.90,12.58 3 0
github.com/muety/wakapi/utils/http.go:12.58,14.3 1 0
github.com/muety/wakapi/utils/summary.go:10.66,11.40 1 0
github.com/muety/wakapi/utils/summary.go:16.2,16.48 1 0
github.com/muety/wakapi/utils/summary.go:11.40,12.27 1 0
@ -478,161 +409,101 @@ 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/services/aggregation.go:29.142,37.2 1 0
github.com/muety/wakapi/services/aggregation.go:46.43,48.37 1 0
github.com/muety/wakapi/services/aggregation.go:52.2,54.19 3 0
github.com/muety/wakapi/services/aggregation.go:48.37,50.3 1 0
github.com/muety/wakapi/services/aggregation.go:57.67,58.47 1 0
github.com/muety/wakapi/services/aggregation.go:61.2,66.40 4 0
github.com/muety/wakapi/services/aggregation.go:70.2,70.50 1 0
github.com/muety/wakapi/services/aggregation.go:75.2,75.60 1 0
github.com/muety/wakapi/services/aggregation.go:81.2,81.35 1 0
github.com/muety/wakapi/services/aggregation.go:58.47,60.3 1 0
github.com/muety/wakapi/services/aggregation.go:66.40,68.3 1 0
github.com/muety/wakapi/services/aggregation.go:70.50,72.3 1 0
github.com/muety/wakapi/services/aggregation.go:75.60,79.3 3 0
github.com/muety/wakapi/services/aggregation.go:84.109,85.24 1 0
github.com/muety/wakapi/services/aggregation.go:85.24,86.111 1 0
github.com/muety/wakapi/services/aggregation.go:86.111,88.4 1 0
github.com/muety/wakapi/services/aggregation.go:88.9,91.4 2 0
github.com/muety/wakapi/services/aggregation.go:95.80,96.33 1 0
github.com/muety/wakapi/services/aggregation.go:96.33,97.60 1 0
github.com/muety/wakapi/services/aggregation.go:97.60,99.4 1 0
github.com/muety/wakapi/services/aggregation.go:103.100,107.59 3 0
github.com/muety/wakapi/services/aggregation.go:122.2,123.16 2 0
github.com/muety/wakapi/services/aggregation.go:129.2,130.16 2 0
github.com/muety/wakapi/services/aggregation.go:136.2,137.44 2 0
github.com/muety/wakapi/services/aggregation.go:142.2,142.41 1 0
github.com/muety/wakapi/services/aggregation.go:156.2,156.12 1 0
github.com/muety/wakapi/services/aggregation.go:107.59,110.3 2 0
github.com/muety/wakapi/services/aggregation.go:110.8,110.47 1 0
github.com/muety/wakapi/services/aggregation.go:110.47,112.30 2 0
github.com/muety/wakapi/services/aggregation.go:112.30,113.43 1 0
github.com/muety/wakapi/services/aggregation.go:113.43,115.5 1 0
github.com/muety/wakapi/services/aggregation.go:117.8,119.3 1 0
github.com/muety/wakapi/services/aggregation.go:123.16,126.3 2 0
github.com/muety/wakapi/services/aggregation.go:130.16,133.3 2 0
github.com/muety/wakapi/services/aggregation.go:137.44,139.3 1 0
github.com/muety/wakapi/services/aggregation.go:142.41,143.21 1 0
github.com/muety/wakapi/services/aggregation.go:143.21,147.4 1 0
github.com/muety/wakapi/services/aggregation.go:147.9,147.62 1 0
github.com/muety/wakapi/services/aggregation.go:147.62,151.4 1 0
github.com/muety/wakapi/services/aggregation.go:159.73,162.27 3 0
github.com/muety/wakapi/services/aggregation.go:167.2,167.27 1 0
github.com/muety/wakapi/services/aggregation.go:170.2,170.12 1 0
github.com/muety/wakapi/services/aggregation.go:162.27,163.39 1 0
github.com/muety/wakapi/services/aggregation.go:163.39,165.4 1 0
github.com/muety/wakapi/services/aggregation.go:167.27,169.3 1 0
github.com/muety/wakapi/services/aggregation.go:173.69,176.27 3 0
github.com/muety/wakapi/services/aggregation.go:176.27,178.3 1 0
github.com/muety/wakapi/services/aggregation.go:181.83,196.41 5 0
github.com/muety/wakapi/services/aggregation.go:196.41,206.3 3 0
github.com/muety/wakapi/services/aggregation.go:209.34,212.2 2 0
github.com/muety/wakapi/services/heartbeat.go:17.141,23.2 1 0
github.com/muety/wakapi/services/heartbeat.go:25.72,27.2 1 0
github.com/muety/wakapi/services/heartbeat.go:29.80,34.32 3 0
github.com/muety/wakapi/services/heartbeat.go:41.2,41.55 1 0
github.com/muety/wakapi/services/heartbeat.go:34.32,35.36 1 0
github.com/muety/wakapi/services/heartbeat.go:35.36,38.4 2 0
github.com/muety/wakapi/services/heartbeat.go:44.53,46.2 1 0
github.com/muety/wakapi/services/heartbeat.go:48.76,50.2 1 0
github.com/muety/wakapi/services/heartbeat.go:52.96,54.2 1 0
github.com/muety/wakapi/services/heartbeat.go:56.111,58.16 2 0
github.com/muety/wakapi/services/heartbeat.go:61.2,61.43 1 0
github.com/muety/wakapi/services/heartbeat.go:58.16,60.3 1 0
github.com/muety/wakapi/services/heartbeat.go:64.92,66.2 1 0
github.com/muety/wakapi/services/heartbeat.go:68.116,70.2 1 0
github.com/muety/wakapi/services/heartbeat.go:72.78,74.2 1 0
github.com/muety/wakapi/services/heartbeat.go:76.62,78.2 1 0
github.com/muety/wakapi/services/heartbeat.go:80.116,82.16 2 0
github.com/muety/wakapi/services/heartbeat.go:86.2,86.28 1 0
github.com/muety/wakapi/services/heartbeat.go:90.2,90.24 1 0
github.com/muety/wakapi/services/heartbeat.go:82.16,84.3 1 0
github.com/muety/wakapi/services/heartbeat.go:86.28,88.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.78,27.16 2 0
github.com/muety/wakapi/services/key_value.go:33.2,33.11 1 0
github.com/muety/wakapi/services/key_value.go:27.16,32.3 1 0
github.com/muety/wakapi/services/key_value.go:36.72,38.2 1 0
github.com/muety/wakapi/services/key_value.go:40.60,42.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/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.151 1 0
github.com/muety/wakapi/services/misc.go:91.3,91.48 1 0
github.com/muety/wakapi/services/misc.go:82.151,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/utils/auth.go:16.79,18.54 2 0
github.com/muety/wakapi/utils/auth.go:22.2,24.16 3 0
github.com/muety/wakapi/utils/auth.go:28.2,30.45 3 0
github.com/muety/wakapi/utils/auth.go:33.2,34.32 2 0
github.com/muety/wakapi/utils/auth.go:18.54,20.3 1 0
github.com/muety/wakapi/utils/auth.go:24.16,26.3 1 0
github.com/muety/wakapi/utils/auth.go:30.45,32.3 1 0
github.com/muety/wakapi/utils/auth.go:37.65,39.85 2 0
github.com/muety/wakapi/utils/auth.go:43.2,44.30 2 0
github.com/muety/wakapi/utils/auth.go:39.85,41.3 1 0
github.com/muety/wakapi/utils/auth.go:47.94,49.16 2 0
github.com/muety/wakapi/utils/auth.go:53.2,53.107 1 0
github.com/muety/wakapi/utils/auth.go:57.2,57.22 1 0
github.com/muety/wakapi/utils/auth.go:49.16,51.3 1 0
github.com/muety/wakapi/utils/auth.go:53.107,55.3 1 0
github.com/muety/wakapi/utils/auth.go:60.56,64.2 3 0
github.com/muety/wakapi/utils/auth.go:66.55,69.16 3 0
github.com/muety/wakapi/utils/auth.go:72.2,72.16 1 0
github.com/muety/wakapi/utils/auth.go:69.16,71.3 1 0
github.com/muety/wakapi/utils/color.go:8.90,10.32 2 0
github.com/muety/wakapi/utils/color.go:15.2,15.15 1 0
github.com/muety/wakapi/utils/color.go:10.32,11.50 1 0
github.com/muety/wakapi/utils/color.go:11.50,13.4 1 0
github.com/muety/wakapi/utils/common.go:18.73,19.58 1 0
github.com/muety/wakapi/utils/common.go:22.2,22.87 1 0
github.com/muety/wakapi/utils/common.go:25.2,25.64 1 0
github.com/muety/wakapi/utils/common.go:19.58,21.3 1 0
github.com/muety/wakapi/utils/common.go:22.87,24.3 1 0
github.com/muety/wakapi/utils/common.go:28.40,30.2 1 0
github.com/muety/wakapi/utils/common.go:32.44,34.2 1 0
github.com/muety/wakapi/utils/common.go:36.45,38.2 1 0
github.com/muety/wakapi/utils/common.go:40.24,42.2 1 0
github.com/muety/wakapi/utils/common.go:44.56,47.45 3 1
github.com/muety/wakapi/utils/common.go:50.2,50.40 1 1
github.com/muety/wakapi/utils/common.go:47.45,49.3 1 1
github.com/muety/wakapi/utils/date.go:8.43,10.2 1 1
github.com/muety/wakapi/utils/date.go:12.48,14.2 1 0
github.com/muety/wakapi/utils/date.go:16.41,18.21 2 1
github.com/muety/wakapi/utils/date.go:21.2,21.23 1 1
github.com/muety/wakapi/utils/date.go:18.21,20.3 1 0
github.com/muety/wakapi/utils/date.go:24.46,26.2 1 0
github.com/muety/wakapi/utils/date.go:28.51,30.2 1 0
github.com/muety/wakapi/utils/date.go:32.44,35.2 2 1
github.com/muety/wakapi/utils/date.go:37.52,39.2 1 0
github.com/muety/wakapi/utils/date.go:41.45,43.2 1 0
github.com/muety/wakapi/utils/date.go:45.51,47.2 1 0
github.com/muety/wakapi/utils/date.go:49.44,51.2 1 0
github.com/muety/wakapi/utils/date.go:54.42,56.2 1 1
github.com/muety/wakapi/utils/date.go:59.41,61.21 2 1
github.com/muety/wakapi/utils/date.go:64.2,64.36 1 1
github.com/muety/wakapi/utils/date.go:61.21,63.3 1 1
github.com/muety/wakapi/utils/date.go:68.63,70.2 1 0
github.com/muety/wakapi/utils/date.go:73.62,79.2 5 0
github.com/muety/wakapi/utils/date.go:82.67,85.33 2 1
github.com/muety/wakapi/utils/date.go:94.2,94.18 1 1
github.com/muety/wakapi/utils/date.go:85.33,87.19 2 1
github.com/muety/wakapi/utils/date.go:90.3,91.10 2 1
github.com/muety/wakapi/utils/date.go:87.19,89.4 1 1
github.com/muety/wakapi/utils/date.go:97.50,103.2 5 0
github.com/muety/wakapi/utils/date.go:106.79,109.36 3 1
github.com/muety/wakapi/utils/date.go:113.2,113.21 1 1
github.com/muety/wakapi/utils/date.go:117.2,117.21 1 1
github.com/muety/wakapi/utils/date.go:121.2,121.13 1 1
github.com/muety/wakapi/utils/date.go:109.36,112.3 2 0
github.com/muety/wakapi/utils/date.go:113.21,116.3 2 1
github.com/muety/wakapi/utils/date.go:117.21,120.3 2 1
github.com/muety/wakapi/utils/filesystem.go:14.68,16.16 2 0
github.com/muety/wakapi/utils/filesystem.go:20.2,21.15 2 0
github.com/muety/wakapi/utils/filesystem.go:33.2,33.15 1 0
github.com/muety/wakapi/utils/filesystem.go:16.16,18.3 1 0
github.com/muety/wakapi/utils/filesystem.go:21.15,23.47 2 0
github.com/muety/wakapi/utils/filesystem.go:23.47,25.23 2 0
github.com/muety/wakapi/utils/filesystem.go:29.4,29.19 1 0
github.com/muety/wakapi/utils/filesystem.go:25.23,27.5 1 0
github.com/muety/wakapi/utils/http.go:9.90,12.58 3 0
github.com/muety/wakapi/utils/http.go:12.58,14.3 1 0
github.com/muety/wakapi/utils/strings.go:8.34,10.2 1 0
github.com/muety/wakapi/utils/strings.go:12.77,13.29 1 0
github.com/muety/wakapi/utils/strings.go:18.2,18.19 1 0
github.com/muety/wakapi/utils/strings.go:13.29,14.18 1 0
github.com/muety/wakapi/utils/strings.go:14.18,16.4 1 0
github.com/muety/wakapi/services/report.go:22.122,30.2 1 0
github.com/muety/wakapi/services/report.go:32.38,36.16 3 0
github.com/muety/wakapi/services/report.go:40.2,41.26 2 0
github.com/muety/wakapi/services/report.go:36.16,38.3 1 0
github.com/muety/wakapi/services/report.go:41.26,43.3 1 0
github.com/muety/wakapi/services/report.go:46.62,51.65 3 0
github.com/muety/wakapi/services/report.go:59.2,59.65 1 0
github.com/muety/wakapi/services/report.go:51.65,56.3 4 0
github.com/muety/wakapi/services/report.go:59.65,69.3 4 0
github.com/muety/wakapi/services/report.go:72.80,77.16 4 0
github.com/muety/wakapi/services/report.go:82.2,89.65 2 0
github.com/muety/wakapi/services/report.go:94.2,95.12 2 0
github.com/muety/wakapi/services/report.go:77.16,80.3 2 0
github.com/muety/wakapi/services/report.go:89.65,92.3 2 0
github.com/muety/wakapi/services/summary.go:28.149,36.2 1 1
github.com/muety/wakapi/services/summary.go:40.136,43.66 2 1
github.com/muety/wakapi/services/summary.go:48.2,48.44 1 1
@ -740,19 +611,175 @@ github.com/muety/wakapi/services/user.go:47.16,49.3 1 0
github.com/muety/wakapi/services/user.go:55.76,57.2 1 0
github.com/muety/wakapi/services/user.go:59.86,61.2 1 0
github.com/muety/wakapi/services/user.go:63.58,65.2 1 0
github.com/muety/wakapi/services/user.go:67.61,70.2 2 0
github.com/muety/wakapi/services/user.go:72.48,74.2 1 0
github.com/muety/wakapi/services/user.go:76.102,86.93 2 0
github.com/muety/wakapi/services/user.go:92.2,92.38 1 0
github.com/muety/wakapi/services/user.go:86.93,88.3 1 0
github.com/muety/wakapi/services/user.go:88.8,90.3 1 0
github.com/muety/wakapi/services/user.go:95.73,98.2 2 0
github.com/muety/wakapi/services/user.go:100.78,104.2 3 0
github.com/muety/wakapi/services/user.go:106.99,109.2 2 0
github.com/muety/wakapi/services/user.go:111.106,114.96 3 0
github.com/muety/wakapi/services/user.go:119.2,119.68 1 0
github.com/muety/wakapi/services/user.go:114.96,116.3 1 0
github.com/muety/wakapi/services/user.go:116.8,118.3 1 0
github.com/muety/wakapi/services/user.go:122.85,124.2 1 0
github.com/muety/wakapi/services/user.go:126.57,129.2 2 0
github.com/muety/wakapi/services/user.go:131.38,133.2 1 0
github.com/muety/wakapi/services/user.go:67.86,69.2 1 0
github.com/muety/wakapi/services/user.go:71.61,74.2 2 0
github.com/muety/wakapi/services/user.go:76.48,78.2 1 0
github.com/muety/wakapi/services/user.go:80.102,90.93 2 0
github.com/muety/wakapi/services/user.go:96.2,96.38 1 0
github.com/muety/wakapi/services/user.go:90.93,92.3 1 0
github.com/muety/wakapi/services/user.go:92.8,94.3 1 0
github.com/muety/wakapi/services/user.go:99.73,102.2 2 0
github.com/muety/wakapi/services/user.go:104.78,108.2 3 0
github.com/muety/wakapi/services/user.go:110.99,113.2 2 0
github.com/muety/wakapi/services/user.go:115.106,118.96 3 0
github.com/muety/wakapi/services/user.go:123.2,123.68 1 0
github.com/muety/wakapi/services/user.go:118.96,120.3 1 0
github.com/muety/wakapi/services/user.go:120.8,122.3 1 0
github.com/muety/wakapi/services/user.go:126.85,128.2 1 0
github.com/muety/wakapi/services/user.go:130.57,133.2 2 0
github.com/muety/wakapi/services/user.go:135.38,137.2 1 0
github.com/muety/wakapi/services/aggregation.go:29.142,37.2 1 0
github.com/muety/wakapi/services/aggregation.go:46.43,48.37 1 0
github.com/muety/wakapi/services/aggregation.go:52.2,54.19 3 0
github.com/muety/wakapi/services/aggregation.go:48.37,50.3 1 0
github.com/muety/wakapi/services/aggregation.go:57.67,58.47 1 0
github.com/muety/wakapi/services/aggregation.go:61.2,66.40 4 0
github.com/muety/wakapi/services/aggregation.go:70.2,70.50 1 0
github.com/muety/wakapi/services/aggregation.go:75.2,75.60 1 0
github.com/muety/wakapi/services/aggregation.go:81.2,81.35 1 0
github.com/muety/wakapi/services/aggregation.go:58.47,60.3 1 0
github.com/muety/wakapi/services/aggregation.go:66.40,68.3 1 0
github.com/muety/wakapi/services/aggregation.go:70.50,72.3 1 0
github.com/muety/wakapi/services/aggregation.go:75.60,79.3 3 0
github.com/muety/wakapi/services/aggregation.go:84.109,85.24 1 0
github.com/muety/wakapi/services/aggregation.go:85.24,86.111 1 0
github.com/muety/wakapi/services/aggregation.go:86.111,88.4 1 0
github.com/muety/wakapi/services/aggregation.go:88.9,91.4 2 0
github.com/muety/wakapi/services/aggregation.go:95.80,96.33 1 0
github.com/muety/wakapi/services/aggregation.go:96.33,97.60 1 0
github.com/muety/wakapi/services/aggregation.go:97.60,99.4 1 0
github.com/muety/wakapi/services/aggregation.go:103.100,107.59 3 0
github.com/muety/wakapi/services/aggregation.go:122.2,123.16 2 0
github.com/muety/wakapi/services/aggregation.go:129.2,130.16 2 0
github.com/muety/wakapi/services/aggregation.go:136.2,137.44 2 0
github.com/muety/wakapi/services/aggregation.go:142.2,142.41 1 0
github.com/muety/wakapi/services/aggregation.go:156.2,156.12 1 0
github.com/muety/wakapi/services/aggregation.go:107.59,110.3 2 0
github.com/muety/wakapi/services/aggregation.go:110.8,110.47 1 0
github.com/muety/wakapi/services/aggregation.go:110.47,112.30 2 0
github.com/muety/wakapi/services/aggregation.go:112.30,113.43 1 0
github.com/muety/wakapi/services/aggregation.go:113.43,115.5 1 0
github.com/muety/wakapi/services/aggregation.go:117.8,119.3 1 0
github.com/muety/wakapi/services/aggregation.go:123.16,126.3 2 0
github.com/muety/wakapi/services/aggregation.go:130.16,133.3 2 0
github.com/muety/wakapi/services/aggregation.go:137.44,139.3 1 0
github.com/muety/wakapi/services/aggregation.go:142.41,143.21 1 0
github.com/muety/wakapi/services/aggregation.go:143.21,147.4 1 0
github.com/muety/wakapi/services/aggregation.go:147.9,147.62 1 0
github.com/muety/wakapi/services/aggregation.go:147.62,151.4 1 0
github.com/muety/wakapi/services/aggregation.go:159.73,162.27 3 0
github.com/muety/wakapi/services/aggregation.go:167.2,167.27 1 0
github.com/muety/wakapi/services/aggregation.go:170.2,170.12 1 0
github.com/muety/wakapi/services/aggregation.go:162.27,163.39 1 0
github.com/muety/wakapi/services/aggregation.go:163.39,165.4 1 0
github.com/muety/wakapi/services/aggregation.go:167.27,169.3 1 0
github.com/muety/wakapi/services/aggregation.go:173.69,176.27 3 0
github.com/muety/wakapi/services/aggregation.go:176.27,178.3 1 0
github.com/muety/wakapi/services/aggregation.go:181.83,196.41 5 0
github.com/muety/wakapi/services/aggregation.go:196.41,206.3 3 0
github.com/muety/wakapi/services/aggregation.go:209.34,212.2 2 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.78,27.16 2 0
github.com/muety/wakapi/services/key_value.go:33.2,33.11 1 0
github.com/muety/wakapi/services/key_value.go:27.16,32.3 1 0
github.com/muety/wakapi/services/key_value.go:36.72,38.2 1 0
github.com/muety/wakapi/services/key_value.go:40.60,42.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.151 1 0
github.com/muety/wakapi/services/misc.go:91.3,91.48 1 0
github.com/muety/wakapi/services/misc.go:82.151,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/heartbeat.go:17.141,23.2 1 0
github.com/muety/wakapi/services/heartbeat.go:25.72,27.2 1 0
github.com/muety/wakapi/services/heartbeat.go:29.80,34.32 3 0
github.com/muety/wakapi/services/heartbeat.go:41.2,41.55 1 0
github.com/muety/wakapi/services/heartbeat.go:34.32,35.36 1 0
github.com/muety/wakapi/services/heartbeat.go:35.36,38.4 2 0
github.com/muety/wakapi/services/heartbeat.go:44.53,46.2 1 0
github.com/muety/wakapi/services/heartbeat.go:48.76,50.2 1 0
github.com/muety/wakapi/services/heartbeat.go:52.96,54.2 1 0
github.com/muety/wakapi/services/heartbeat.go:56.111,58.16 2 0
github.com/muety/wakapi/services/heartbeat.go:61.2,61.43 1 0
github.com/muety/wakapi/services/heartbeat.go:58.16,60.3 1 0
github.com/muety/wakapi/services/heartbeat.go:64.92,66.2 1 0
github.com/muety/wakapi/services/heartbeat.go:68.116,70.2 1 0
github.com/muety/wakapi/services/heartbeat.go:72.78,74.2 1 0
github.com/muety/wakapi/services/heartbeat.go:76.62,78.2 1 0
github.com/muety/wakapi/services/heartbeat.go:80.116,82.16 2 0
github.com/muety/wakapi/services/heartbeat.go:86.2,86.28 1 0
github.com/muety/wakapi/services/heartbeat.go:90.2,90.24 1 0
github.com/muety/wakapi/services/heartbeat.go:82.16,84.3 1 0
github.com/muety/wakapi/services/heartbeat.go:86.28,88.3 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

View File

@ -62,6 +62,7 @@ var (
aggregationService services.IAggregationService
mailService services.IMailService
keyValueService services.IKeyValueService
reportService services.IReportService
miscService services.IMiscService
)
@ -146,11 +147,13 @@ func main() {
aggregationService = services.NewAggregationService(userService, summaryService, heartbeatService)
mailService = mail.NewMailService()
keyValueService = services.NewKeyValueService(keyValueRepository)
reportService = services.NewReportService(summaryService, userService, mailService)
miscService = services.NewMiscService(userService, summaryService, keyValueService)
// Schedule background tasks
go aggregationService.Schedule()
go miscService.ScheduleCountTotalTime()
go reportService.Schedule()
routes.Init()

View File

@ -34,6 +34,11 @@ func (m *UserServiceMock) GetAll() ([]*models.User, error) {
return args.Get(0).([]*models.User), args.Error(1)
}
func (m *UserServiceMock) GetAllByReports(b bool) ([]*models.User, error) {
args := m.Called(b)
return args.Get(0).([]*models.User), args.Error(1)
}
func (m *UserServiceMock) GetActive() ([]*models.User, error) {
args := m.Called()
return args.Get(0).([]*models.User), args.Error(1)

View File

@ -152,9 +152,7 @@ func newDataFrom(s *models.Summary) *SummariesData {
}
func convertEntry(e *models.SummaryItem, entityTotal time.Duration) *SummariesEntry {
// this is a workaround, since currently, the total time of a summary item is mistakenly represented in seconds
// TODO: fix some day, while migrating persisted summary items
total := e.Total * time.Second
total := e.TotalFixed()
hrs := int(total.Hours())
mins := int((total - time.Duration(hrs)*time.Hour).Minutes())
secs := int((total - time.Duration(hrs)*time.Hour - time.Duration(mins)*time.Minute).Seconds())

10
models/report.go Normal file
View File

@ -0,0 +1,10 @@
package models
import "time"
type Report struct {
From time.Time
To time.Time
User *User
Summary *Summary
}

View File

@ -235,6 +235,12 @@ func (s *Summary) WithResolvedAliases(resolve AliasResolver) *Summary {
return s
}
func (s *SummaryItem) TotalFixed() time.Duration {
// this is a workaround, since currently, the total time of a summary item is mistakenly represented in seconds
// TODO: fix some day, while migrating persisted summary items
return s.Total * time.Second
}
func (s SummaryItems) Len() int {
return len(s)
}

View File

@ -27,6 +27,7 @@ type User struct {
HasData bool `json:"-" gorm:"default:false; type:bool"`
WakatimeApiKey string `json:"-"`
ResetToken string `json:"-"`
ReportsWeekly bool `json:"-" gorm:"default:false; type:bool"`
}
type Login struct {

View File

@ -60,6 +60,7 @@ type IUserRepository interface {
GetByEmail(string) (*models.User, error)
GetByResetToken(string) (*models.User, error)
GetAll() ([]*models.User, error)
GetAllByReports(bool) ([]*models.User, error)
GetByLoggedInAfter(time.Time) ([]*models.User, error)
GetByLastActiveAfter(time.Time) ([]*models.User, error)
Count() (int64, error)

View File

@ -74,6 +74,14 @@ func (r *UserRepository) GetAll() ([]*models.User, error) {
return users, nil
}
func (r *UserRepository) GetAllByReports(reportsEnabled bool) ([]*models.User, error) {
var users []*models.User
if err := r.db.Where(&models.User{ReportsWeekly: reportsEnabled}).Find(&users).Error; err != nil {
return nil, err
}
return users, nil
}
func (r *UserRepository) GetByLoggedInAfter(t time.Time) ([]*models.User, error) {
var users []*models.User
if err := r.db.
@ -143,6 +151,7 @@ func (r *UserRepository) Update(user *models.User) (*models.User, error) {
"has_data": user.HasData,
"reset_token": user.ResetToken,
"location": user.Location,
"reports_weekly": user.ReportsWeekly,
}
result := r.db.Model(user).Updates(updateMap)

View File

@ -23,12 +23,13 @@ type action func(w http.ResponseWriter, r *http.Request) (int, string, string)
var templates map[string]*template.Template
func loadTemplates() {
tpls := template.New("").Funcs(template.FuncMap{
func DefaultTemplateFuncs() template.FuncMap {
return template.FuncMap{
"json": utils.Json,
"date": utils.FormatDateHuman,
"simpledate": utils.FormatDate,
"simpledatetime": utils.FormatDateTime,
"duration": utils.FmtWakatimeDuration,
"floordate": utils.FloorDate,
"ceildate": utils.CeilDate,
"title": strings.Title,
@ -53,7 +54,11 @@ func loadTemplates() {
"htmlSafe": func(html string) template.HTML {
return template.HTML(html)
},
})
}
}
func loadTemplates() {
tpls := template.New("").Funcs(DefaultTemplateFuncs())
templates = make(map[string]*template.Template)
// Use local file system when in 'dev' environment, go embed file system otherwise

View File

@ -16,7 +16,7 @@ const (
aggregateIntervalDays int = 1
)
var lock = sync.Mutex{}
var aggregationLock = sync.Mutex{}
type AggregationService struct {
config *config.Config
@ -157,8 +157,8 @@ func (srv *AggregationService) trigger(jobs chan<- *AggregationJob, userIds map[
}
func (srv *AggregationService) lockUsers(userIds map[string]bool) error {
lock.Lock()
defer lock.Unlock()
aggregationLock.Lock()
defer aggregationLock.Unlock()
for uid := range userIds {
if _, ok := srv.inProgress[uid]; ok {
return errors.New("aggregation already in progress for at least of the request users")
@ -171,8 +171,8 @@ func (srv *AggregationService) lockUsers(userIds map[string]bool) error {
}
func (srv *AggregationService) unlockUsers(userIds map[string]bool) {
lock.Lock()
defer lock.Unlock()
aggregationLock.Lock()
defer aggregationLock.Unlock()
for uid := range userIds {
delete(srv.inProgress, uid)
}

View File

@ -3,8 +3,10 @@ package mail
import (
"bytes"
"fmt"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/routes"
"html/template"
"io/ioutil"
"text/template"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/services"
@ -14,8 +16,10 @@ import (
const (
tplNamePasswordReset = "reset_password"
tplNameImportNotification = "import_finished"
tplNameReport = "report"
subjectPasswordReset = "Wakapi Password Reset"
subjectImportNotification = "Wakapi Data Import Finished"
subjectReport = "Wakapi Your Latest Report"
)
type PasswordResetTplData struct {
@ -28,6 +32,10 @@ type ImportNotificationTplData struct {
NumHeartbeats int
}
type ReportTplData struct {
Report *models.Report
}
// Factory
func NewMailService() services.IMailService {
config := conf.Get()
@ -65,6 +73,18 @@ func getImportNotificationTemplate(data ImportNotificationTplData) (*bytes.Buffe
return &rendered, nil
}
func getReportTemplate(data ReportTplData) (*bytes.Buffer, error) {
tpl, err := loadTemplate(tplNameReport)
if err != nil {
return nil, err
}
var rendered bytes.Buffer
if err := tpl.Execute(&rendered, data); err != nil {
return nil, err
}
return &rendered, nil
}
func loadTemplate(tplName string) (*template.Template, error) {
tplFile, err := views.TemplateFiles.Open(fmt.Sprintf("mail/%s.tpl.html", tplName))
if err != nil {
@ -77,5 +97,8 @@ func loadTemplate(tplName string) (*template.Template, error) {
return nil, err
}
return template.New(tplName).Parse(string(tplData))
return template.
New(tplName).
Funcs(routes.DefaultTemplateFuncs()).
Parse(string(tplData))
}

View File

@ -56,6 +56,14 @@ func (s *MailWhaleMailService) SendImportNotification(recipient *models.User, du
return s.send(recipient.Email, subjectImportNotification, template.String(), true)
}
func (s *MailWhaleMailService) SendReport(recipient *models.User, report *models.Report) error {
template, err := getReportTemplate(ReportTplData{report})
if err != nil {
return err
}
return s.send(recipient.Email, subjectReport, template.String(), true)
}
func (s *MailWhaleMailService) send(to, subject, body string, isHtml bool) error {
if to == "" {
return errors.New("not sending mail as recipient mail address seems to be invalid")

View File

@ -8,12 +8,19 @@ import (
type NoopMailService struct{}
const notImplemented = "noop mail service doing nothing instead of sending password reset mail to %s"
func (n *NoopMailService) SendReport(recipient *models.User, report *models.Report) error {
logbuch.Info(notImplemented, recipient.ID)
return nil
}
func (n *NoopMailService) SendPasswordReset(recipient *models.User, resetLink string) error {
logbuch.Info("noop mail service doing nothing instead of sending password reset mail to %s", recipient.ID)
logbuch.Info(notImplemented, recipient.ID)
return nil
}
func (n *NoopMailService) SendImportNotification(recipient *models.User, duration time.Duration, numHeartbeats int) error {
logbuch.Info("noop mail service doing nothing instead of sending import notification mail to %s", recipient.ID)
logbuch.Info(notImplemented, recipient.ID)
return nil
}

View File

@ -17,6 +17,10 @@ type SMTPMailService struct {
auth sasl.Client
}
func (s *SMTPMailService) SendReport(recipient *models.User, report *models.Report) error {
panic("implement me") // TODO
}
func NewSMTPMailService(config conf.SMTPMailConfig, publicUrl string) *SMTPMailService {
return &SMTPMailService{
publicUrl: publicUrl,

96
services/report.go Normal file
View File

@ -0,0 +1,96 @@
package services
import (
"github.com/emvi/logbuch"
"github.com/go-co-op/gocron"
"github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"sync"
"time"
)
var reportLock = sync.Mutex{}
type ReportService struct {
config *config.Config
summaryService ISummaryService
userService IUserService
mailService IMailService
schedulersWeekly map[string]*gocron.Scheduler // user id -> scheduler
}
func NewReportService(summaryService ISummaryService, userService IUserService, mailService IMailService) *ReportService {
return &ReportService{
config: config.Get(),
summaryService: summaryService,
userService: userService,
mailService: mailService,
schedulersWeekly: map[string]*gocron.Scheduler{},
}
}
func (srv *ReportService) Schedule() {
logbuch.Info("initializing report service")
users, err := srv.userService.GetAllByReports(true)
if err != nil {
config.Log().Fatal("%v", err)
}
logbuch.Info("scheduling reports for %d users", len(users))
for _, u := range users {
srv.UpdateUserSchedule(u)
}
}
func (srv *ReportService) UpdateUserSchedule(u *models.User) {
reportLock.Lock()
defer reportLock.Unlock()
// unschedule
if s, ok := srv.schedulersWeekly[u.ID]; ok && !u.ReportsWeekly {
s.Stop()
s.Clear()
delete(srv.schedulersWeekly, u.ID)
return
}
// schedule
if _, ok := srv.schedulersWeekly[u.ID]; !ok && u.ReportsWeekly {
s := gocron.NewScheduler(u.TZ())
s.
Every(1).
Week().
Weekday(srv.config.App.GetWeeklyReportDay()).
At(srv.config.App.GetWeeklyReportTime()).
Do(srv.Run, u, 7*24*time.Hour)
s.StartAsync()
srv.schedulersWeekly[u.ID] = s
}
}
func (srv *ReportService) Run(user *models.User, duration time.Duration) error {
end := time.Now().In(user.TZ())
start := time.Now().Add(-1 * duration)
summary, err := srv.summaryService.Aliased(start, end, user, srv.summaryService.Retrieve, false)
if err != nil {
config.Log().Error("failed to generate report for '%s' %v", user.ID, err)
return err
}
report := &models.Report{
From: start,
To: end,
User: user,
Summary: summary,
}
if err := srv.mailService.SendReport(user, report); err != nil {
config.Log().Error("failed to send report for '%s' %v", user.ID, err)
return err
}
logbuch.Info("sent report to user '%s'", user.ID)
return nil
}

View File

@ -53,6 +53,12 @@ type ILanguageMappingService interface {
Delete(mapping *models.LanguageMapping) error
}
type IMailService interface {
SendPasswordReset(*models.User, string) error
SendImportNotification(*models.User, time.Duration, int) error
SendReport(*models.User, *models.Report) error
}
type ISummaryService interface {
Aliased(time.Time, time.Time, *models.User, SummaryRetriever, bool) (*models.Summary, error)
Retrieve(time.Time, time.Time, *models.User) (*models.Summary, error)
@ -62,12 +68,19 @@ type ISummaryService interface {
Insert(*models.Summary) error
}
type IReportService interface {
Schedule()
UpdateUserSchedule(user *models.User)
Run(*models.User, time.Duration) error
}
type IUserService interface {
GetUserById(string) (*models.User, error)
GetUserByKey(string) (*models.User, error)
GetUserByEmail(string) (*models.User, error)
GetUserByResetToken(string) (*models.User, error)
GetAll() ([]*models.User, error)
GetAllByReports(bool) ([]*models.User, error)
GetActive() ([]*models.User, error)
Count() (int64, error)
CreateOrGet(*models.Signup, bool) (*models.User, bool, error)
@ -79,8 +92,3 @@ type IUserService interface {
GenerateResetToken(*models.User) (*models.User, error)
FlushCache()
}
type IMailService interface {
SendPasswordReset(*models.User, string) error
SendImportNotification(*models.User, time.Duration, int) error
}

View File

@ -64,6 +64,10 @@ func (srv *UserService) GetAll() ([]*models.User, error) {
return srv.repository.GetAll()
}
func (srv *UserService) GetAllByReports(reportsEnabled bool) ([]*models.User, error) {
return srv.repository.GetAllByReports(reportsEnabled)
}
func (srv *UserService) GetActive() ([]*models.User, error) {
minDate := time.Now().Add(-24 * time.Hour * time.Duration(srv.Config.App.InactiveDays))
return srv.repository.GetByLastActiveAfter(minDate)

View File

@ -93,12 +93,18 @@
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<!-- START CENTERED WHITE CONTAINER -->
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
@ -126,11 +132,8 @@
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- START FOOTER -->
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
@ -140,9 +143,6 @@
</tr>
</table>
</div>
<!-- END FOOTER -->
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>

198
views/mail/report.tpl.html Normal file
View File

@ -0,0 +1,198 @@
<!doctype html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Wakapi Report</title>
<style>
@media only screen and (max-width: 620px) {
table[class=body] h1 {
font-size: 28px !important;
margin-bottom: 10px !important;
}
table[class=body] p,
table[class=body] ul,
table[class=body] ol,
table[class=body] td,
table[class=body] span,
table[class=body] a {
font-size: 16px !important;
}
table[class=body] .wrapper,
table[class=body] .article {
padding: 10px !important;
}
table[class=body] .content {
padding: 0 !important;
}
table[class=body] .container {
padding: 0 !important;
width: 100% !important;
}
table[class=body] .main {
border-left-width: 0 !important;
border-radius: 0 !important;
border-right-width: 0 !important;
}
table[class=body] .btn table {
width: 100% !important;
}
table[class=body] .btn a {
width: 100% !important;
}
table[class=body] .img-responsive {
height: auto !important;
max-width: 100% !important;
width: auto !important;
}
}
/* -------------------------------------
PRESERVE THESE STYLES IN THE HEAD
------------------------------------- */
@media all {
.ExternalClass {
width: 100%;
}
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
.apple-link a {
color: inherit !important;
font-family: inherit !important;
font-size: inherit !important;
font-weight: inherit !important;
line-height: inherit !important;
text-decoration: none !important;
}
#MessageViewBody a {
color: inherit;
text-decoration: none;
font-size: inherit;
font-family: inherit;
font-weight: inherit;
line-height: inherit;
}
.btn-primary table td:hover {
background-color: #047857 !important;
}
.btn-primary a:hover {
background-color: #047857 !important;
border-color: #047857 !important;
}
}
</style>
</head>
<body class="" style="background-color: #f6f6f6; font-family: sans-serif; -webkit-font-smoothing: antialiased; font-size: 14px; line-height: 1.4; margin: 0; padding: 0; -ms-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;">
<table border="0" cellpadding="0" cellspacing="0" class="body" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background-color: #f6f6f6;">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
<tr>
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">
<p style="font-family: sans-serif; font-size: 18px; font-weight: 500; margin: 0; Margin-bottom: 15px;">Your Stats from {{ .Report.From | simpledate }} to {{ .Report.To | simpledate }}</p>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px;">You have coded a total of <strong>{{ .Report.Summary.TotalTime | duration }}</strong> between {{ .Report.From | simpledate }} and {{ .Report.To | simpledate }}</p>
<p style="font-family: sans-serif; font-size: 16px; font-weight: 500; margin: 0; Margin-bottom: 15px; Margin-top: 30px;">Projects</p>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>
{{ range $i, $item := .Report.Summary.Projects }}
<tr>
<td align="left" style="width: 300px; font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px; font-weight: 800;">{{ $item.Key }}:</td>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;">{{ $item.TotalFixed | duration }}</td>
</tr>
{{ end }}
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 16px; font-weight: 500; margin: 0; Margin-bottom: 15px; Margin-top: 30px;">Languages</p>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>
{{ range $i, $item := .Report.Summary.Languages }}
<tr>
<td align="left" style="width: 300px; font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px; font-weight: 800;">{{ $item.Key }}:</td>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;">{{ $item.TotalFixed | duration }}</td>
</tr>
{{ end }}
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 16px; font-weight: 500; margin: 0; Margin-bottom: 15px; Margin-top: 30px;">Editors</p>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>
{{ range $i, $item := .Report.Summary.Editors }}
<tr>
<td align="left" style="width: 300px; font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px; font-weight: 800;">{{ $item.Key }}:</td>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;">{{ $item.TotalFixed | duration }}</td>
</tr>
{{ end }}
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 16px; font-weight: 500; margin: 0; Margin-bottom: 15px; Margin-top: 30px;">Operating Systems</p>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>
{{ range $i, $item := .Report.Summary.OperatingSystems }}
<tr>
<td align="left" style="width: 300px; font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px; font-weight: 800;">{{ $item.Key }}:</td>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;">{{ $item.TotalFixed | duration }}</td>
</tr>
{{ end }}
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 16px; font-weight: 500; margin: 0; Margin-bottom: 15px; Margin-top: 30px;">Machines</p>
<table border="0" cellpadding="0" cellspacing="0" class="btn btn-primary" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; box-sizing: border-box;">
<tbody>
{{ range $i, $item := .Report.Summary.Machines }}
<tr>
<td align="left" style="width: 300px; font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px; font-weight: 800;">{{ $item.Key }}:</td>
<td align="left" style="font-family: sans-serif; font-size: 14px; vertical-align: top; padding-bottom: 15px;">{{ $item.TotalFixed | duration }}</td>
</tr>
{{ end }}
</tbody>
</table>
<p style="font-family: sans-serif; font-size: 14px; font-weight: normal; margin: 0; Margin-bottom: 15px; Margin-top: 30px;">If you do not want to receive e-mail reports anymore, please log in to Wakapi.dev and go to <i>Settings</i> to disable them.</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block powered-by" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
Powered by <a href="https://wakapi.dev" style="color: #999999; font-size: 12px; text-align: center; text-decoration: none;">Wakapi.dev</a>.
</td>
</tr>
</table>
</div>
</div>
</td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
</tr>
</table>
</body>
</html>

View File

@ -93,12 +93,18 @@
<tr>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>
<td class="container" style="font-family: sans-serif; font-size: 14px; vertical-align: top; display: block; Margin: 0 auto; max-width: 580px; padding: 10px; width: 580px;">
<div class="header" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
<td class="content-block" style="font-family: sans-serif; vertical-align: top; padding-bottom: 10px; padding-top: 10px; font-size: 12px; color: #999999; text-align: center;">
<img src="https://wakapi.dev/assets/images/android-chrome-192x192.png?utm_source=mail" alt="Wakapi Logo" width="96" style="width: 96px">
</td>
</tr>
</table>
</div>
<div class="content" style="box-sizing: border-box; display: block; Margin: 0 auto; max-width: 580px; padding: 10px;">
<!-- START CENTERED WHITE CONTAINER -->
<table class="main" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%; background: #ffffff; border-radius: 3px;">
<!-- START MAIN CONTENT AREA -->
<tr>
<td class="wrapper" style="font-family: sans-serif; font-size: 14px; vertical-align: top; box-sizing: border-box; padding: 20px;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
@ -127,11 +133,8 @@
</table>
</td>
</tr>
<!-- END MAIN CONTENT AREA -->
</table>
<!-- START FOOTER -->
<div class="footer" style="clear: both; Margin-top: 10px; text-align: center; width: 100%;">
<table border="0" cellpadding="0" cellspacing="0" style="border-collapse: separate; mso-table-lspace: 0pt; mso-table-rspace: 0pt; width: 100%;">
<tr>
@ -141,9 +144,6 @@
</tr>
</table>
</div>
<!-- END FOOTER -->
<!-- END CENTERED WHITE CONTAINER -->
</div>
</td>
<td style="font-family: sans-serif; font-size: 14px; vertical-align: top;">&nbsp;</td>