Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Konstantinos Sideris committed May 10, 2020
0 parents commit 7dae338
Show file tree
Hide file tree
Showing 55 changed files with 10,823 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
version: 2.1
jobs:
build_server:
docker:
- image: nixos/nix:2.3
steps:
- checkout
- run:
name: build
command: nix-build --pure release.nix
build_dashboard:
working_directory: 'dashboard'
docker:
- image: circleci/node:10.16.3
steps:
- checkout
- run:
name: install-yarn
command: "sudo npm install yarn"
- restore_cache:
key: dependency-cache-{{ checksum "yarn-lock.json" }}
- run:
name: install
command: yarn install
- save_cache:
key: dependency-cache-{{ checksum "yarn-lock.json" }}
paths:
- ./node_modules
- run:
name: build
command: npm run prod
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
dist
dist-*
cabal-dev
*.o
*.hi
*.chi
*.chs.h
*.dyn_o
*.dyn_hi
.hpc
.hsenv
.cabal-sandbox/
cabal.sandbox.config
*.prof
*.aux
*.hp
*.eventlog
.stack-work/
cabal.project.local
cabal.project.local~
.HTF/
.ghc.environment.*
result


18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
db:
@docker-compose down
@docker-compose up -d

db-repl:
@pgcli -h localhost -p 5432 -u test -W test -d test

clean:
@git clean -xdf

shell:
nix-shell -p ghc cabal-install zlib postgresql

ui:
cd ./dashboard && yarn install && yarn run prod

gen-nix:
cabal2nix --no-haddock --no-check . > default.nix
126 changes: 126 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# hakatime

[![CircleCI](https://circleci.com/gh/mujx/hakatime.svg?style=svg)](https://circleci.com/gh/mujx/hakatime)
[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-blue.svg)](http://unlicense.org/)

Hakatime is a server implementation of [Wakatime](https://wakatime.com/). It
provides a single API endpoint (`/api/v1/users/current/heartbeats.bulk`) that
the Wakatime client can use to send heartbeats containing info about your coding
activity.

It comes together with a simple dashboard which provides a graphical
representation of the collected data.

## Building

### Server

Requirements:

- [GHC](https://www.haskell.org/ghc/) (tested with 8.8)
- [libpq](https://www.postgresql.org/docs/11/libpq.html) (for PostgreSQL bindings)
- [cabal-install](https://www.haskell.org/cabal/) (If building with cabal)

Using [nix](https://nixos.org/nix/) requires the least amount of manual
intervention (installing packages etc)

#### nix

```bash
nix-build release.nix
```

#### cabal

```bash
cabal build
```

### Dashboard

Requirements:

- Node.js
- npm / yarn

```bash
cd dashboard

npm install # yarn install

npm run prod # Optimized build for production usage.

npm run dev # Development server with hot reloading.
```

## Running

### Database

The server needs a database to store its data, so we will have to create a
PostgreSQL instance and initialize it with the schema found in
[docker/001-init.sql](docker/001-init.sql). You can use the provided solution
using docker-compose (`docker-compose up -d`) or do it manually, depending on
your system.

### Server

Start the server and point it to the database.

```bash
# We assume that the docker-compose setup is used.
# Change these values according to your actual setup.
export HAKA_DB_USER=test
export HAKA_DB_PASS=test
export HAKA_DB_NAME=test
export HAKA_DB_HOST=localhost
export HAKA_DB_PORT=5432

hakatime run
```

### Dashboard

1. Point your browser to [http://localhost:8080](http://localhost:8080)
2. Create a new user.
3. Create an API token and set up your Wakatime client with it.

_NOTE_: In order to start sending data from your editor, you'll have to change the
original URL on the Wakatime client with the one of your Hakatime instance.

## CLI options

```
hakatime :: v0.1.0
Usage: hakatime COMMAND
Wakatime server implementation
Available options:
-h,--help Show this help text
Available commands:
create-token Create a new auth token
create-user Create a new user account
run Start the Server
```

## Screens

### Overview

![Overview Page](img/overview.png "Overview Page")

### Projects

![Projects Page](img/projects.png "Projects Page")


## Contributing

Any kind of contribution is greatly appreciated. This could be:

- Bug fixes
- Suggesting/Implementing new features
- UI/UX improvements/suggestions
- Code refactoring
24 changes: 24 additions & 0 deletions UNLICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <http://unlicense.org/>
95 changes: 95 additions & 0 deletions app/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
module Main
( main,
)
where

import Control.Exception (try)
import Control.Monad.Trans.Except (ExceptT (..))
import qualified Haka.Authentication as Auth
import qualified Haka.Cli as Cli
import qualified Haka.Heartbeats as Heartbeats
import qualified Haka.Projects as Projects
import qualified Haka.Stats as Stats
import Haka.Types (AppCtx (..), AppM, LogState (..), runAppT)
import qualified Hasql.Pool as HasqlPool
import Katip
import Network.Wai
import Network.Wai.Handler.Warp
import Network.Wai.Logger (withStdoutLogger)
import Network.Wai.Middleware.Cors
import qualified Options.Applicative as Opt
import Servant
import System.IO (stdout)

type Static = Raw

-- Combined API type for each sub-api available.
type HakaAPI =
Heartbeats.API
:<|> Stats.API
:<|> Projects.API
:<|> Auth.API
:<|> Static

-- The API handlers should be presented in the same order as in the API type.
server :: ServerT HakaAPI AppM
server =
Heartbeats.server
:<|> Stats.server
:<|> Projects.server
:<|> Auth.server
:<|> serveDirectoryFileServer "./dashboard/dist/"

api :: Proxy HakaAPI
api = Proxy

-- | Convert our 'App' type to a 'Servant.Handler', for a given 'AppCtx'.
nt :: AppCtx -> AppM a -> Handler a
nt ctx = Handler . ExceptT . try . runAppT ctx

app :: AppCtx -> Application
app conf =
cors (const $ Just policy)
$ serve api
$ hoistServer api (nt conf) server
where
policy =
simpleCorsResourcePolicy
{ corsRequestHeaders = ["content-type", "authorization"],
-- TODO: Make this list configurable.
corsOrigins = Just (["http://localhost:8080"], True)
}

-- TODO: Write method to initialize logging based on ENV variables.
-- Env
-- LogLevel
-- Verbosity

initApp :: (AppCtx -> Application) -> IO ()
initApp unApp = do
dbsettings <- Cli.getDbSettings
dbPool <- HasqlPool.acquire (10, 1, dbsettings)
let ns = Namespace {unNamespace = ["server"]}
handleScribe <- mkHandleScribe ColorIfTerminal stdout (permitItem InfoS) V2
logEnv' <- registerScribe "stdout" handleScribe defaultScribeSettings =<< initLogEnv "hakatime" "dev"
let logState' =
LogState
{ lsNamespace = ns,
lsLogEnv = logEnv',
lsContext = mempty
}
withStdoutLogger $ \logger -> do
let conf = setPort 8080 $ setLogger logger defaultSettings
runSettings
conf
( unApp
AppCtx
{ pool = dbPool,
logState = logState'
}
)

main :: IO ()
main = do
parsedOpts <- Opt.execParser Cli.opts
Cli.handleCommand (Cli.serverCmd parsedOpts) (initApp app)
Loading

0 comments on commit 7dae338

Please sign in to comment.