1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00

Compare commits

..

7 Commits
1.0.0 ... 1.1.0

Author SHA1 Message Date
Ferdinand Mütsch
7d36c4e111 Rename project.
Add build script.
2020-03-31 12:22:17 +02:00
Ferdinand Mütsch
1510bcaa91 Experimental Postgres support. 2020-03-31 12:03:49 +02:00
Ferdinand Mütsch
b858a02ecd Update Readme. 2020-03-31 11:25:24 +02:00
Ferdinand Mütsch
0e61870568 Resolve #7. 2020-03-31 11:24:44 +02:00
Ferdinand Mütsch
0664861f74 Fix #13. 2020-03-31 10:47:22 +02:00
Ferdinand Mütsch
bcb56a02ef Readme typo. 2020-03-31 09:17:00 +02:00
Ferdinand Mütsch
fd2e0d145d Update README.md 2020-03-11 10:19:55 +01:00
24 changed files with 1715 additions and 111 deletions

View File

@@ -1,4 +1,5 @@
ENV=prod ENV=prod
WAKAPI_DB_TYPE=mysql
WAKAPI_DB_USER=myuser WAKAPI_DB_USER=myuser
WAKAPI_DB_PASSWORD=mysecretpassword WAKAPI_DB_PASSWORD=mysecretpassword
WAKAPI_DB_HOST=localhost WAKAPI_DB_HOST=localhost

2
.github/FUNDING.yml vendored
View File

@@ -1,2 +1,2 @@
github: n1try github: muety
custom: ['https://paypal.me/ferdinandmuetsch', 'https://www.buymeacoffee.com/n1try'] custom: ['https://paypal.me/ferdinandmuetsch', 'https://www.buymeacoffee.com/n1try']

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ launch.json
.env .env
wakapi wakapi
.idea .idea
build

View File

