mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
Compare commits
4 Commits
Author | SHA1 | Date | |
---|---|---|---|
4dd77ded26 | |||
0bccbffd80 | |||
2b45b064eb | |||
5d8fc99b93 |
25
README.md
25
README.md
@ -77,7 +77,12 @@ If you want to you out free, hosted cloud service, all you need to do is create
|
||||
|
||||
However, we do not guarantee data persistence, so you might potentially lose your data if the service is taken down some day ❕
|
||||
|
||||
### 🐳 Option 2: Use Docker
|
||||
### 📦 Option 2: Quick-run a Release
|
||||
```bash
|
||||
$ curl -L https://wakapi.dev/get | bash
|
||||
```
|
||||
|
||||
### 🐳 Option 3: Use Docker
|
||||
```bash
|
||||
# Create a persistent volume
|
||||
$ docker volume create wakapi-data
|
||||
@ -94,20 +99,7 @@ $ docker run -d \
|
||||
|
||||
If you want to run Wakapi on **Kubernetes**, there is [wakapi-helm-chart](https://github.com/andreymaznyak/wakapi-helm-chart) for quick and easy deployment.
|
||||
|
||||
### 📦 Option 3: Run a release
|
||||
```bash
|
||||
# Download the release and unpack it
|
||||
$ wget https://github.com/muety/wakapi/releases/download/1.20.2/wakapi_linux_amd64.zip
|
||||
$ unzip wakapi_linux_amd64.zip
|
||||
|
||||
# Optionally adapt config to your needs
|
||||
$ vi config.yml
|
||||
|
||||
# Run it
|
||||
$ ./wakapi
|
||||
```
|
||||
|
||||
### 🧑💻 Option 4: Run from source
|
||||
### 🧑💻 Option 4: Compile and run from source
|
||||
#### Prerequisites
|
||||
* Go >= 1.16 (with `$GOPATH` properly set)
|
||||
* gcc (to compile [go-sqlite3](https://github.com/mattn/go-sqlite3))
|
||||
@ -117,7 +109,6 @@ $ ./wakapi
|
||||
|
||||
#### Compile & Run
|
||||
```bash
|
||||
|
||||
# Build the executable
|
||||
$ go build -o wakapi
|
||||
|
||||
@ -129,7 +120,7 @@ $ vi config.yml
|
||||
$ ./wakapi
|
||||
```
|
||||
|
||||
**Note:** By default, the application is running in dev mode. However, it is recommended to set `ENV=production` for enhanced performance and security. To still be able to log in when using production mode, you either have to run Wakapi behind a reverse proxy, that enables for HTTPS encryption (see [best practices](#best-practices)) or set `security.insecure_cookies = true` in `config.yml`.
|
||||
**Note:** Check the comments `config.yml` for best practices regarding security configuration and more.
|
||||
|
||||
### 💻 Client Setup
|
||||
Wakapi relies on the open-source [WakaTime](https://github.com/wakatime/wakatime) client tools. In order to collect statistics to Wakapi, you need to set them up.
|
||||
|
@ -1,58 +1,58 @@
|
||||
env: development
|
||||
env: production
|
||||
|
||||
server:
|
||||
listen_ipv4: 127.0.0.1 # leave blank to disable ipv4
|
||||
listen_ipv6: ::1 # leave blank to disable ipv6
|
||||
tls_cert_path: # leave blank to not use https
|
||||
tls_key_path: # leave blank to not use https
|
||||
listen_ipv4: 127.0.0.1 # leave blank to disable ipv4
|
||||
listen_ipv6: ::1 # leave blank to disable ipv6
|
||||
tls_cert_path: # leave blank to not use https
|
||||
tls_key_path: # leave blank to not use https
|
||||
port: 3000
|
||||
base_path: /
|
||||
public_url: http://localhost:3000 # required for links (e.g. password reset) in e-mail
|
||||
public_url: http://localhost:3000 # required for links (e.g. password reset) in e-mail
|
||||
|
||||
app:
|
||||
aggregation_time: '02:15' # time at which to run daily aggregation batch jobs
|
||||
inactive_days: 7 # time of previous days within a user must have logged in to be considered active
|
||||
aggregation_time: '02:15' # time at which to run daily aggregation batch jobs
|
||||
inactive_days: 7 # time of previous days within a user must have logged in to be considered active
|
||||
custom_languages:
|
||||
vue: Vue
|
||||
jsx: JSX
|
||||
svelte: Svelte
|
||||
|
||||
db:
|
||||
host: # leave blank when using sqlite3
|
||||
port: # leave blank when using sqlite3
|
||||
user: # leave blank when using sqlite3
|
||||
password: # leave blank when using sqlite3
|
||||
name: wakapi_db.db # database name for mysql / postgres or file path for sqlite (e.g. /tmp/wakapi.db)
|
||||
dialect: sqlite3 # mysql, postgres, sqlite3
|
||||
charset: utf8mb4 # only used for mysql connections
|
||||
max_conn: 2 # maximum number of concurrent connections to maintain
|
||||
ssl: false # whether to use tls for db connection (must be true for cockroachdb) (ignored for mysql and sqlite)
|
||||
automgirate_fail_silently: false # whether to ignore schema auto-migration failures when starting up
|
||||
host: # leave blank when using sqlite3
|
||||
port: # leave blank when using sqlite3
|
||||
user: # leave blank when using sqlite3
|
||||
password: # leave blank when using sqlite3
|
||||
name: wakapi_db.db # database name for mysql / postgres or file path for sqlite (e.g. /tmp/wakapi.db)
|
||||
dialect: sqlite3 # mysql, postgres, sqlite3
|
||||
charset: utf8mb4 # only used for mysql connections
|
||||
max_conn: 2 # maximum number of concurrent connections to maintain
|
||||
ssl: false # whether to use tls for db connection (must be true for cockroachdb) (ignored for mysql and sqlite)
|
||||
automgirate_fail_silently: false # whether to ignore schema auto-migration failures when starting up
|
||||
|
||||
security:
|
||||
password_salt: # CHANGE !
|
||||
insecure_cookies: false # You need to set this to 'true' when on localhost
|
||||
password_salt: # change this
|
||||
insecure_cookies: true # should be set to 'false', except when not running with HTTPS (e.g. on localhost)
|
||||
cookie_max_age: 172800
|
||||
allow_signup: true
|
||||
expose_metrics: false
|
||||
|
||||
sentry:
|
||||
dsn: # leave blank to disable sentry integration
|
||||
enable_tracing: true # whether to use performance monitoring
|
||||
sample_rate: 0.75 # probability of tracing a request
|
||||
sample_rate_heartbeats: 0.1 # probability of tracing a heartbeat request
|
||||
dsn: # leave blank to disable sentry integration
|
||||
enable_tracing: true # whether to use performance monitoring
|
||||
sample_rate: 0.75 # probability of tracing a request
|
||||
sample_rate_heartbeats: 0.1 # probability of tracing a heartbeat request
|
||||
|
||||
mail:
|
||||
enabled: true # whether to enable mails (used for password resets, reports, etc.)
|
||||
provider: smtp # method for sending mails, currently one of ['smtp', 'mailwhale']
|
||||
smtp: # smtp settings when sending mails via smtp
|
||||
enabled: true # whether to enable mails (used for password resets, reports, etc.)
|
||||
provider: smtp # method for sending mails, currently one of ['smtp', 'mailwhale']
|
||||
smtp: # smtp settings when sending mails via smtp
|
||||
host:
|
||||
port:
|
||||
username:
|
||||
password:
|
||||
tls:
|
||||
sender: Wakapi <noreply@wakapi.dev>
|
||||
mailwhale: # mailwhale.dev settings when using mailwhale as sending service
|
||||
mailwhale: # mailwhale.dev settings when using mailwhale as sending service
|
||||
url:
|
||||
client_id:
|
||||
client_secret:
|
||||
|
23
config/db.go
23
config/db.go
@ -11,21 +11,23 @@ import (
|
||||
/*
|
||||
A quick note to myself including some clarifications about time zones.
|
||||
|
||||
- There are basically four time zones (at least in case of MySQL):
|
||||
- User
|
||||
- Wakapi (host system)
|
||||
- MySQL server
|
||||
- MySQL session
|
||||
- There are basically four time zones (at least in case of MySQL): (1) User, (2) Wakapi (host system), (3) MySQL server, (4) MySQL session
|
||||
- From my understanding, MySQL server tz is only a fallback and can be ignored as long as a connection tz is specified
|
||||
- All times are currently stored inside TIMESTAMP columns (alternatives would be DATETIME and BIGINT (plain Unix timestamps)
|
||||
- All times are currently stored inside TIMESTAMP columns (alternatives would be DATETIME and BIGINT (plain Unix timestamps))
|
||||
- TIMESTAMP columns, to my understanding, do not keep any time zone information, but only the very time they store
|
||||
- Setting a session tz will still not cause any conversions to inserted TIMESTAMP, it will only make a difference when running functions like NOW() / CURRENT_TIMESTAMP()
|
||||
- Query to insert a heartbeat involves, e.g., a `time` value like '2006-01-02 15:04:05-07:00', which doesn't contain time zone information is just saved as is
|
||||
- However, as long as the Wakapi server always runs in the same time zone, it will always parse these dates the same way (i.e. as time.Local, Europe/Berlin in case of Wakapi.dev)
|
||||
- Setting a `loc` parameter specifies what location parsed time.Time objects will be in, however, does not affect the session time zone setting (https://github.com/go-sql-driver/mysql#loc)
|
||||
- I.e., when not setting `time_zone` in addition, the session time zone will probably default to the server time zone (UTC in case of Docker)
|
||||
- Session time zone will result in conversions of inserted times from that time zone to UTC
|
||||
- From my understanding, TIMESTAMP only stores a plain time value without tz information and then converts it only for retrieval to whatever tz is set for the session
|
||||
- E.g., when inserting '2021-04-27 08:26:07' with session tz set to Europe/Berlin and then viewing the database table with UTC tz will return '2021-04-27 06:26:07' instead
|
||||
- Currently, no session tz is set (only loc), so the database server will assume it receives UTC. However, as no tz is set when retrieving the values either, they are also going to be returned just as is and as long as `loc=Local` is set properly, they are parsed in Go code with the correct time zone
|
||||
- As long as the Wakapi server always runs in the same time zone, it will always parse these dates the same way (i.e. as time.Local, Europe/Berlin in case of Wakapi.dev)
|
||||
- Using TIMESTAMP columns would only become problematic when either data needs to be migrated to a Wakapi instance in a different tz or if two consumers in different tzs were reading and writing to the same table
|
||||
- It is important to have same `time_zone` and `loc` parameters set when sending and receiving, no matter what it is (writing / reading in 'UTC' will yield same results as writing / reading in 'Europe/Berlin')
|
||||
- "The session time zone setting affects display and storage of time values that are zone-sensitive. This includes the values displayed by functions such as NOW() or CURTIME(), and values stored in and retrieved from TIMESTAMP columns. Values for TIMESTAMP columns are converted from the session time zone to UTC for storage, and from UTC to the session time zone for retrieval." (https://dev.mysql.com/doc/refman/8.0/en/time-zone-support.html)
|
||||
- Wakapi always uses time.Local for everything, i.e. all times in the database have to be interpreted with that tz
|
||||
- New heartbeats are sent with Python-like Unix timestamps, i.e. are absolute points in time as therefore not subject to any kind of tz issues
|
||||
- E.g. with Wakapi running in Europe/Berlin, 1619379014.7335322 (2021-04-25T19:30:14.733Z (UTC)) will be inserted as 2021-04-25T21:30:14.733+0200 (CEST), but obviously represents the exact same point in time no matter where it originated from
|
||||
- E.g. with Wakapi running in Europe/Berlin, 1619379014.7335322 (2021-04-25T19:30:14.733Z (UTC)) will be inserted as 2021-04-25T21:30:14.733+0200 (CEST), but obviously represents the exact same point in time no matter where it originated from
|
||||
- The reason why we need to explicitly care about tzs in the first place is the fact that user's can request their data within intervals and the results should correspond to their tz
|
||||
- Users from California wouldn't have to care about their heartbeats being stored in German time zone
|
||||
- However, they DO care when requesting their summaries
|
||||
@ -52,7 +54,6 @@ func (c *dbConfig) GetDialector() gorm.Dialector {
|
||||
}
|
||||
|
||||
func mysqlConnectionString(config *dbConfig) string {
|
||||
//location, _ := time.LoadLocation("Local")
|
||||
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=%s&sql_mode=ANSI_QUOTES",
|
||||
config.User,
|
||||
config.Password,
|
||||
|
2
main.go
2
main.go
@ -118,7 +118,7 @@ func main() {
|
||||
if config.IsDev() {
|
||||
db = db.Debug()
|
||||
}
|
||||
sqlDb, _ := db.DB()
|
||||
sqlDb, err := db.DB()
|
||||
sqlDb.SetMaxIdleConns(int(config.Db.MaxConn))
|
||||
sqlDb.SetMaxOpenConns(int(config.Db.MaxConn))
|
||||
if err != nil {
|
||||
|
@ -99,12 +99,12 @@ func (h *SummariesHandler) loadUserSummaries(r *http.Request) ([]*models.Summary
|
||||
// eventually, consider start and end params a date
|
||||
var err error
|
||||
|
||||
start, err = time.Parse(time.RFC3339, strings.Replace(startParam, " ", "+", 1))
|
||||
start, err = utils.ParseDateTimeTZ(strings.Replace(startParam, " ", "+", 1), user.TZ())
|
||||
if err != nil {
|
||||
return nil, errors.New("missing required 'start' parameter"), http.StatusBadRequest
|
||||
}
|
||||
|
||||
end, err = time.Parse(time.RFC3339, strings.Replace(endParam, " ", "+", 1))
|
||||
end, err = utils.ParseDateTimeTZ(strings.Replace(endParam, " ", "+", 1), user.TZ())
|
||||
if err != nil {
|
||||
return nil, errors.New("missing required 'end' parameter"), http.StatusBadRequest
|
||||
}
|
||||
|
12
scripts/config.yml
Normal file
12
scripts/config.yml
Normal file
@ -0,0 +1,12 @@
|
||||
# SQLite
|
||||
source:
|
||||
name: ../wakapi_db.db
|
||||
|
||||
# MySQL
|
||||
target:
|
||||
host: localhost
|
||||
port: 5432
|
||||
user: wakapi_user
|
||||
password: wakapi
|
||||
name: wakapi_local
|
||||
dialect:
|
86
scripts/get.sh
Normal file
86
scripts/get.sh
Normal file
@ -0,0 +1,86 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script installs Wakapi.
|
||||
#
|
||||
# Quick install: `curl https://wakapi.dev/get | bash`
|
||||
#
|
||||
# This script will install Wakapi to the directory you're in. To install
|
||||
# somewhere else (e.g. /usr/local/bin), cd there and make sure you can write to
|
||||
# that directory, e.g. `cd /usr/local/bin; curl https://wakapi.dev/get | sudo bash`
|
||||
#
|
||||
# Acknowledgments:
|
||||
# - Micro Editor for this script: https://micro-editor.github.io/
|
||||
# - ASCII art courtesy of figlet: http://www.figlet.org/
|
||||
|
||||
set -e -u
|
||||
|
||||
githubLatestTag() {
|
||||
finalUrl=$(curl "https://github.com/$1/releases/latest" -s -L -I -o /dev/null -w '%{url_effective}')
|
||||
printf "%s\n" "${finalUrl##*/}"
|
||||
}
|
||||
|
||||
platform=''
|
||||
machine=$(uname -m) # currently, Wakapi builds are only available for AMD64 anyway
|
||||
|
||||
if [ "${GETWAKAPI_PLATFORM:-x}" != "x" ]; then
|
||||
platform="$GETWAKAPI_PLATFORM"
|
||||
else
|
||||
case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
|
||||
"linux") platform='linux_amd64' ;;
|
||||
"msys"*|"cygwin"*|"mingw"*|*"_nt"*|"win"*) platform='win_amd64' ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if [ "x$platform" = "x" ]; then
|
||||
cat << 'EOM'
|
||||
/=====================================\\
|
||||
| COULD NOT DETECT PLATFORM |
|
||||
\\=====================================/
|
||||
|
||||
Uh oh! We couldn't automatically detect your operating system. You can file a
|
||||
bug here: https://github.com/muety/wakapi
|
||||
EOM
|
||||
exit 1
|
||||
else
|
||||
printf "Detected platform: %s\n" "$platform"
|
||||
fi
|
||||
|
||||
TAG=$(githubLatestTag muety/wakapi)
|
||||
|
||||
printf "Tag: %s" "$TAG"
|
||||
|
||||
extension='zip'
|
||||
|
||||
printf "Latest Version: %s\n" "$TAG"
|
||||
printf "Downloading https://github.com/muety/wakapi/releases/download/%s/wakapi_%s.%s\n" "$TAG" "$platform" "$extension"
|
||||
|
||||
curl -L "https://github.com/muety/wakapi/releases/download/$TAG/wakapi_$platform.$extension" > "wakapi.$extension"
|
||||
|
||||
case "$extension" in
|
||||
"zip") unzip -j "wakapi.$extension" -d "wakapi-$TAG" ;;
|
||||
"tar.gz") tar -xvzf "wakapi.$extension" "wakapi-$TAG/wakapi" ;;
|
||||
esac
|
||||
|
||||
mv "wakapi-$TAG/wakapi" ./wakapi
|
||||
mv "wakapi-$TAG/config.yml" ./config.yml
|
||||
|
||||
rm "wakapi.$extension"
|
||||
rm -rf "wakapi-$TAG"
|
||||
|
||||
cat <<-'EOM'
|
||||
|
||||
__ __ _ _
|
||||
\ \ / /_ _| | ____ _ _ __ (_)
|
||||
\ \ /\ / / _` | |/ / _` | '_ \| |
|
||||
\ V V / (_| | < (_| | |_) | |
|
||||
\_/\_/ \__,_|_|\_\__,_| .__/|_|
|
||||
|_|
|
||||
|
||||
Wakapi has been downloaded to the current directory.
|
||||
You can run it with:
|
||||
|
||||
./wakapi
|
||||
|
||||
For further instructions see https://github.com/muety/wakapi
|
||||
|
||||
EOM
|
@ -1 +1 @@
|
||||
1.26.7
|
||||
1.26.8
|
||||
|
Reference in New Issue
Block a user