mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
aef0c929df | |||
9cb9747e2e | |||
68a17950ef | |||
a2368ff76a | |||
4838300086 | |||
a60c725d38 | |||
8ceef42ad4 | |||
8bed266110 | |||
a7afd73e62 | |||
1dc5be4784 | |||
b6812ddc3a |
42
.github/workflows/docker.yml
vendored
Normal file
42
.github/workflows/docker.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
name: Publish Docker Image
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '*.*.*'
|
||||
- '!*.*.*-*'
|
||||
|
||||
jobs:
|
||||
docker-publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
# https://stackoverflow.com/questions/58177786
|
||||
- name: Get version
|
||||
run: echo "GIT_TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Build and push to Docker Hub
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: true
|
||||
tags: |
|
||||
n1try/wakapi:${{ env.GIT_TAG }}
|
||||
n1try/wakapi:latest
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,dest=/tmp/.buildx-cache
|
3
.github/workflows/linux-build-on-release.yml
vendored
3
.github/workflows/linux-build-on-release.yml
vendored
@ -2,10 +2,11 @@ name: Build Wakapi on Linux
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
pull_request:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
|
3
.github/workflows/win-build-on-release.yml
vendored
3
.github/workflows/win-build-on-release.yml
vendored
@ -2,10 +2,11 @@ name: Build Wakapi on Windows
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
pull_request:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
- published
|
||||
|
||||
jobs:
|
||||
build-and-release:
|
||||
|
@ -21,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultConfigPath = "config.yml"
|
||||
defaultConfigPath = "config.yml"
|
||||
|
||||
SQLDialectMysql = "mysql"
|
||||
SQLDialectPostgres = "postgres"
|
||||
@ -312,6 +312,10 @@ func Load() *Config {
|
||||
logbuch.Fatal("either of listen_ipv4 or listen_ipv6 must be set")
|
||||
}
|
||||
|
||||
if config.Db.MaxConn <= 0 {
|
||||
logbuch.Fatal("you must allow at least one database connection")
|
||||
}
|
||||
|
||||
Set(config)
|
||||
return Get()
|
||||
}
|
||||
|
@ -22,27 +22,6 @@ 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/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/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/user.go:35.43,38.2 1 0
|
||||
github.com/muety/wakapi/models/user.go:40.33,44.2 1 0
|
||||
github.com/muety/wakapi/models/user.go:46.45,48.2 1 0
|
||||
github.com/muety/wakapi/models/user.go:50.45,52.2 1 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:30.34,32.2 1 1
|
||||
github.com/muety/wakapi/models/heartbeat.go:34.65,35.28 1 1
|
||||
github.com/muety/wakapi/models/heartbeat.go:38.2,39.45 2 1
|
||||
@ -60,9 +39,14 @@ github.com/muety/wakapi/models/heartbeat.go:55.23,56.19 1 1
|
||||
github.com/muety/wakapi/models/heartbeat.go:57.17,58.26 1 1
|
||||
github.com/muety/wakapi/models/heartbeat.go:59.22,60.18 1 1
|
||||
github.com/muety/wakapi/models/heartbeat.go:63.15,65.3 1 1
|
||||
github.com/muety/wakapi/models/heartbeat.go:76.41,78.16 2 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:81.2,82.10 2 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:78.16,80.3 1 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:70.37,86.2 1 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:94.41,96.16 2 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:99.2,100.10 2 0
|
||||
github.com/muety/wakapi/models/heartbeat.go:96.16,98.3 1 0
|
||||
github.com/muety/wakapi/models/user.go:35.43,38.2 1 0
|
||||
github.com/muety/wakapi/models/user.go:40.33,44.2 1 0
|
||||
github.com/muety/wakapi/models/user.go:46.45,48.2 1 0
|
||||
github.com/muety/wakapi/models/user.go:50.45,52.2 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
|
||||
@ -73,7 +57,25 @@ 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/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/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.45,76.2 1 0
|
||||
github.com/muety/wakapi/models/shared.go:78.51,81.2 2 0
|
||||
github.com/muety/wakapi/models/shared.go:83.37,86.2 2 0
|
||||
github.com/muety/wakapi/models/shared.go:88.35,90.2 1 0
|
||||
github.com/muety/wakapi/models/shared.go:92.34,94.2 1 0
|
||||
github.com/muety/wakapi/models/summary.go:41.27,45.2 1 0
|
||||
github.com/muety/wakapi/models/summary.go:97.29,99.2 1 1
|
||||
github.com/muety/wakapi/models/summary.go:101.37,108.2 6 1
|
||||
@ -124,90 +126,51 @@ github.com/muety/wakapi/models/summary.go:236.11,244.6 1 1
|
||||
github.com/muety/wakapi/models/summary.go:261.33,263.2 1 1
|
||||
github.com/muety/wakapi/models/summary.go:265.43,267.2 1 1
|
||||
github.com/muety/wakapi/models/summary.go:269.38,271.2 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/summary.go:10.71,13.18 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:49.2,49.22 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:14.58,15.24 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:16.66,18.22 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:19.64,20.23 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:21.39,23.21 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:24.66,25.24 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:26.40,28.22 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:29.31,30.23 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:31.66,32.42 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:33.49,35.40 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:36.41,37.43 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:38.68,40.42 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:41.35,42.43 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:43.26,44.21 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:45.10,46.39 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:52.73,59.56 5 0
|
||||
github.com/muety/wakapi/utils/summary.go:73.2,80.8 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:59.56,61.3 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:61.8,63.17 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:67.3,68.17 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:63.17,65.4 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:68.17,70.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/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: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.54 2 0
|
||||
github.com/muety/wakapi/utils/auth.go:43.2,44.30 2 0
|
||||
github.com/muety/wakapi/utils/auth.go:39.54,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: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.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
|
||||
github.com/muety/wakapi/utils/date.go:22.31,25.2 2 0
|
||||
github.com/muety/wakapi/utils/date.go:27.30,30.2 2 0
|
||||
github.com/muety/wakapi/utils/date.go:32.67,35.33 2 0
|
||||
github.com/muety/wakapi/utils/date.go:44.2,44.18 1 0
|
||||
github.com/muety/wakapi/utils/date.go:35.33,37.19 2 0
|
||||
github.com/muety/wakapi/utils/date.go:40.3,41.10 2 0
|
||||
github.com/muety/wakapi/utils/date.go:37.19,39.4 1 0
|
||||
github.com/muety/wakapi/utils/date.go:47.50,53.2 5 0
|
||||
github.com/muety/wakapi/utils/date.go:56.79,59.36 3 0
|
||||
github.com/muety/wakapi/utils/date.go:63.2,63.21 1 0
|
||||
github.com/muety/wakapi/utils/date.go:67.2,67.21 1 0
|
||||
github.com/muety/wakapi/utils/date.go:71.2,71.13 1 0
|
||||
github.com/muety/wakapi/utils/date.go:59.36,62.3 2 0
|
||||
github.com/muety/wakapi/utils/date.go:63.21,66.3 2 0
|
||||
github.com/muety/wakapi/utils/date.go:67.21,70.3 2 0
|
||||
github.com/muety/wakapi/utils/http.go:9.73,12.58 3 0
|
||||
github.com/muety/wakapi/utils/http.go:12.58,14.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:20.116,26.2 1 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:28.71,29.71 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:29.71,31.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:34.107,35.37 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:42.2,45.16 3 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:49.2,49.16 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:59.2,60.29 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:35.37,36.58 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:36.58,39.4 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:45.16,47.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:49.16,50.44 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:56.3,56.9 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:50.44,52.4 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:52.9,55.4 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:63.92,65.16 2 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:69.2,72.16 4 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:75.2,75.18 1 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:65.16,67.3 1 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:72.16,74.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:78.92,80.16 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:84.2,85.16 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:92.2,92.18 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:80.16,82.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:85.16,87.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:17.79,18.43 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:18.43,23.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:26.80,44.2 6 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:46.41,48.14 2 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:51.2,51.14 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:54.2,54.11 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:48.14,50.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:51.14,53.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:85.52,87.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:99.45,100.20 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:100.20,104.3 3 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:106.54,109.18 3 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:116.2,117.15 2 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:109.18,112.17 2 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:112.17,114.4 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:119.42,120.20 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:120.20,122.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:124.36,126.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:127.42,129.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:130.40,132.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:133.52,135.2 1 0
|
||||
github.com/muety/wakapi/config/utils.go:5.78,7.22 2 0
|
||||
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
|
||||
@ -264,52 +227,33 @@ github.com/muety/wakapi/config/config.go:284.21,289.96 3 0
|
||||
github.com/muety/wakapi/config/config.go:293.2,301.52 5 0
|
||||
github.com/muety/wakapi/config/config.go:305.2,305.47 1 0
|
||||
github.com/muety/wakapi/config/config.go:311.2,311.70 1 0
|
||||
github.com/muety/wakapi/config/config.go:315.2,316.14 2 0
|
||||
github.com/muety/wakapi/config/config.go:315.2,315.28 1 0
|
||||
github.com/muety/wakapi/config/config.go:319.2,320.14 2 0
|
||||
github.com/muety/wakapi/config/config.go:289.96,291.3 1 0
|
||||
github.com/muety/wakapi/config/config.go:301.52,303.3 1 0
|
||||
github.com/muety/wakapi/config/config.go:305.47,306.14 1 0
|
||||
github.com/muety/wakapi/config/config.go:306.14,308.4 1 0
|
||||
github.com/muety/wakapi/config/config.go:311.70,313.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:20.116,26.2 1 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:28.71,29.71 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:29.71,31.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:34.107,35.37 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:42.2,45.16 3 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:49.2,49.16 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:59.2,60.29 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:35.37,36.58 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:36.58,39.4 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:45.16,47.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:49.16,50.44 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:56.3,56.9 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:50.44,52.4 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:52.9,55.4 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:63.92,65.16 2 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:69.2,72.16 4 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:75.2,75.18 1 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:65.16,67.3 1 1
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:72.16,74.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:78.92,80.16 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:84.2,85.16 2 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:92.2,92.18 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:80.16,82.3 1 0
|
||||
github.com/muety/wakapi/middlewares/authenticate.go:85.16,87.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:17.79,18.43 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:18.43,23.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:26.80,44.2 6 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:74.52,76.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:88.45,89.20 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:89.20,93.3 3 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:95.54,98.18 3 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:105.2,106.15 2 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:98.18,101.17 2 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:101.17,103.4 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:108.42,109.20 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:109.20,111.3 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:113.36,115.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:116.42,118.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:119.40,121.2 1 0
|
||||
github.com/muety/wakapi/middlewares/logging.go:122.52,124.2 1 0
|
||||
github.com/muety/wakapi/config/config.go:315.28,317.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
|
||||
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
|
||||
@ -422,6 +366,41 @@ github.com/muety/wakapi/services/summary.go:324.54,326.3 1 1
|
||||
github.com/muety/wakapi/services/summary.go:331.59,333.25 2 1
|
||||
github.com/muety/wakapi/services/summary.go:336.2,336.32 1 1
|
||||
github.com/muety/wakapi/services/summary.go:333.25,335.3 1 1
|
||||
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/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
|
||||
@ -438,25 +417,6 @@ 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
|
||||
@ -497,41 +457,6 @@ 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: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/user.go:19.73,25.2 1 0
|
||||
github.com/muety/wakapi/services/user.go:27.74,28.40 1 0
|
||||
github.com/muety/wakapi/services/user.go:32.2,33.16 2 0
|
||||
@ -556,3 +481,88 @@ github.com/muety/wakapi/services/user.go:96.106,99.96 3 0
|
||||
github.com/muety/wakapi/services/user.go:104.2,104.68 1 0
|
||||
github.com/muety/wakapi/services/user.go:99.96,101.3 1 0
|
||||
github.com/muety/wakapi/services/user.go:101.8,103.3 1 0
|
||||
github.com/muety/wakapi/services/user.go:107.57,110.2 2 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.54 2 0
|
||||
github.com/muety/wakapi/utils/auth.go:43.2,44.30 2 0
|
||||
github.com/muety/wakapi/utils/auth.go:39.54,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: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.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
|
||||
github.com/muety/wakapi/utils/date.go:22.31,25.2 2 0
|
||||
github.com/muety/wakapi/utils/date.go:27.30,30.2 2 0
|
||||
github.com/muety/wakapi/utils/date.go:32.67,35.33 2 0
|
||||
github.com/muety/wakapi/utils/date.go:44.2,44.18 1 0
|
||||
github.com/muety/wakapi/utils/date.go:35.33,37.19 2 0
|
||||
github.com/muety/wakapi/utils/date.go:40.3,41.10 2 0
|
||||
github.com/muety/wakapi/utils/date.go:37.19,39.4 1 0
|
||||
github.com/muety/wakapi/utils/date.go:47.50,53.2 5 0
|
||||
github.com/muety/wakapi/utils/date.go:56.79,59.36 3 0
|
||||
github.com/muety/wakapi/utils/date.go:63.2,63.21 1 0
|
||||
github.com/muety/wakapi/utils/date.go:67.2,67.21 1 0
|
||||
github.com/muety/wakapi/utils/date.go:71.2,71.13 1 0
|
||||
github.com/muety/wakapi/utils/date.go:59.36,62.3 2 0
|
||||
github.com/muety/wakapi/utils/date.go:63.21,66.3 2 0
|
||||
github.com/muety/wakapi/utils/date.go:67.21,70.3 2 0
|
||||
github.com/muety/wakapi/utils/http.go:9.73,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/utils/summary.go:10.71,13.18 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:49.2,49.22 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:14.58,15.24 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:16.66,18.22 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:19.64,20.23 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:21.39,23.21 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:24.66,25.24 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:26.40,28.22 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:29.31,30.23 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:31.66,32.42 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:33.49,35.40 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:36.41,37.43 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:38.68,40.42 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:41.35,42.43 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:43.26,44.21 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:45.10,46.39 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:52.73,59.56 5 0
|
||||
github.com/muety/wakapi/utils/summary.go:73.2,80.8 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:59.56,61.3 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:61.8,63.17 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:67.3,68.17 2 0
|
||||
github.com/muety/wakapi/utils/summary.go:63.17,65.4 1 0
|
||||
github.com/muety/wakapi/utils/summary.go:68.17,70.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/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
|
||||
|
1
go.sum
1
go.sum
@ -273,7 +273,6 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/hashstructure v1.1.0 h1:P6P1hdjqAAknpY/M1CGipelZgp+4y9ja9kmUZPXP+H0=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1 h1:L60q1+q7cXE4JeEJJKMnh2brFIe3rZxCihYAB61ypAY=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
|
84
main.go
84
main.go
@ -7,8 +7,9 @@ import (
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/markbates/pkger"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/migrations/common"
|
||||
"github.com/muety/wakapi/migrations"
|
||||
"github.com/muety/wakapi/repositories"
|
||||
"github.com/muety/wakapi/routes/api"
|
||||
"gorm.io/gorm/logger"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -18,7 +19,6 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/muety/wakapi/middlewares"
|
||||
customMiddleware "github.com/muety/wakapi/middlewares/custom"
|
||||
"github.com/muety/wakapi/routes"
|
||||
shieldsV1Routes "github.com/muety/wakapi/routes/compat/shields/v1"
|
||||
wtV1Routes "github.com/muety/wakapi/routes/compat/wakatime/v1"
|
||||
@ -96,9 +96,9 @@ func main() {
|
||||
defer sqlDb.Close()
|
||||
|
||||
// Migrate database schema
|
||||
common.RunCustomPreMigrations(db, config)
|
||||
migrations.RunPreMigrations(db, config)
|
||||
runDatabaseMigrations()
|
||||
common.RunCustomPostMigrations(db, config)
|
||||
migrations.RunCustomPostMigrations(db, config)
|
||||
|
||||
// Repositories
|
||||
aliasRepository = repositories.NewAliasRepository(db)
|
||||
@ -122,69 +122,57 @@ func main() {
|
||||
go aggregationService.Schedule()
|
||||
go miscService.ScheduleCountTotalTime()
|
||||
|
||||
// TODO: move endpoint registration to the respective routes files
|
||||
|
||||
routes.Init()
|
||||
|
||||
// Handlers
|
||||
summaryHandler := routes.NewSummaryHandler(summaryService)
|
||||
healthHandler := routes.NewHealthHandler(db)
|
||||
heartbeatHandler := routes.NewHeartbeatHandler(heartbeatService, languageMappingService)
|
||||
settingsHandler := routes.NewSettingsHandler(userService, summaryService, aliasService, aggregationService, languageMappingService)
|
||||
homeHandler := routes.NewHomeHandler(keyValueService)
|
||||
loginHandler := routes.NewLoginHandler(userService)
|
||||
imprintHandler := routes.NewImprintHandler(keyValueService)
|
||||
// API Handlers
|
||||
healthApiHandler := api.NewHealthApiHandler(db)
|
||||
heartbeatApiHandler := api.NewHeartbeatApiHandler(heartbeatService, languageMappingService)
|
||||
summaryApiHandler := api.NewSummaryApiHandler(summaryService)
|
||||
|
||||
// Compat Handlers
|
||||
wakatimeV1AllHandler := wtV1Routes.NewAllTimeHandler(summaryService)
|
||||
wakatimeV1SummariesHandler := wtV1Routes.NewSummariesHandler(summaryService)
|
||||
shieldV1BadgeHandler := shieldsV1Routes.NewBadgeHandler(summaryService, userService)
|
||||
|
||||
// MVC Handlers
|
||||
summaryHandler := routes.NewSummaryHandler(summaryService, userService)
|
||||
settingsHandler := routes.NewSettingsHandler(userService, summaryService, aliasService, aggregationService, languageMappingService)
|
||||
homeHandler := routes.NewHomeHandler(keyValueService)
|
||||
loginHandler := routes.NewLoginHandler(userService)
|
||||
imprintHandler := routes.NewImprintHandler(keyValueService)
|
||||
|
||||
// Setup Routers
|
||||
router := mux.NewRouter()
|
||||
publicRouter := router.PathPrefix("/").Subrouter()
|
||||
settingsRouter := publicRouter.PathPrefix("/settings").Subrouter()
|
||||
summaryRouter := publicRouter.PathPrefix("/summary").Subrouter()
|
||||
rootRouter := router.PathPrefix("/").Subrouter()
|
||||
apiRouter := router.PathPrefix("/api").Subrouter()
|
||||
summaryApiRouter := apiRouter.PathPrefix("/summary").Subrouter()
|
||||
heartbeatApiRouter := apiRouter.PathPrefix("/heartbeat").Subrouter()
|
||||
healthApiRouter := apiRouter.PathPrefix("/health").Subrouter()
|
||||
compatRouter := apiRouter.PathPrefix("/compat").Subrouter()
|
||||
wakatimeV1Router := compatRouter.PathPrefix("/wakatime/v1/users/{user}").Subrouter()
|
||||
shieldsV1Router := compatRouter.PathPrefix("/shields/v1/{user}").Subrouter()
|
||||
compatApiRouter := apiRouter.PathPrefix("/compat").Subrouter()
|
||||
|
||||
// Middlewares
|
||||
// Globally used middlewares
|
||||
recoveryMiddleware := handlers.RecoveryHandler()
|
||||
loggingMiddleware := middlewares.NewLoggingMiddleware(
|
||||
// Use logbuch here once https://github.com/emvi/logbuch/issues/4 is realized
|
||||
log.New(os.Stdout, "", log.LstdFlags),
|
||||
)
|
||||
loggingMiddleware := middlewares.NewLoggingMiddleware(log.New(os.Stdout, "", log.LstdFlags))
|
||||
corsMiddleware := handlers.CORS()
|
||||
authenticateMiddleware := middlewares.NewAuthenticateMiddleware(
|
||||
userService,
|
||||
[]string{"/api/health", "/api/compat/shields/v1"},
|
||||
).Handler
|
||||
wakatimeRelayMiddleware := customMiddleware.NewWakatimeRelayMiddleware().Handler
|
||||
authenticateMiddleware := middlewares.NewAuthenticateMiddleware(userService, []string{"/api/health", "/api/compat/shields/v1"}).Handler
|
||||
|
||||
// Router configs
|
||||
router.Use(loggingMiddleware, recoveryMiddleware)
|
||||
summaryRouter.Use(authenticateMiddleware)
|
||||
settingsRouter.Use(authenticateMiddleware)
|
||||
apiRouter.Use(corsMiddleware, authenticateMiddleware)
|
||||
heartbeatApiRouter.Use(wakatimeRelayMiddleware)
|
||||
|
||||
// Route registrations
|
||||
homeHandler.RegisterRoutes(publicRouter)
|
||||
loginHandler.RegisterRoutes(publicRouter)
|
||||
imprintHandler.RegisterRoutes(publicRouter)
|
||||
summaryHandler.RegisterRoutes(summaryRouter)
|
||||
settingsHandler.RegisterRoutes(settingsRouter)
|
||||
homeHandler.RegisterRoutes(rootRouter)
|
||||
loginHandler.RegisterRoutes(rootRouter)
|
||||
imprintHandler.RegisterRoutes(rootRouter)
|
||||
summaryHandler.RegisterRoutes(rootRouter)
|
||||
settingsHandler.RegisterRoutes(rootRouter)
|
||||
|
||||
// API Route registrations
|
||||
summaryHandler.RegisterAPIRoutes(summaryApiRouter)
|
||||
healthHandler.RegisterAPIRoutes(healthApiRouter)
|
||||
heartbeatHandler.RegisterAPIRoutes(heartbeatApiRouter)
|
||||
wakatimeV1AllHandler.RegisterAPIRoutes(wakatimeV1Router)
|
||||
wakatimeV1SummariesHandler.RegisterAPIRoutes(wakatimeV1Router)
|
||||
shieldV1BadgeHandler.RegisterAPIRoutes(shieldsV1Router)
|
||||
// API route registrations
|
||||
summaryApiHandler.RegisterRoutes(apiRouter)
|
||||
healthApiHandler.RegisterRoutes(apiRouter)
|
||||
heartbeatApiHandler.RegisterRoutes(apiRouter)
|
||||
|
||||
// Compat route registrations
|
||||
wakatimeV1AllHandler.RegisterRoutes(compatApiRouter)
|
||||
wakatimeV1SummariesHandler.RegisterRoutes(compatApiRouter)
|
||||
shieldV1BadgeHandler.RegisterRoutes(compatApiRouter)
|
||||
|
||||
// Static Routes
|
||||
router.PathPrefix("/assets").Handler(http.FileServer(pkger.Dir("/static")))
|
||||
|
17
migrations/00000000_apply_fixtures.go
Normal file
17
migrations/00000000_apply_fixtures.go
Normal file
@ -0,0 +1,17 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/muety/wakapi/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
f := migrationFunc{
|
||||
name: "000-apply_fixtures",
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
return cfg.GetFixturesFunc(cfg.Db.Dialect)(db)
|
||||
},
|
||||
}
|
||||
|
||||
registerPostMigration(f)
|
||||
}
|
32
migrations/20201103_rename_language_mappings_table.go
Normal file
32
migrations/20201103_rename_language_mappings_table.go
Normal file
@ -0,0 +1,32 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
f := migrationFunc{
|
||||
name: "20201103-rename_language_mappings_table",
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
migrator := db.Migrator()
|
||||
oldTableName, newTableName := "custom_rules", "language_mappings"
|
||||
oldIndexName, newIndexName := "idx_customrule_user", "idx_language_mapping_user"
|
||||
|
||||
if migrator.HasTable(oldTableName) {
|
||||
logbuch.Info("renaming '%s' table to '%s'", oldTableName, newTableName)
|
||||
if err := migrator.RenameTable(oldTableName, &models.LanguageMapping{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logbuch.Info("renaming '%s' index to '%s'", oldIndexName, newIndexName)
|
||||
return migrator.RenameIndex(&models.LanguageMapping{}, oldIndexName, newIndexName)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
registerPreMigration(f)
|
||||
}
|
79
migrations/20201106_migration_cascade_constraints.go
Normal file
79
migrations/20201106_migration_cascade_constraints.go
Normal file
@ -0,0 +1,79 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
const name = "20201106-migration_cascade_constraints"
|
||||
|
||||
f := migrationFunc{
|
||||
name: name,
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
// drop all already existing foreign key constraints
|
||||
// afterwards let them be re-created by auto migrate with the newly introduced cascade settings,
|
||||
|
||||
migrator := db.Migrator()
|
||||
|
||||
if cfg.Db.Dialect == config.SQLDialectSqlite {
|
||||
// https://stackoverflow.com/a/1884893/3112139
|
||||
// unfortunately, we can't migrate existing sqlite databases to the newly introduced cascade settings
|
||||
// things like deleting all summaries won't work in those cases unless an entirely new db is created
|
||||
logbuch.Info("not attempting to drop and regenerate constraints on sqlite")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !migrator.HasTable(&models.KeyStringValue{}) {
|
||||
logbuch.Info("key-value table not yet existing")
|
||||
return nil
|
||||
}
|
||||
|
||||
condition := "key = ?"
|
||||
if cfg.Db.Dialect == config.SQLDialectMysql {
|
||||
condition = "`key` = ?"
|
||||
}
|
||||
lookupResult := db.Where(condition, name).First(&models.KeyStringValue{})
|
||||
if lookupResult.Error == nil && lookupResult.RowsAffected > 0 {
|
||||
logbuch.Info("no need to migrate '%s'", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SELECT * FROM INFORMATION_SCHEMA.table_constraints;
|
||||
constraints := map[string]interface{}{
|
||||
"fk_summaries_editors": &models.SummaryItem{},
|
||||
"fk_summaries_languages": &models.SummaryItem{},
|
||||
"fk_summaries_machines": &models.SummaryItem{},
|
||||
"fk_summaries_operating_systems": &models.SummaryItem{},
|
||||
"fk_summaries_projects": &models.SummaryItem{},
|
||||
"fk_summary_items_summary": &models.SummaryItem{},
|
||||
"fk_summaries_user": &models.Summary{},
|
||||
"fk_language_mappings_user": &models.LanguageMapping{},
|
||||
"fk_heartbeats_user": &models.Heartbeat{},
|
||||
"fk_aliases_user": &models.Alias{},
|
||||
}
|
||||
|
||||
for name, table := range constraints {
|
||||
if migrator.HasConstraint(table, name) {
|
||||
logbuch.Info("dropping constraint '%s'", name)
|
||||
if err := migrator.DropConstraint(table, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.Create(&models.KeyStringValue{
|
||||
Key: name,
|
||||
Value: "done",
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
registerPreMigration(f)
|
||||
}
|
58
migrations/20210202_fix_cascade_for_alias_user_constraint.go
Normal file
58
migrations/20210202_fix_cascade_for_alias_user_constraint.go
Normal file
@ -0,0 +1,58 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
const name = "20210202-fix_cascade_for_alias_user_constraint"
|
||||
|
||||
f := migrationFunc{
|
||||
name: name,
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
migrator := db.Migrator()
|
||||
|
||||
if cfg.Db.Dialect == config.SQLDialectSqlite {
|
||||
// see 20201106_migration_cascade_constraints
|
||||
logbuch.Info("not attempting to drop and regenerate constraints on sqlite")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !migrator.HasTable(&models.KeyStringValue{}) {
|
||||
logbuch.Info("key-value table not yet existing")
|
||||
return nil
|
||||
}
|
||||
|
||||
condition := "key = ?"
|
||||
if cfg.Db.Dialect == config.SQLDialectMysql {
|
||||
condition = "`key` = ?"
|
||||
}
|
||||
lookupResult := db.Where(condition, name).First(&models.KeyStringValue{})
|
||||
if lookupResult.Error == nil && lookupResult.RowsAffected > 0 {
|
||||
logbuch.Info("no need to migrate '%s'", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
if migrator.HasConstraint(&models.Alias{}, "fk_aliases_user") {
|
||||
logbuch.Info("dropping constraint 'fk_aliases_user'")
|
||||
if err := migrator.DropConstraint(&models.Alias{}, "fk_aliases_user"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.Create(&models.KeyStringValue{
|
||||
Key: name,
|
||||
Value: "done",
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
registerPreMigration(f)
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/muety/wakapi/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type migrationFunc struct {
|
||||
f func(db *gorm.DB, cfg *config.Config) error
|
||||
name string
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var customPostMigrations []migrationFunc
|
||||
|
||||
func init() {
|
||||
customPostMigrations = []migrationFunc{
|
||||
{
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
return cfg.GetFixturesFunc(cfg.Db.Dialect)(db)
|
||||
},
|
||||
name: "apply fixtures",
|
||||
},
|
||||
// TODO: add function to modify aggregated summaries according to configured custom language mappings
|
||||
}
|
||||
}
|
||||
|
||||
func RunCustomPostMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
for _, m := range customPostMigrations {
|
||||
logbuch.Info("potentially running migration '%s'", m.name)
|
||||
if err := m.f(db, cfg); err != nil {
|
||||
logbuch.Fatal("migration '%s' failed – %v", m.name, err)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var customPreMigrations []migrationFunc
|
||||
|
||||
func init() {
|
||||
customPreMigrations = []migrationFunc{
|
||||
{
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
migrator := db.Migrator()
|
||||
oldTableName, newTableName := "custom_rules", "language_mappings"
|
||||
oldIndexName, newIndexName := "idx_customrule_user", "idx_language_mapping_user"
|
||||
|
||||
if migrator.HasTable(oldTableName) {
|
||||
logbuch.Info("renaming '%s' table to '%s'", oldTableName, newTableName)
|
||||
if err := migrator.RenameTable(oldTableName, &models.LanguageMapping{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logbuch.Info("renaming '%s' index to '%s'", oldIndexName, newIndexName)
|
||||
return migrator.RenameIndex(&models.LanguageMapping{}, oldIndexName, newIndexName)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
name: "rename language mappings table",
|
||||
},
|
||||
{
|
||||
f: func(db *gorm.DB, cfg *config.Config) error {
|
||||
// drop all already existing foreign key constraints
|
||||
// afterwards let them be re-created by auto migrate with the newly introduced cascade settings,
|
||||
|
||||
migrator := db.Migrator()
|
||||
const lookupKey = "20201106-migration_cascade_constraints"
|
||||
|
||||
if cfg.Db.Dialect == config.SQLDialectSqlite {
|
||||
// https://stackoverflow.com/a/1884893/3112139
|
||||
// unfortunately, we can't migrate existing sqlite databases to the newly introduced cascade settings
|
||||
// things like deleting all summaries won't work in those cases unless an entirely new db is created
|
||||
logbuch.Info("not attempting to drop and regenerate constraints on sqlite")
|
||||
return nil
|
||||
}
|
||||
|
||||
if !migrator.HasTable(&models.KeyStringValue{}) {
|
||||
logbuch.Info("key-value table not yet existing")
|
||||
return nil
|
||||
}
|
||||
|
||||
condition := "key = ?"
|
||||
if cfg.Db.Dialect == config.SQLDialectMysql {
|
||||
condition = "`key` = ?"
|
||||
}
|
||||
lookupResult := db.Where(condition, lookupKey).First(&models.KeyStringValue{})
|
||||
if lookupResult.Error == nil && lookupResult.RowsAffected > 0 {
|
||||
logbuch.Info("no need to migrate cascade constraints")
|
||||
return nil
|
||||
}
|
||||
|
||||
// SELECT * FROM INFORMATION_SCHEMA.table_constraints;
|
||||
constraints := map[string]interface{}{
|
||||
"fk_summaries_editors": &models.SummaryItem{},
|
||||
"fk_summaries_languages": &models.SummaryItem{},
|
||||
"fk_summaries_machines": &models.SummaryItem{},
|
||||
"fk_summaries_operating_systems": &models.SummaryItem{},
|
||||
"fk_summaries_projects": &models.SummaryItem{},
|
||||
"fk_summary_items_summary": &models.SummaryItem{},
|
||||
"fk_summaries_user": &models.Summary{},
|
||||
"fk_language_mappings_user": &models.LanguageMapping{},
|
||||
"fk_heartbeats_user": &models.Heartbeat{},
|
||||
"fk_aliases_user": &models.Alias{},
|
||||
}
|
||||
|
||||
for name, table := range constraints {
|
||||
if migrator.HasConstraint(table, name) {
|
||||
logbuch.Info("dropping constraint '%s'", name)
|
||||
if err := migrator.DropConstraint(table, name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := db.Create(&models.KeyStringValue{
|
||||
Key: lookupKey,
|
||||
Value: "done",
|
||||
}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
name: "add cascade constraints",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func RunCustomPreMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
for _, m := range customPreMigrations {
|
||||
logbuch.Info("potentially running migration '%s'", m.name)
|
||||
if err := m.f(db, cfg); err != nil {
|
||||
logbuch.Fatal("migration '%s' failed – %v", m.name, err)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/models"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func MigrateLanguages(db *gorm.DB) {
|
||||
cfg := config.Get()
|
||||
|
||||
for k, v := range cfg.App.CustomLanguages {
|
||||
result := db.Model(models.Heartbeat{}).
|
||||
Where("language = ?", "").
|
||||
Where("entity LIKE ?", "%."+k).
|
||||
Updates(models.Heartbeat{Language: v})
|
||||
if result.Error != nil {
|
||||
logbuch.Fatal(result.Error.Error())
|
||||
}
|
||||
if result.RowsAffected > 0 {
|
||||
logbuch.Info("migrated %+v rows for custom language %+s", result.RowsAffected, k)
|
||||
}
|
||||
}
|
||||
}
|
67
migrations/migrations.go
Normal file
67
migrations/migrations.go
Normal file
@ -0,0 +1,67 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/muety/wakapi/config"
|
||||
"gorm.io/gorm"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type migrationFunc struct {
|
||||
f func(db *gorm.DB, cfg *config.Config) error
|
||||
name string
|
||||
}
|
||||
|
||||
type migrationFuncs []migrationFunc
|
||||
|
||||
var (
|
||||
preMigrations migrationFuncs
|
||||
postMigrations migrationFuncs
|
||||
)
|
||||
|
||||
func registerPreMigration(f migrationFunc) {
|
||||
preMigrations = append(preMigrations, f)
|
||||
}
|
||||
|
||||
func registerPostMigration(f migrationFunc) {
|
||||
postMigrations = append(postMigrations, f)
|
||||
}
|
||||
|
||||
// NOTE: Currently, migrations themselves keep track
|
||||
// of whether they have run, yet or not, because some
|
||||
// simply run on every start.
|
||||
|
||||
func RunPreMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
sort.Sort(preMigrations)
|
||||
|
||||
for _, m := range preMigrations {
|
||||
logbuch.Info("potentially running migration '%s'", m.name)
|
||||
if err := m.f(db, cfg); err != nil {
|
||||
logbuch.Fatal("migration '%s' failed – %v", m.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RunCustomPostMigrations(db *gorm.DB, cfg *config.Config) {
|
||||
sort.Sort(postMigrations)
|
||||
|
||||
for _, m := range postMigrations {
|
||||
logbuch.Info("potentially running migration '%s'", m.name)
|
||||
if err := m.f(db, cfg); err != nil {
|
||||
logbuch.Fatal("migration '%s' failed – %v", m.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m migrationFuncs) Len() int {
|
||||
return len(m)
|
||||
}
|
||||
|
||||
func (m migrationFuncs) Less(i, j int) bool {
|
||||
return strings.Compare(m[i].name, m[j].name) < 0
|
||||
}
|
||||
|
||||
func (m migrationFuncs) Swap(i, j int) {
|
||||
m[i], m[j] = m[j], m[i]
|
||||
}
|
@ -34,6 +34,11 @@ func (m *UserServiceMock) Update(user *models.User) (*models.User, error) {
|
||||
return args.Get(0).(*models.User), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *UserServiceMock) Delete(user *models.User) error {
|
||||
args := m.Called(user)
|
||||
return args.Error(0)
|
||||
}
|
||||
|
||||
func (m *UserServiceMock) ResetApiKey(user *models.User) (*models.User, error) {
|
||||
args := m.Called(user)
|
||||
return args.Get(0).(*models.User), args.Error(1)
|
||||
|
@ -2,8 +2,8 @@ package models
|
||||
|
||||
type Alias struct {
|
||||
ID uint `gorm:"primary_key"`
|
||||
Type uint8 `gorm:"not null; index:idx_alias_type_key; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||
User *User `json:"-" gorm:"not null"`
|
||||
Type uint8 `gorm:"not null; index:idx_alias_type_key"`
|
||||
User *User `json:"-" gorm:"not null; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
|
||||
UserID string `gorm:"not null; index:idx_alias_user"`
|
||||
Key string `gorm:"not null; index:idx_alias_type_key"`
|
||||
Value string `gorm:"not null"`
|
||||
|
@ -49,4 +49,5 @@ type IUserRepository interface {
|
||||
InsertOrGet(*models.User) (*models.User, bool, error)
|
||||
Update(*models.User) (*models.User, error)
|
||||
UpdateField(*models.User, string, interface{}) (*models.User, error)
|
||||
Delete(*models.User) error
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ func (r *UserRepository) GetByApiKey(key string) (*models.User, error) {
|
||||
func (r *UserRepository) GetAll() ([]*models.User, error) {
|
||||
var users []*models.User
|
||||
if err := r.db.
|
||||
Table("users").
|
||||
Where(&models.User{}).
|
||||
Find(&users).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -78,3 +78,7 @@ func (r *UserRepository) UpdateField(user *models.User, key string, value interf
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (r *UserRepository) Delete(user *models.User) error {
|
||||
return r.db.Delete(user).Error
|
||||
}
|
||||
|
33
routes/api/health.go
Normal file
33
routes/api/health.go
Normal file
@ -0,0 +1,33 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type HealthApiHandler struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewHealthApiHandler(db *gorm.DB) *HealthApiHandler {
|
||||
return &HealthApiHandler{db: db}
|
||||
}
|
||||
|
||||
func (h *HealthApiHandler) RegisterRoutes(router *mux.Router) {
|
||||
r := router.PathPrefix("/health").Subrouter()
|
||||
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||
}
|
||||
|
||||
func (h *HealthApiHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
var dbStatus int
|
||||
if sqlDb, err := h.db.DB(); err == nil {
|
||||
if err := sqlDb.Ping(); err == nil {
|
||||
dbStatus = 1
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(fmt.Sprintf("app=1\ndb=%d", dbStatus)))
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
package routes
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/emvi/logbuch"
|
||||
"github.com/gorilla/mux"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
customMiddleware "github.com/muety/wakapi/middlewares/custom"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"net/http"
|
||||
@ -12,14 +13,14 @@ import (
|
||||
"github.com/muety/wakapi/models"
|
||||
)
|
||||
|
||||
type HeartbeatHandler struct {
|
||||
type HeartbeatApiHandler struct {
|
||||
config *conf.Config
|
||||
heartbeatSrvc services.IHeartbeatService
|
||||
languageMappingSrvc services.ILanguageMappingService
|
||||
}
|
||||
|
||||
func NewHeartbeatHandler(heartbeatService services.IHeartbeatService, languageMappingService services.ILanguageMappingService) *HeartbeatHandler {
|
||||
return &HeartbeatHandler{
|
||||
func NewHeartbeatApiHandler(heartbeatService services.IHeartbeatService, languageMappingService services.ILanguageMappingService) *HeartbeatApiHandler {
|
||||
return &HeartbeatApiHandler{
|
||||
config: conf.Get(),
|
||||
heartbeatSrvc: heartbeatService,
|
||||
languageMappingSrvc: languageMappingService,
|
||||
@ -30,13 +31,15 @@ type heartbeatResponseVm struct {
|
||||
Responses [][]interface{} `json:"responses"`
|
||||
}
|
||||
|
||||
func (h *HeartbeatHandler) RegisterRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *HeartbeatHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodPost).HandlerFunc(h.ApiPost)
|
||||
func (h *HeartbeatApiHandler) RegisterRoutes(router *mux.Router) {
|
||||
r := router.PathPrefix("/heartbeat").Subrouter()
|
||||
r.Use(
|
||||
customMiddleware.NewWakatimeRelayMiddleware().Handler,
|
||||
)
|
||||
r.Methods(http.MethodPost).HandlerFunc(h.Post)
|
||||
}
|
||||
|
||||
func (h *HeartbeatHandler) ApiPost(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *HeartbeatApiHandler) Post(w http.ResponseWriter, r *http.Request) {
|
||||
var heartbeats []*models.Heartbeat
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
opSys, editor, _ := utils.ParseUserAgent(r.Header.Get("User-Agent"))
|
38
routes/api/summary.go
Normal file
38
routes/api/summary.go
Normal file
@ -0,0 +1,38 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
su "github.com/muety/wakapi/routes/utils"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type SummaryApiHandler struct {
|
||||
config *conf.Config
|
||||
summarySrvc services.ISummaryService
|
||||
}
|
||||
|
||||
func NewSummaryApiHandler(summaryService services.ISummaryService) *SummaryApiHandler {
|
||||
return &SummaryApiHandler{
|
||||
summarySrvc: summaryService,
|
||||
config: conf.Get(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SummaryApiHandler) RegisterRoutes(router *mux.Router) {
|
||||
r := router.PathPrefix("/summary").Subrouter()
|
||||
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||
}
|
||||
|
||||
func (h *SummaryApiHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
summary, err, status := su.LoadUserSummary(h.summarySrvc, r)
|
||||
if err != nil {
|
||||
w.WriteHeader(status)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
utils.RespondJSON(w, http.StatusOK, summary)
|
||||
}
|
@ -31,13 +31,12 @@ func NewBadgeHandler(summaryService services.ISummaryService, userService servic
|
||||
}
|
||||
}
|
||||
|
||||
func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *BadgeHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).HandlerFunc(h.ApiGet)
|
||||
func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
|
||||
r := router.PathPrefix("/shields/v1/{user}").Subrouter()
|
||||
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||
}
|
||||
|
||||
func (h *BadgeHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *BadgeHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
intervalReg := regexp.MustCompile(intervalPattern)
|
||||
entityFilterReg := regexp.MustCompile(entityFilterPattern)
|
||||
|
||||
|
@ -24,13 +24,11 @@ func NewAllTimeHandler(summaryService services.ISummaryService) *AllTimeHandler
|
||||
}
|
||||
}
|
||||
|
||||
func (h *AllTimeHandler) RegisterRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *AllTimeHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
router.Path("/all_time_since_today").Methods(http.MethodGet).HandlerFunc(h.ApiGet)
|
||||
func (h *AllTimeHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Path("/wakatime/v1/users/{user}/all_time_since_today").Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||
}
|
||||
|
||||
func (h *AllTimeHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *AllTimeHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
values, _ := url.ParseQuery(r.URL.RawQuery)
|
||||
|
||||
|
@ -25,10 +25,8 @@ func NewSummariesHandler(summaryService services.ISummaryService) *SummariesHand
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SummariesHandler) RegisterRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *SummariesHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
router.Path("/summaries").Methods(http.MethodGet).HandlerFunc(h.ApiGet)
|
||||
func (h *SummariesHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Path("/wakatime/v1/users/{user}/summaries").Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||
}
|
||||
|
||||
// TODO: Support parameters: project, branches, timeout, writes_only, timezone
|
||||
@ -36,7 +34,7 @@ func (h *SummariesHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
// Timezone can be specified via an offset suffix (e.g. +02:00) in date strings.
|
||||
// Requires https://github.com/muety/wakapi/issues/108.
|
||||
|
||||
func (h *SummariesHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SummariesHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
requestedUser := vars["user"]
|
||||
authorizedUser := r.Context().Value(models.UserKey).(*models.User)
|
||||
|
@ -4,5 +4,4 @@ import "github.com/gorilla/mux"
|
||||
|
||||
type Handler interface {
|
||||
RegisterRoutes(router *mux.Router)
|
||||
RegisterAPIRoutes(router *mux.Router)
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type HealthHandler struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewHealthHandler(db *gorm.DB) *HealthHandler {
|
||||
return &HealthHandler{db: db}
|
||||
}
|
||||
|
||||
func (h *HealthHandler) RegisterRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *HealthHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).HandlerFunc(h.ApiGet)
|
||||
}
|
||||
|
||||
func (h *HealthHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
var dbStatus int
|
||||
if sqlDb, err := h.db.DB(); err == nil {
|
||||
if err := sqlDb.Ping(); err == nil {
|
||||
dbStatus = 1
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(fmt.Sprintf("app=1\ndb=%d", dbStatus)))
|
||||
}
|
@ -32,8 +32,6 @@ func (h *HomeHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Path("/").Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||
}
|
||||
|
||||
func (h *HomeHandler) RegisterAPIRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *HomeHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
|
@ -25,8 +25,6 @@ func (h *ImprintHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Path("/imprint").Methods(http.MethodGet).HandlerFunc(h.GetImprint)
|
||||
}
|
||||
|
||||
func (h *ImprintHandler) RegisterAPIRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *ImprintHandler) GetImprint(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
|
@ -32,8 +32,6 @@ func (h *LoginHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Path("/signup").Methods(http.MethodPost).HandlerFunc(h.PostSignup)
|
||||
}
|
||||
|
||||
func (h *LoginHandler) RegisterAPIRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *LoginHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/muety/wakapi/utils"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
@ -16,6 +17,8 @@ func Init() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
type action func(w http.ResponseWriter, r *http.Request) (int, string, string)
|
||||
|
||||
var templates map[string]*template.Template
|
||||
|
||||
func loadTemplates() {
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/schema"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/middlewares"
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/models/view"
|
||||
"github.com/muety/wakapi/services"
|
||||
@ -41,20 +42,14 @@ func NewSettingsHandler(userService services.IUserService, summaryService servic
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||
router.Path("/credentials").Methods(http.MethodPost).HandlerFunc(h.PostCredentials)
|
||||
router.Path("/aliases").Methods(http.MethodPost).HandlerFunc(h.PostAlias)
|
||||
router.Path("/aliases/delete").Methods(http.MethodPost).HandlerFunc(h.DeleteAlias)
|
||||
router.Path("/language_mappings").Methods(http.MethodPost).HandlerFunc(h.PostLanguageMapping)
|
||||
router.Path("/language_mappings/delete").Methods(http.MethodPost).HandlerFunc(h.DeleteLanguageMapping)
|
||||
router.Path("/reset").Methods(http.MethodPost).HandlerFunc(h.PostResetApiKey)
|
||||
router.Path("/badges").Methods(http.MethodPost).HandlerFunc(h.PostToggleBadges)
|
||||
router.Path("/wakatime_integration").Methods(http.MethodPost).HandlerFunc(h.PostSetWakatimeApiKey)
|
||||
router.Path("/regenerate").Methods(http.MethodPost).HandlerFunc(h.PostRegenerateSummaries)
|
||||
r := router.PathPrefix("/settings").Subrouter()
|
||||
r.Use(
|
||||
middlewares.NewAuthenticateMiddleware(h.userSrvc, []string{}).Handler,
|
||||
)
|
||||
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||
r.Methods(http.MethodPost).HandlerFunc(h.PostIndex)
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) RegisterAPIRoutes(router *mux.Router) {}
|
||||
|
||||
func (h *SettingsHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
@ -63,7 +58,73 @@ func (h *SettingsHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) PostIndex(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
if err := r.ParseForm(); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing form values"))
|
||||
return
|
||||
}
|
||||
|
||||
action := r.PostForm.Get("action")
|
||||
r.PostForm.Del("action")
|
||||
|
||||
actionFunc := h.dispatchAction(action)
|
||||
if actionFunc == nil {
|
||||
logbuch.Warn("failed to dispatch action '%s'", action)
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("unknown action requests"))
|
||||
return
|
||||
}
|
||||
|
||||
status, successMsg, errorMsg := actionFunc(w, r)
|
||||
|
||||
// action responded itself
|
||||
if status == -1 {
|
||||
return
|
||||
}
|
||||
|
||||
if errorMsg != "" {
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError(errorMsg))
|
||||
return
|
||||
}
|
||||
if successMsg != "" {
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess(successMsg))
|
||||
return
|
||||
}
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) dispatchAction(action string) action {
|
||||
switch action {
|
||||
case "change_password":
|
||||
return h.actionChangePassword
|
||||
case "reset_apikey":
|
||||
return h.actionResetApiKey
|
||||
case "delete_alias":
|
||||
return h.actionDeleteAlias
|
||||
case "add_alias":
|
||||
return h.actionAddAlias
|
||||
case "delete_mapping":
|
||||
return h.actionDeleteLanguageMapping
|
||||
case "add_mapping":
|
||||
return h.actionAddLanguageMapping
|
||||
case "toggle_badges":
|
||||
return h.actionToggleBadges
|
||||
case "toggle_wakatime":
|
||||
return h.actionSetWakatimeApiKey
|
||||
case "regenerate_summaries":
|
||||
return h.actionRegenerateSummaries
|
||||
case "delete_account":
|
||||
return h.actionDeleteUser
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) actionChangePassword(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
@ -72,41 +133,29 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request
|
||||
|
||||
var credentials models.CredentialsReset
|
||||
if err := r.ParseForm(); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters"))
|
||||
return
|
||||
return http.StatusBadRequest, "", "missing parameters"
|
||||
}
|
||||
if err := credentialsDecoder.Decode(&credentials, r.PostForm); err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("missing parameters"))
|
||||
return
|
||||
return http.StatusBadRequest, "", "missing parameters"
|
||||
}
|
||||
|
||||
if !utils.CompareBcrypt(user.Password, credentials.PasswordOld, h.config.Security.PasswordSalt) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid credentials"))
|
||||
return
|
||||
return http.StatusUnauthorized, "", "invalid credentials"
|
||||
}
|
||||
|
||||
if !credentials.IsValid() {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("invalid parameters"))
|
||||
return
|
||||
return http.StatusBadRequest, "", "invalid parameters"
|
||||
}
|
||||
|
||||
user.Password = credentials.PasswordNew
|
||||
if hash, err := utils.HashBcrypt(user.Password, h.config.Security.PasswordSalt); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
||||
return
|
||||
return http.StatusInternalServerError, "", "internal server error"
|
||||
} else {
|
||||
user.Password = hash
|
||||
}
|
||||
|
||||
if _, err := h.userSrvc.Update(user); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
||||
return
|
||||
return http.StatusInternalServerError, "", "internal server error"
|
||||
}
|
||||
|
||||
login := &models.Login{
|
||||
@ -115,75 +164,28 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request
|
||||
}
|
||||
encoded, err := h.config.Security.SecureCookie.Encode(models.AuthCookieKey, login.Username)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
||||
return
|
||||
return http.StatusInternalServerError, "", "internal server error"
|
||||
}
|
||||
|
||||
http.SetCookie(w, h.config.CreateCookie(models.AuthCookieKey, encoded, "/"))
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("password was updated successfully"))
|
||||
return http.StatusOK, "password was updated successfully", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) DeleteLanguageMapping(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) actionResetApiKey(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
id, err := strconv.Atoi(r.PostFormValue("mapping_id"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete mapping"))
|
||||
return
|
||||
if _, err := h.userSrvc.ResetApiKey(user); err != nil {
|
||||
return http.StatusInternalServerError, "", "internal server error"
|
||||
}
|
||||
|
||||
if mapping, err := h.languageMappingSrvc.GetById(uint(id)); err != nil || mapping == nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("mapping not found"))
|
||||
return
|
||||
} else if mapping.UserID != user.ID {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("not allowed to delete mapping"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.languageMappingSrvc.Delete(&models.LanguageMapping{ID: uint(id)}); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("could not delete mapping"))
|
||||
return
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping deleted successfully"))
|
||||
msg := fmt.Sprintf("your new api key is: %s", user.ApiKey)
|
||||
return http.StatusOK, msg, ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostLanguageMapping(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
extension := r.PostFormValue("extension")
|
||||
language := r.PostFormValue("language")
|
||||
|
||||
if extension[0] == '.' {
|
||||
extension = extension[1:]
|
||||
}
|
||||
|
||||
mapping := &models.LanguageMapping{
|
||||
UserID: user.ID,
|
||||
Extension: extension,
|
||||
Language: language,
|
||||
}
|
||||
|
||||
if _, err := h.languageMappingSrvc.Create(mapping); err != nil {
|
||||
w.WriteHeader(http.StatusConflict)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("mapping already exists"))
|
||||
return
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("mapping added successfully"))
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) DeleteAlias(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) actionDeleteAlias(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
@ -196,19 +198,15 @@ func (h *SettingsHandler) DeleteAlias(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
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
|
||||
return http.StatusNotFound, "", "aliases not found"
|
||||
} 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
|
||||
return http.StatusInternalServerError, "", "could not delete aliases"
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("aliases deleted successfully"))
|
||||
return http.StatusOK, "aliases deleted successfully", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostAlias(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) actionAddAlias(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
@ -228,32 +226,76 @@ func (h *SettingsHandler) PostAlias(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
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
|
||||
return http.StatusBadRequest, "", "invalid input"
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("alias added successfully"))
|
||||
return http.StatusOK, "alias added successfully", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostResetApiKey(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) actionDeleteLanguageMapping(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
if _, err := h.userSrvc.ResetApiKey(user); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
||||
return
|
||||
id, err := strconv.Atoi(r.PostFormValue("mapping_id"))
|
||||
if err != nil {
|
||||
return http.StatusInternalServerError, "", "could not delete mapping"
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("your new api key is: %s", user.ApiKey)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess(msg))
|
||||
if mapping, err := h.languageMappingSrvc.GetById(uint(id)); err != nil || mapping == nil {
|
||||
return http.StatusNotFound, "", "mapping not found"
|
||||
} else if mapping.UserID != user.ID {
|
||||
return http.StatusForbidden, "", "not allowed to delete mapping"
|
||||
}
|
||||
|
||||
if err := h.languageMappingSrvc.Delete(&models.LanguageMapping{ID: uint(id)}); err != nil {
|
||||
return http.StatusInternalServerError, "", "could not delete mapping"
|
||||
}
|
||||
|
||||
return http.StatusOK, "mapping deleted successfully", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostSetWakatimeApiKey(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) actionAddLanguageMapping(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
extension := r.PostFormValue("extension")
|
||||
language := r.PostFormValue("language")
|
||||
|
||||
if extension[0] == '.' {
|
||||
extension = extension[1:]
|
||||
}
|
||||
|
||||
mapping := &models.LanguageMapping{
|
||||
UserID: user.ID,
|
||||
Extension: extension,
|
||||
Language: language,
|
||||
}
|
||||
|
||||
if _, err := h.languageMappingSrvc.Create(mapping); err != nil {
|
||||
return http.StatusConflict, "", "mapping already exists"
|
||||
}
|
||||
|
||||
return http.StatusOK, "mapping added successfully", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) actionToggleBadges(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
if _, err := h.userSrvc.ToggleBadges(user); err != nil {
|
||||
return http.StatusInternalServerError, "", "internal server error"
|
||||
}
|
||||
|
||||
return http.StatusOK, "", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) actionSetWakatimeApiKey(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
@ -263,35 +305,17 @@ func (h *SettingsHandler) PostSetWakatimeApiKey(w http.ResponseWriter, r *http.R
|
||||
|
||||
// Healthcheck, if a new API key is set, i.e. the feature is activated
|
||||
if (user.WakatimeApiKey == "" && apiKey != "") && !h.validateWakatimeKey(apiKey) {
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to connect to WakaTime, API key invalid?"))
|
||||
return
|
||||
return http.StatusBadRequest, "", "failed to connect to WakaTime, API key invalid?"
|
||||
}
|
||||
|
||||
if _, err := h.userSrvc.SetWakatimeApiKey(user, apiKey); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
||||
return
|
||||
return http.StatusInternalServerError, "", "internal server error"
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("Wakatime API Key updated successfully"))
|
||||
return http.StatusOK, "Wakatime API Key updated successfully", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostToggleBadges(w http.ResponseWriter, r *http.Request) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
if _, err := h.userSrvc.ToggleBadges(user); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("internal server error"))
|
||||
return
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r))
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) PostRegenerateSummaries(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *SettingsHandler) actionRegenerateSummaries(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
@ -301,19 +325,37 @@ func (h *SettingsHandler) PostRegenerateSummaries(w http.ResponseWriter, r *http
|
||||
logbuch.Info("clearing summaries for user '%s'", user.ID)
|
||||
if err := h.summarySrvc.DeleteByUser(user.ID); err != nil {
|
||||
logbuch.Error("failed to clear summaries: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to delete old summaries"))
|
||||
return
|
||||
return http.StatusInternalServerError, "", "failed to delete old summaries"
|
||||
}
|
||||
|
||||
if err := h.aggregationSrvc.Run(map[string]bool{user.ID: true}); err != nil {
|
||||
logbuch.Error("failed to regenerate summaries: %v", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithError("failed to generate aggregations"))
|
||||
return
|
||||
return http.StatusInternalServerError, "", "failed to generate aggregations"
|
||||
|
||||
}
|
||||
|
||||
templates[conf.SettingsTemplate].Execute(w, h.buildViewModel(r).WithSuccess("summaries are being regenerated – this may take a few seconds"))
|
||||
return http.StatusOK, "summaries are being regenerated – this may take a few seconds", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) actionDeleteUser(w http.ResponseWriter, r *http.Request) (int, string, string) {
|
||||
if h.config.IsDev() {
|
||||
loadTemplates()
|
||||
}
|
||||
|
||||
user := r.Context().Value(models.UserKey).(*models.User)
|
||||
go func(user *models.User) {
|
||||
logbuch.Info("deleting user '%s' shortly", user.ID)
|
||||
time.Sleep(5 * time.Minute)
|
||||
if err := h.userSrvc.Delete(user); err != nil {
|
||||
logbuch.Error("failed to delete user '%s' – %v", user.ID, err)
|
||||
} else {
|
||||
logbuch.Info("successfully deleted user '%s'", user.ID)
|
||||
}
|
||||
}(user)
|
||||
|
||||
http.SetCookie(w, h.config.GetClearCookie(models.AuthCookieKey, "/"))
|
||||
http.Redirect(w, r, fmt.Sprintf("%s/?success=%s", h.config.Server.BasePath, "Your account will be deleted in a few minutes. Sorry to you go."), http.StatusFound)
|
||||
return -1, "", ""
|
||||
}
|
||||
|
||||
func (h *SettingsHandler) validateWakatimeKey(apiKey string) bool {
|
||||
|
@ -3,8 +3,10 @@ package routes
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
conf "github.com/muety/wakapi/config"
|
||||
"github.com/muety/wakapi/middlewares"
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/models/view"
|
||||
su "github.com/muety/wakapi/routes/utils"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"net/http"
|
||||
@ -12,33 +14,24 @@ import (
|
||||
|
||||
type SummaryHandler struct {
|
||||
config *conf.Config
|
||||
userSrvc services.IUserService
|
||||
summarySrvc services.ISummaryService
|
||||
}
|
||||
|
||||
func NewSummaryHandler(summaryService services.ISummaryService) *SummaryHandler {
|
||||
func NewSummaryHandler(summaryService services.ISummaryService, userService services.IUserService) *SummaryHandler {
|
||||
return &SummaryHandler{
|
||||
summarySrvc: summaryService,
|
||||
userSrvc: userService,
|
||||
config: conf.Get(),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SummaryHandler) RegisterRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||
}
|
||||
|
||||
func (h *SummaryHandler) RegisterAPIRoutes(router *mux.Router) {
|
||||
router.Methods(http.MethodGet).HandlerFunc(h.ApiGet)
|
||||
}
|
||||
|
||||
func (h *SummaryHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
|
||||
summary, err, status := h.loadUserSummary(r)
|
||||
if err != nil {
|
||||
w.WriteHeader(status)
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
utils.RespondJSON(w, http.StatusOK, summary)
|
||||
r := router.PathPrefix("/summary").Subrouter()
|
||||
r.Use(
|
||||
middlewares.NewAuthenticateMiddleware(h.userSrvc, []string{}).Handler,
|
||||
)
|
||||
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||
}
|
||||
|
||||
func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
@ -52,7 +45,7 @@ func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
r.URL.RawQuery = q.Encode()
|
||||
}
|
||||
|
||||
summary, err, status := h.loadUserSummary(r)
|
||||
summary, err, status := su.LoadUserSummary(h.summarySrvc, r)
|
||||
if err != nil {
|
||||
w.WriteHeader(status)
|
||||
templates[conf.SummaryTemplate].Execute(w, h.buildViewModel(r).WithError(err.Error()))
|
||||
@ -77,25 +70,6 @@ func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
|
||||
templates[conf.SummaryTemplate].Execute(w, vm)
|
||||
}
|
||||
|
||||
func (h *SummaryHandler) loadUserSummary(r *http.Request) (*models.Summary, error, int) {
|
||||
summaryParams, err := utils.ParseSummaryParams(r)
|
||||
if err != nil {
|
||||
return nil, err, http.StatusBadRequest
|
||||
}
|
||||
|
||||
var retrieveSummary services.SummaryRetriever = h.summarySrvc.Retrieve
|
||||
if summaryParams.Recompute {
|
||||
retrieveSummary = h.summarySrvc.Summarize
|
||||
}
|
||||
|
||||
summary, err := h.summarySrvc.Aliased(summaryParams.From, summaryParams.To, summaryParams.User, retrieveSummary)
|
||||
if err != nil {
|
||||
return nil, err, http.StatusInternalServerError
|
||||
}
|
||||
|
||||
return summary, nil, http.StatusOK
|
||||
}
|
||||
|
||||
func (h *SummaryHandler) buildViewModel(r *http.Request) *view.SummaryViewModel {
|
||||
return &view.SummaryViewModel{
|
||||
Success: r.URL.Query().Get("success"),
|
||||
|
27
routes/utils/summary_utils.go
Normal file
27
routes/utils/summary_utils.go
Normal file
@ -0,0 +1,27 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"github.com/muety/wakapi/models"
|
||||
"github.com/muety/wakapi/services"
|
||||
"github.com/muety/wakapi/utils"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func LoadUserSummary(ss services.ISummaryService, r *http.Request) (*models.Summary, error, int) {
|
||||
summaryParams, err := utils.ParseSummaryParams(r)
|
||||
if err != nil {
|
||||
return nil, err, http.StatusBadRequest
|
||||
}
|
||||
|
||||
var retrieveSummary services.SummaryRetriever = ss.Retrieve
|
||||
if summaryParams.Recompute {
|
||||
retrieveSummary = ss.Summarize
|
||||
}
|
||||
|
||||
summary, err := ss.Aliased(summaryParams.From, summaryParams.To, summaryParams.User, retrieveSummary)
|
||||
if err != nil {
|
||||
return nil, err, http.StatusInternalServerError
|
||||
}
|
||||
|
||||
return summary, nil, http.StatusOK
|
||||
}
|
@ -97,10 +97,10 @@ func (srv *AggregationService) trigger(jobs chan<- *AggregationJob, userIds map[
|
||||
logbuch.Error(err.Error())
|
||||
return err
|
||||
} else if userIds != nil && len(userIds) > 0 {
|
||||
users = make([]*models.User, len(userIds))
|
||||
for i, u := range allUsers {
|
||||
users = make([]*models.User, 0)
|
||||
for _, u := range allUsers {
|
||||
if yes, ok := userIds[u.ID]; yes && ok {
|
||||
users[i] = u
|
||||
users = append(users, u)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -61,6 +61,7 @@ type IUserService interface {
|
||||
GetAll() ([]*models.User, error)
|
||||
CreateOrGet(*models.Signup) (*models.User, bool, error)
|
||||
Update(*models.User) (*models.User, error)
|
||||
Delete(*models.User) error
|
||||
ResetApiKey(*models.User) (*models.User, error)
|
||||
ToggleBadges(*models.User) (*models.User, error)
|
||||
SetWakatimeApiKey(*models.User, string) (*models.User, error)
|
||||
|
@ -103,3 +103,8 @@ func (srv *UserService) MigrateMd5Password(user *models.User, login *models.Logi
|
||||
}
|
||||
return srv.repository.UpdateField(user, "password", user.Password)
|
||||
}
|
||||
|
||||
func (srv *UserService) Delete(user *models.User) error {
|
||||
srv.cache.Flush()
|
||||
return srv.repository.Delete(user)
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
1.21.0
|
||||
1.22.2
|
@ -64,7 +64,8 @@
|
||||
Change Password
|
||||
</h2>
|
||||
|
||||
<form class="mt-10" action="settings/credentials" method="post">
|
||||
<form class="mt-10" action="" method="post">
|
||||
<input type="hidden" name="action" value="change_password">
|
||||
<div class="mb-8">
|
||||
<label class="inline-block text-sm mb-1 text-gray-500" for="password_old">Current Password</label>
|
||||
<input class="shadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded w-full py-1 px-3"
|
||||
@ -96,7 +97,8 @@
|
||||
Reset API Key
|
||||
</h2>
|
||||
|
||||
<form class="mt-6" action="settings/reset" method="post">
|
||||
<form class="mt-6" action="" method="post">
|
||||
<input type="hidden" name="action" value="reset_apikey">
|
||||
<div class="text-gray-300 text-sm mb-4">
|
||||
<strong>⚠️ Caution:</strong> Resetting your API key requires you to update your <span
|
||||
class="font-mono">.wakatime.cfg</span> files on all of your computers to make the WakaTime
|
||||
@ -141,7 +143,8 @@
|
||||
are mapped to <span class="underline">{{ $alias.Type | typeName }}</span> <span
|
||||
class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono">{{ $alias.Key }}</span>.
|
||||
</div>
|
||||
<form class="float-right" action="settings/aliases/delete" method="post">
|
||||
<form class="float-right" action="" method="post">
|
||||
<input type="hidden" name="action" value="delete_alias">
|
||||
<input type="hidden" id="delete_alias_key" name="key" required value="{{ $alias.Key }}">
|
||||
<input type="hidden" id="delete_alias_type" name="type" required value="{{ $alias.Type }}">
|
||||
<button type="submit"
|
||||
@ -155,7 +158,8 @@
|
||||
{{end}}
|
||||
|
||||
<h3 class="inline-block font-semibold text-md border-b border-green-700 text-white mb-2">Add Rule</h3>
|
||||
<form action="settings/aliases" method="post">
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="action" value="add_alias">
|
||||
<div class="flex items-center mt-2 w-full text-gray-500 text-sm">
|
||||
<span class="mr-2">Map</span>
|
||||
<select name="type" id="select-type"
|
||||
@ -203,7 +207,8 @@
|
||||
then change the <span class="underline">language</span> to <span
|
||||
class="text-white text-xs bg-gray-900 rounded py-1 px-2 font-mono mr-1">{{ $mapping.Language }}</span>
|
||||
</div>
|
||||
<form class="float-right" action="settings/language_mappings/delete" method="post">
|
||||
<form class="float-right" action="" method="post">
|
||||
<input type="hidden" name="action" value="delete_mapping">
|
||||
<input type="hidden" id="mapping_id" name="mapping_id" required value="{{ $mapping.ID }}">
|
||||
<button type="submit"
|
||||
class="py-1 px-3 rounded border border-red-500 hover:border-red-600 text-gray-400 text-sm">
|
||||
@ -216,7 +221,8 @@
|
||||
{{end}}
|
||||
|
||||
<h3 class="inline-block font-semibold text-md border-b border-green-700 text-white">Add Rule</h3>
|
||||
<form action="settings/language_mappings" method="post">
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="action" value="add_mapping">
|
||||
<div class="flex items-center w-full text-gray-500 text-sm">
|
||||
<span class="mr-2">When filename ends in</span>
|
||||
<input class="shadow appearance-nonshadow appearance-none bg-gray-800 focus:bg-gray-700 text-gray-300 border-green-700 focus:border-gray-500 border rounded py-1 px-3"
|
||||
@ -241,7 +247,8 @@
|
||||
Badges
|
||||
</div>
|
||||
|
||||
<form class="mt-6" action="settings/badges" method="post">
|
||||
<form class="mt-6" action="" method="post">
|
||||
<input type="hidden" name="action" value="toggle_badges">
|
||||
<div class="text-gray-300 text-sm mb-4">
|
||||
{{ if .User.BadgesEnabled }}
|
||||
<p>Badges are currently enabled. You can disable the feature by deactivating the respective API
|
||||
@ -328,7 +335,8 @@
|
||||
target="_blank">get your API key</a> and paste it here.</p>
|
||||
</div>
|
||||
|
||||
<form action="settings/wakatime_integration" method="post">
|
||||
<form action="" method="post">
|
||||
<input type="hidden" name="action" value="toggle_wakatime">
|
||||
|
||||
{{ $placeholderText := "Paste your WakaTime API key here ..." }}
|
||||
{{ if .User.WakatimeApiKey }}
|
||||
@ -389,14 +397,34 @@
|
||||
case heartbeats were deleted after the respective summaries had been generated.
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-10 flex justify-center">
|
||||
<form action="settings/regenerate" method="post" id="form-regenerate-summaries">
|
||||
<div class="mt-6 flex justify-center">
|
||||
<form action="" method="post" id="form-regenerate-summaries">
|
||||
<input type="hidden" name="action" value="regenerate_summaries">
|
||||
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
||||
id="btn-regenerate-summaries">
|
||||
Clear & Regenerate
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="mt-10 text-gray-300 text-sm">
|
||||
<h3 class="font-semibold text-md mb-4 border-b border-green-700 inline-block">
|
||||
Delete Account
|
||||
</h3>
|
||||
<p>
|
||||
Deleting your account will cause all data, including all your heartbeats, to be erased from the
|
||||
server immediately. This action is irreversible. <strong>Be careful!</strong>
|
||||
</p>
|
||||
</div>
|
||||
<div class="mt-6 flex justify-center">
|
||||
<form action="" method="post" id="form-delete-user">
|
||||
<input type="hidden" name="action" value="delete_account">
|
||||
<button type="button" class="py-1 px-3 rounded bg-red-500 hover:bg-red-600 text-white text-sm"
|
||||
id="btn-confirm-delete-user">
|
||||
Delete my Account
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
@ -419,6 +447,14 @@
|
||||
formRegenerate.submit()
|
||||
}
|
||||
})
|
||||
|
||||
const btnDelete = document.querySelector('#btn-confirm-delete-user')
|
||||
const formDelete = document.querySelector('#form-delete-user')
|
||||
btnDelete.addEventListener('click', () => {
|
||||
if (confirm('Are you sure? This can not be undone!')) {
|
||||
formDelete.submit()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{{ template "footer.tpl.html" . }}
|
||||
|
Reference in New Issue
Block a user