@@ -8,16 +8,16 @@
## Prerequisites ## Prerequisites
### Server ### Server
* Go >= 1.13 (with `$GOPATH` properly set) * Go >= 1.13 (with `$GOPATH` properly set)
* A MySQL database * An SQL database (MySQL or Postgres)
### Client ### Client
* [WakaTime plugin](https://wakatime.com/plugins) for your editor / IDE * [WakaTime plugin](https://wakatime.com/plugins) for your editor / IDE
## Usage ## Usage
* Create an empty MySQL database * Create an empty database
* Enable Go module support: `export GO111MODULE=on` * Enable Go module support: `export GO111MODULE=on`
* Get code: `go get github.com/n1try/wakapi` * Get code: `go get github.com/muety/wakapi`
* Go to project root: `cd "$GOPATH/src/github.com/n1try/wakapi"` * Go to project root: `cd "$GOPATH/src/github.com/muety/wakapi"`
* Copy `.env.example` to `.env` and set database credentials * Copy `.env.example` to `.env` and set database credentials
* Set target port in `config.ini` * Set target port in `config.ini`
* Build executable: `go build` * Build executable: `go build`
@@ -27,6 +27,8 @@
* `api_key = the_api_key_printed_to_the_console_after_starting_the_server` * `api_key = the_api_key_printed_to_the_console_after_starting_the_server`
* Open [http://localhost:3000](http://localhost:3000) in your browser * Open [http://localhost:3000](http://localhost:3000) in your browser
**As an alternative** to building from source or using `go get` you can also download one of the existing [pre-compiled binaries](https://github.com/muety/wakapi/releases).
### Run with Docker ### Run with Docker
* Edit `docker-compose.yml` file and change passwords for the DB * Edit `docker-compose.yml` file and change passwords for the DB
* Build the container `docker-compose build` * Build the container `docker-compose build`
@@ -34,7 +36,6 @@
* To get the api key look in the logs `docker-compose logs | grep "API key"` * To get the api key look in the logs `docker-compose logs | grep "API key"`
* The application should now be running on `localhost:3000` * The application should now be running on `localhost:3000`
### User Accounts ### User Accounts
* When starting wakapi for the first time, a default user _**admin**_ with password _**admin**_ is created. The corresponding API key is printed to the console. * When starting wakapi for the first time, a default user _**admin**_ with password _**admin**_ is created. The corresponding API key is printed to the console.
* Additional users, at the moment, can be added only via SQL statements on your database, like this: * Additional users, at the moment, can be added only via SQL statements on your database, like this:
@@ -62,12 +63,6 @@ For the above example, you would need to add two aliases, like this:
It is recommended to use wakapi behind a **reverse proxy**, like [Caddy](https://caddyserver.com) or _nginx_ to enable **TLS encryption** (HTTPS). It is recommended to use wakapi behind a **reverse proxy**, like [Caddy](https://caddyserver.com) or _nginx_ to enable **TLS encryption** (HTTPS).
However, if you want to expose your wakapi instance to the public anyway, you need to set `listen = 0.0.0.0` in `config.ini` However, if you want to expose your wakapi instance to the public anyway, you need to set `listen = 0.0.0.0` in `config.ini`
## Todo
* User sign up and log in
* Additional endpoints for retrieving statistics data
* Support for SQLite database
* Unit tests
## Important Note ## Important Note
**This is not an alternative to using WakaTime.** It is just a custom, non-commercial, self-hosted application to collect coding statistics using the already existing editor plugins provided by the WakaTime community. It was created for personal use only and with the purpose of keeping the sovereignity of your own data. However, if you like the official product, **please support the authors and buy an official WakaTime subscription!** **This is not an alternative to using WakaTime.** It is just a custom, non-commercial, self-hosted application to collect coding statistics using the already existing editor plugins provided by the WakaTime community. It was created for personal use only and with the purpose of keeping the sovereignity of your own data. However, if you like the official product, **please support the authors and buy an official WakaTime subscription!**

16
build.sh Normal file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
OSLIST=( darwin linux windows )
ARCHLIST=( amd64 )
VERSION=$(cat version.txt)
for os in ${OSLIST[*]}
do
for arch in ${ARCHLIST[*]}
do
GOOS=$os
GOARCH=$arch
echo "Building $GOOS / $GOARCH"
GOOS=$GOOS GOARCH=$GOARCH go build -o "build/wakapi_${VERSION}_${GOOS}_${GOARCH}" "github.com/muety/wakapi"
done
done

1482
data/colors.json Normal file

File diff suppressed because it is too large Load Diff

2
go.mod
View File

@@ -1,4 +1,4 @@
module github.com/n1try/wakapi module github.com/muety/wakapi
go 1.13 go 1.13

19
go.sum
View File

@@ -1,6 +1,5 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU=
cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@@ -13,14 +12,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY= github.com/codegangsta/negroni v1.0.0 h1:+aYywywx4bnKXWvoWtRfJ91vC59NbEhEY03sZjQhbVY=
github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3 h1:tkum0XDgfR0jcVVXuTsYv/erY2NnEDqwRojbxR1rBYA=
github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -38,12 +34,10 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
@@ -57,25 +51,20 @@ github.com/jinzhu/gorm v1.9.11 h1:gaHGvE+UnWGlbWG4Y3FUwY1EcZ5n6S9WtqBA/uySMLE=
github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw= github.com/jinzhu/gorm v1.9.11/go.mod h1:bu/pK8szGZ2puuErfU0RwyeNdsf3e6nCX/noXaVxkfw=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M=
github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4=
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -89,7 +78,6 @@ github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaR
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
@@ -104,21 +92,17 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/t-tiger/gorm-bulk-insert v0.0.0-20191014134946-beb77b81825f h1:Op5lFYUNE7tPxu6gJfwkgY8HMIWpLqiLApBJfGs71U8= github.com/t-tiger/gorm-bulk-insert v0.0.0-20191014134946-beb77b81825f h1:Op5lFYUNE7tPxu6gJfwkgY8HMIWpLqiLApBJfGs71U8=
github.com/t-tiger/gorm-bulk-insert v0.0.0-20191014134946-beb77b81825f/go.mod h1:SK1RZT4TR1aMUNGtbk6YxTPgx2D/gfbxB571QGnAV+c= github.com/t-tiger/gorm-bulk-insert v0.0.0-20191014134946-beb77b81825f/go.mod h1:SK1RZT4TR1aMUNGtbk6YxTPgx2D/gfbxB571QGnAV+c=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -157,7 +141,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
@@ -168,14 +151,12 @@ google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.50.0 h1:c/4YI/GUgB7d2yOkxdsQyYDhW67nWrTl6Zyd9vagYmg= gopkg.in/ini.v1 v1.50.0 h1:c/4YI/GUgB7d2yOkxdsQyYDhW67nWrTl6Zyd9vagYmg=
gopkg.in/ini.v1 v1.50.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.50.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

51
main.go
View File

@@ -3,10 +3,13 @@ package main
import ( import (
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"encoding/json"
"io/ioutil"
"log" "log"
"net/http" "net/http"
"os" "os"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/codegangsta/negroni" "github.com/codegangsta/negroni"
@@ -17,21 +20,26 @@ import (
uuid "github.com/satori/go.uuid" uuid "github.com/satori/go.uuid"
ini "gopkg.in/ini.v1" ini "gopkg.in/ini.v1"
"github.com/n1try/wakapi/middlewares" "github.com/muety/wakapi/middlewares"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
"github.com/n1try/wakapi/routes" "github.com/muety/wakapi/routes"
"github.com/n1try/wakapi/services" "github.com/muety/wakapi/services"
"github.com/n1try/wakapi/utils" "github.com/muety/wakapi/utils"
_ "github.com/jinzhu/gorm/dialects/mysql" _ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/postgres"
) )
// TODO: Refactor entire project to be structured after business domains
func readConfig() *models.Config { func readConfig() *models.Config {
if err := godotenv.Load(); err != nil { if err := godotenv.Load(); err != nil {
log.Fatal(err) log.Fatal(err)
} }
// TODO: Use jinzhu/configor or so
env, _ := os.LookupEnv("ENV") env, _ := os.LookupEnv("ENV")
dbType, valid := os.LookupEnv("WAKAPI_DB_TYPE")
dbUser, valid := os.LookupEnv("WAKAPI_DB_USER") dbUser, valid := os.LookupEnv("WAKAPI_DB_USER")
dbPassword, valid := os.LookupEnv("WAKAPI_DB_PASSWORD") dbPassword, valid := os.LookupEnv("WAKAPI_DB_PASSWORD")
dbHost, valid := os.LookupEnv("WAKAPI_DB_HOST") dbHost, valid := os.LookupEnv("WAKAPI_DB_HOST")
@@ -48,6 +56,10 @@ func readConfig() *models.Config {
log.Fatalf("Fail to read file: %v", err) log.Fatalf("Fail to read file: %v", err)
} }
if dbType == "" {
dbType = "mysql"
}
dbMaxConn := cfg.Section("database").Key("max_connections").MustUint(1) dbMaxConn := cfg.Section("database").Key("max_connections").MustUint(1)
addr := cfg.Section("server").Key("listen").MustString("127.0.0.1") addr := cfg.Section("server").Key("listen").MustString("127.0.0.1")
port, err := strconv.Atoi(os.Getenv("PORT")) port, err := strconv.Atoi(os.Getenv("PORT"))
@@ -64,6 +76,27 @@ func readConfig() *models.Config {
customLangs[k.Name()] = k.MustString("unknown") customLangs[k.Name()] = k.MustString("unknown")
} }
// Read language colors
// Source: https://raw.githubusercontent.com/ozh/github-colors/master/colors.json
var colors = make(map[string]string)
var rawColors map[string]struct {
Color string `json:"color"`
Url string `json:"url"`
}
data, err := ioutil.ReadFile("data/colors.json")
if err != nil {
log.Fatal(err)
}
if err := json.Unmarshal(data, &rawColors); err != nil {
log.Fatal(err)
}
for k, v := range rawColors {
colors[strings.ToLower(k)] = v.Color
}
return &models.Config{ return &models.Config{
Env: env, Env: env,
Port: port, Port: port,
@@ -73,10 +106,11 @@ func readConfig() *models.Config {
DbUser: dbUser, DbUser: dbUser,
DbPassword: dbPassword, DbPassword: dbPassword,
DbName: dbName, DbName: dbName,
DbDialect: "mysql", DbDialect: dbType,
DbMaxConn: dbMaxConn, DbMaxConn: dbMaxConn,
CleanUp: cleanUp, CleanUp: cleanUp,
CustomLanguages: customLangs, CustomLanguages: customLangs,
LanguageColors: colors,
} }
} }
@@ -92,6 +126,7 @@ func main() {
if err != nil { if err != nil {
log.Fatal("Could not connect to database.") log.Fatal("Could not connect to database.")
} }
// TODO: Graceful shutdown
defer db.Close() defer db.Close()
// Migrate database schema // Migrate database schema
@@ -147,8 +182,8 @@ func main() {
mainRouter.Path("/").Methods(http.MethodGet).HandlerFunc(summaryHandler.Index) mainRouter.Path("/").Methods(http.MethodGet).HandlerFunc(summaryHandler.Index)
// API Routes // API Routes
apiRouter.Path("/heartbeat").Methods(http.MethodPost).HandlerFunc(heartbeatHandler.Post) apiRouter.Path("/heartbeat").Methods(http.MethodPost).HandlerFunc(heartbeatHandler.ApiPost)
apiRouter.Path("/summary").Methods(http.MethodGet).HandlerFunc(summaryHandler.Get) apiRouter.Path("/summary").Methods(http.MethodGet).HandlerFunc(summaryHandler.ApiGet)
// Static Routes // Static Routes
router.PathPrefix("/assets").Handler(negroni.Classic().With(negroni.Wrap(http.FileServer(http.Dir("./static"))))) router.PathPrefix("/assets").Handler(negroni.Classic().With(negroni.Wrap(http.FileServer(http.Dir("./static")))))

View File

@@ -13,8 +13,8 @@ import (
"github.com/patrickmn/go-cache" "github.com/patrickmn/go-cache"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
"github.com/n1try/wakapi/services" "github.com/muety/wakapi/services"
) )
type AuthenticateMiddleware struct { type AuthenticateMiddleware struct {

View File

@@ -13,6 +13,7 @@ type Config struct {
DbMaxConn uint DbMaxConn uint
CleanUp bool CleanUp bool
CustomLanguages map[string]string CustomLanguages map[string]string
LanguageColors map[string]string
} }
func (c *Config) IsDev() bool { func (c *Config) IsDev() bool {

View File

@@ -35,3 +35,8 @@ type SummaryItemContainer struct {
Type uint8 Type uint8
Items []*SummaryItem Items []*SummaryItem
} }
type SummaryViewModel struct {
*Summary
LanguageColors map[string]string
}

View File

@@ -5,17 +5,17 @@ import (
"net/http" "net/http"
"os" "os"
"github.com/n1try/wakapi/services" "github.com/muety/wakapi/services"
"github.com/n1try/wakapi/utils" "github.com/muety/wakapi/utils"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
) )
type HeartbeatHandler struct { type HeartbeatHandler struct {
HeartbeatSrvc *services.HeartbeatService HeartbeatSrvc *services.HeartbeatService
} }
func (h *HeartbeatHandler) Post(w http.ResponseWriter, r *http.Request) { func (h *HeartbeatHandler) ApiPost(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost { if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return

View File

@@ -7,9 +7,9 @@ import (
"path" "path"
"time" "time"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
"github.com/n1try/wakapi/services" "github.com/muety/wakapi/services"
"github.com/n1try/wakapi/utils" "github.com/muety/wakapi/utils"
) )
const ( const (
@@ -44,7 +44,7 @@ func (m *SummaryHandler) loadTemplates() {
m.indexTemplate = indexTpl m.indexTemplate = indexTpl
} }
func (h *SummaryHandler) Get(w http.ResponseWriter, r *http.Request) { func (h *SummaryHandler) ApiGet(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet { if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed) w.WriteHeader(http.StatusMethodNotAllowed)
return return
@@ -91,7 +91,12 @@ func (h *SummaryHandler) Index(w http.ResponseWriter, r *http.Request) {
return return
} }
h.indexTemplate.Execute(w, summary) vm := models.SummaryViewModel{
Summary: summary,
LanguageColors: utils.FilterLanguageColors(h.SummarySrvc.Config.LanguageColors, summary),
}
h.indexTemplate.Execute(w, vm)
} }
func loadUserSummary(r *http.Request, summaryService *services.SummaryService) (*models.Summary, error, int) { func loadUserSummary(r *http.Request, summaryService *services.SummaryService) (*models.Summary, error, int) {

View File

@@ -7,7 +7,7 @@ import (
"github.com/jasonlvhit/gocron" "github.com/jasonlvhit/gocron"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
) )
const ( const (

View File

@@ -5,7 +5,7 @@ import (
"sync" "sync"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
) )
type AliasService struct { type AliasService struct {

View File

@@ -2,12 +2,12 @@ package services
import ( import (
"github.com/jasonlvhit/gocron" "github.com/jasonlvhit/gocron"
"github.com/n1try/wakapi/utils" "github.com/muety/wakapi/utils"
"log" "log"
"time" "time"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
gormbulk "github.com/t-tiger/gorm-bulk-insert" gormbulk "github.com/t-tiger/gorm-bulk-insert"
) )

View File

@@ -10,7 +10,7 @@ import (
"time" "time"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
) )
type SummaryService struct { type SummaryService struct {

View File

@@ -2,7 +2,7 @@ package services
import ( import (
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
) )
type UserService struct { type UserService struct {

View File

@@ -1,11 +1,13 @@
const SHOW_TOP_N = 10 const SHOW_TOP_N = 10
const CHART_TARGET_SIZE = 170
const projectsCanvas = document.getElementById("chart-projects") const projectsCanvas = document.getElementById('chart-projects')
const osCanvas = document.getElementById("chart-os") const osCanvas = document.getElementById('chart-os')
const editorsCanvas = document.getElementById("chart-editor") const editorsCanvas = document.getElementById('chart-editor')
const languagesCanvas = document.getElementById("chart-language") const languagesCanvas = document.getElementById('chart-language')
let charts = [] let charts = []
let resizeCount = 0
String.prototype.toHHMMSS = function () { String.prototype.toHHMMSS = function () {
var sec_num = parseInt(this, 10) var sec_num = parseInt(this, 10)
@@ -64,7 +66,9 @@ function draw() {
tooltips: getTooltipOptions('projects', 'bar'), tooltips: getTooltipOptions('projects', 'bar'),
legend: { legend: {
display: false display: false
} },
maintainAspectRatio: false,
onResize: onChartResize
} }
}) })
@@ -83,7 +87,9 @@ function draw() {
}, },
options: { options: {
title: Object.assign(titleOptions, {text: `Operating Systems (top ${SHOW_TOP_N})`}), title: Object.assign(titleOptions, {text: `Operating Systems (top ${SHOW_TOP_N})`}),
tooltips: getTooltipOptions('operatingSystems', 'pie') tooltips: getTooltipOptions('operatingSystems', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
} }
}) })
@@ -102,7 +108,9 @@ function draw() {
}, },
options: { options: {
title: Object.assign(titleOptions, {text: `Editors (top ${SHOW_TOP_N})`}), title: Object.assign(titleOptions, {text: `Editors (top ${SHOW_TOP_N})`}),
tooltips: getTooltipOptions('editors', 'pie') tooltips: getTooltipOptions('editors', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
} }
}) })
@@ -113,7 +121,7 @@ function draw() {
data: wakapiData.languages data: wakapiData.languages
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length)) .slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length))
.map(p => parseInt(p.total)), .map(p => parseInt(p.total)),
backgroundColor: wakapiData.languages.map(p => getRandomColor(p.key)) backgroundColor: wakapiData.languages.map(p => languageColors[p.key.toLowerCase()] || getRandomColor(p.key))
}], }],
labels: wakapiData.languages labels: wakapiData.languages
.slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length)) .slice(0, Math.min(SHOW_TOP_N, wakapiData.languages.length))
@@ -121,7 +129,9 @@ function draw() {
}, },
options: { options: {
title: Object.assign(titleOptions, {text: `Languages (top ${SHOW_TOP_N})`}), title: Object.assign(titleOptions, {text: `Languages (top ${SHOW_TOP_N})`}),
tooltips: getTooltipOptions('languages', 'pie') tooltips: getTooltipOptions('languages', 'pie'),
maintainAspectRatio: false,
onResize: onChartResize
} }
}) })
@@ -129,39 +139,78 @@ function draw() {
document.getElementById('grid-container').style.visibility = 'visible' document.getElementById('grid-container').style.visibility = 'visible'
charts = [projectChart, osChart, editorChart, languageChart] charts = [projectChart, osChart, editorChart, languageChart]
charts.forEach(c => c.options.onResize(c.chart))
equalizeHeights()
}
function getContainer(chart) {
return chart.canvas.parentNode
}
function onChartResize(chart) {
let container = getContainer(chart)
let targetHeight = Math.min(chart.width, CHART_TARGET_SIZE)
let actualHeight = chart.height - chart.chartArea.top
let containerTargetHeight = container.clientHeight += (targetHeight - actualHeight)
container.style.height = parseInt(containerTargetHeight) + 'px'
resizeCount++
watchEqualize()
}
function watchEqualize() {
if (resizeCount === charts.length) {
equalizeHeights()
resizeCount = 0
}
}
function equalizeHeights() {
let maxHeight = 0
charts.forEach(c => {
let container = getContainer(c)
if (maxHeight < container.clientHeight) {
maxHeight = container.clientHeight
}
})
charts.forEach(c => {
let container = getContainer(c)
container.style.height = parseInt(maxHeight) + 'px'
})
} }
function getTotal(data) { function getTotal(data) {
let total = data.reduce((acc, d) => acc + d.total, 0) let total = data.reduce((acc, d) => acc + d.total, 0)
document.getElementById("total-span").innerText = total.toString().toHHMMSS() document.getElementById('total-span').innerText = total.toString().toHHMMSS()
} }
function getRandomColor(seed) { function getRandomColor(seed) {
seed = seed ? seed : '1234567'; seed = seed ? seed : '1234567'
Math.seedrandom(seed); Math.seedrandom(seed)
var letters = '0123456789ABCDEF'.split(''); var letters = '0123456789ABCDEF'.split('')
var color = '#'; var color = '#'
for (var i = 0; i < 6; i++) { for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)]; color += letters[Math.floor(Math.random() * 16)]
} }
return color; return color
} }
// https://koddsson.com/posts/emoji-favicon/ // https://koddsson.com/posts/emoji-favicon/
const favicon = document.querySelector("link[rel=icon]"); const favicon = document.querySelector('link[rel=icon]')
if (favicon) { if (favicon) {
const emoji = favicon.getAttribute("data-emoji"); const emoji = favicon.getAttribute('data-emoji')
if (emoji) { if (emoji) {
const canvas = document.createElement("canvas"); const canvas = document.createElement('canvas')
canvas.height = 64; canvas.height = 64
canvas.width = 64; canvas.width = 64
const ctx = canvas.getContext("2d"); const ctx = canvas.getContext('2d')
ctx.font = "64px serif"; ctx.font = '64px serif'
ctx.fillText(emoji, 0, 64); ctx.fillText(emoji, 0, 64)
favicon.href = canvas.toDataURL(); favicon.href = canvas.toDataURL()
} }
} }
window.addEventListener('load', function() { window.addEventListener('load', function () {
draw() draw()
}) })

16
utils/color.go Normal file
View File

@@ -0,0 +1,16 @@
package utils
import (
"github.com/muety/wakapi/models"
"strings"
)
func FilterLanguageColors(all map[string]string, summary *models.Summary) map[string]string {
subset := make(map[string]string)
for _, item := range summary.Languages {
if c, ok := all[strings.ToLower(item.Key)]; ok {
subset[strings.ToLower(item.Key)] = c
}
}
return subset
}

View File

@@ -2,12 +2,11 @@ package utils
import ( import (
"errors" "errors"
"fmt"
"regexp" "regexp"
"strconv"
"strings"
"time" "time"
"github.com/n1try/wakapi/models" "github.com/muety/wakapi/models"
) )
func ParseDate(date string) (time.Time, error) { func ParseDate(date string) (time.Time, error) {
@@ -32,18 +31,34 @@ func ParseUserAgent(ua string) (string, string, error) {
} }
func MakeConnectionString(config *models.Config) string { func MakeConnectionString(config *models.Config) string {
location, _ := time.LoadLocation("Local") switch config.DbDialect {
str := strings.Builder{} case "mysql":
str.WriteString(config.DbUser) return mySqlConnectionString(config)
str.WriteString(":") case "postgres":
str.WriteString(config.DbPassword) return postgresConnectionString(config)
str.WriteString("@tcp(") }
str.WriteString(config.DbHost) return ""
str.WriteString(":") }
str.WriteString(strconv.Itoa(int(config.DbPort)))
str.WriteString(")/") func mySqlConnectionString(config *models.Config) string {
str.WriteString(config.DbName) location, _ := time.LoadLocation("Local")
str.WriteString("?charset=utf8&parseTime=true&loc=") return fmt.Sprintf(
str.WriteString(location.String()) "%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=true&loc=%s",
return str.String() config.DbUser,
config.DbPassword,
config.DbHost,
config.DbPort,
config.DbName,
location.String(),
)
}
func postgresConnectionString(config *models.Config) string {
return fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s sslmode=disable",
config.DbHost,
config.DbPort,
config.DbUser,
config.DbName,
config.DbPassword,
)
} }

1
version.txt Normal file
View File

@@ -0,0 +1 @@
1.1.0

View File

@@ -10,7 +10,7 @@
<link href="assets/app.css" rel="stylesheet"> <link href="assets/app.css" rel="stylesheet">
</head> </head>
<body class="bg-gray-800 text-gray-700 p-4 pt-12 flex flex-col min-h-screen max-w-screen-xl mx-auto justify-center"> <body class="bg-gray-800 text-gray-700 p-4 pt-10 flex flex-col min-h-screen max-w-screen-xl mx-auto justify-center">
<div class="flex items-center justify-center"> <div class="flex items-center justify-center">
<h1 class="font-semibold text-2xl text-white m-0 border-b-4 border-green-700">Your Coding Statistics 🤓</h1> <h1 class="font-semibold text-2xl text-white m-0 border-b-4 border-green-700">Your Coding Statistics 🤓</h1>
</div> </div>
@@ -22,7 +22,7 @@
<a href="?interval=year" class="m-1 border-b border-green-700">This Year</a> <a href="?interval=year" class="m-1 border-b border-green-700">This Year</a>
<a href="?interval=any" class="m-1 border-b border-green-700">All Time</a> <a href="?interval=any" class="m-1 border-b border-green-700">All Time</a>
</div> </div>
<main class="mt-12 flex-grow" id="grid-container"> <main class="mt-10 flex-grow" id="grid-container">
<div class="flex justify-center"> <div class="flex justify-center">
<div class="p-1"> <div class="p-1">
<div class="flex justify-center p-4 bg-white rounded shadow"> <div class="flex justify-center p-4 bg-white rounded shadow">
@@ -34,29 +34,29 @@
</div> </div>
<div class="flex flex-wrap justify-center"> <div class="flex flex-wrap justify-center">
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="projects-container"> <div class="p-4 bg-white rounded shadow m-2" id="projects-container" style="height: 300px">
<canvas id="chart-projects"></canvas> <canvas id="chart-projects"></canvas>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="os-container"> <div class="p-4 bg-white rounded shadow m-2" id="os-container" style="height: 300px">
<canvas id="chart-os"></canvas> <canvas id="chart-os"></canvas>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="editor-container"> <div class="p-4 bg-white rounded shadow m-2 relative" id="language-container" style="height: 300px">
<canvas id="chart-editor"></canvas> <canvas id="chart-language"></canvas>
</div> </div>
</div> </div>
<div class="w-full lg:w-1/2 p-1"> <div class="w-full lg:w-1/2 p-1">
<div class="p-4 bg-white rounded shadow m-2" id="language-container"> <div class="p-4 bg-white rounded shadow m-2" id="editor-container" style="height: 300px">
<canvas id="chart-language"></canvas> <canvas id="chart-editor"></canvas>
</div> </div>
</div> </div>
</div> </div>
</main> </main>
<footer class="w-full text-center text-gray-300 text-xs mt-12"> <footer class="w-full text-center text-gray-300 text-xs mt-12">
Made by <a href="https://muetsch.io" class="border-b border-green-700">Ferdinand Mütsch</a> as <a href="https://github.com/n1try/wakapi" class="border-b border-green-700">open-source</a>. Made by <a href="https://muetsch.io" class="border-b border-green-700">Ferdinand Mütsch</a> as <a href="https://github.com/muety/wakapi" class="border-b border-green-700">open-source</a>.
</footer> </footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.4/seedrandom.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.4/seedrandom.min.js"></script>
@@ -64,7 +64,8 @@
<script> <script>
let wakapiData = {} let wakapiData = {}
wakapiData.projects = {{ json .Projects }} let languageColors = {{ .LanguageColors | json }}
wakapiData.projects = {{ .Projects | json }}
wakapiData.operatingSystems = {{ .OperatingSystems | json }} wakapiData.operatingSystems = {{ .OperatingSystems | json }}
wakapiData.editors = {{ .Editors | json }} wakapiData.editors = {{ .Editors | json }}
wakapiData.languages = {{ .Languages | json }} wakapiData.languages = {{ .Languages | json }}