chore: minor code enhancements

This commit is contained in:
Ferdinand Mütsch 2020-10-09 21:37:16 +02:00
parent 4d22756b8a
commit 21b822de42
17 changed files with 72 additions and 55 deletions

9
config/templates.go Normal file
View File

@ -0,0 +1,9 @@
package config
const (
IndexTemplate = "index.tpl.html"
ImprintTemplate = "imprint.tpl.html"
SignupTemplate = "signup.tpl.html"
SettingsTemplate = "settings.tpl.html"
SummaryTemplate = "summary.tpl.html"
)

View File

@ -64,7 +64,6 @@ func main() {
log.Println(err)
log.Fatal("could not connect to database")
}
// TODO: Graceful shutdown
defer db.Close()
// Migrate database schema

View File

@ -1,4 +1,5 @@
package models
func init() {
// nothing no init here, yet
}

View File

@ -3,7 +3,7 @@ package routes
import (
"fmt"
"github.com/gorilla/schema"
config2 "github.com/muety/wakapi/config"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/middlewares"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
@ -14,7 +14,7 @@ import (
)
type IndexHandler struct {
config *config2.Config
config *conf.Config
userSrvc *services.UserService
keyValueSrvc *services.KeyValueService
}
@ -24,7 +24,7 @@ var signupDecoder = schema.NewDecoder()
func NewIndexHandler(userService *services.UserService, keyValueService *services.KeyValueService) *IndexHandler {
return &IndexHandler{
config: config2.Get(),
config: conf.Get(),
userSrvc: userService,
keyValueSrvc: keyValueService,
}
@ -44,7 +44,7 @@ func (h *IndexHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
return
}
templates["index.tpl.html"].Execute(w, nil)
templates[conf.IndexTemplate].Execute(w, nil)
}
func (h *IndexHandler) GetImprint(w http.ResponseWriter, r *http.Request) {
@ -57,7 +57,7 @@ func (h *IndexHandler) GetImprint(w http.ResponseWriter, r *http.Request) {
text = data.Value
}
templates["imprint.tpl.html"].Execute(w, &struct {
templates[conf.ImprintTemplate].Execute(w, &struct {
HtmlText string
}{HtmlText: text})
}
@ -133,11 +133,11 @@ func (h *IndexHandler) GetSignup(w http.ResponseWriter, r *http.Request) {
return
}
if handleAlerts(w, r, "signup.tpl.html") {
if handleAlerts(w, r, conf.SignupTemplate) {
return
}
templates["signup.tpl.html"].Execute(w, nil)
templates[conf.SignupTemplate].Execute(w, nil)
}
func (h *IndexHandler) PostSignup(w http.ResponseWriter, r *http.Request) {
@ -152,26 +152,26 @@ func (h *IndexHandler) PostSignup(w http.ResponseWriter, r *http.Request) {
var signup models.Signup
if err := r.ParseForm(); err != nil {
respondAlert(w, "missing parameters", "", "signup.tpl.html", http.StatusBadRequest)
respondAlert(w, "missing parameters", "", conf.SignupTemplate, http.StatusBadRequest)
return
}
if err := signupDecoder.Decode(&signup, r.PostForm); err != nil {
respondAlert(w, "missing parameters", "", "signup.tpl.html", http.StatusBadRequest)
respondAlert(w, "missing parameters", "", conf.SignupTemplate, http.StatusBadRequest)
return
}
if !signup.IsValid() {
respondAlert(w, "invalid parameters", "", "signup.tpl.html", http.StatusBadRequest)
respondAlert(w, "invalid parameters", "", conf.SignupTemplate, http.StatusBadRequest)
return
}
_, created, err := h.userSrvc.CreateOrGet(&signup)
if err != nil {
respondAlert(w, "failed to create new user", "", "signup.tpl.html", http.StatusInternalServerError)
respondAlert(w, "failed to create new user", "", conf.SignupTemplate, http.StatusInternalServerError)
return
}
if !created {
respondAlert(w, "user already existing", "", "signup.tpl.html", http.StatusConflict)
respondAlert(w, "user already existing", "", conf.SignupTemplate, http.StatusConflict)
return
}

View File

@ -59,7 +59,7 @@ func loadTemplates() {
func respondAlert(w http.ResponseWriter, error, success, tplName string, status int) {
w.WriteHeader(status)
if tplName == "" {
tplName = "index.tpl.html"
tplName = config.IndexTemplate
}
templates[tplName].Execute(w, struct {
Error string

View File

@ -3,7 +3,7 @@ package routes
import (
"fmt"
"github.com/gorilla/schema"
config2 "github.com/muety/wakapi/config"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
"github.com/muety/wakapi/utils"
@ -12,7 +12,7 @@ import (
)
type SettingsHandler struct {
config *config2.Config
config *conf.Config
userSrvc *services.UserService
}
@ -20,7 +20,7 @@ var credentialsDecoder = schema.NewDecoder()
func NewSettingsHandler(userService *services.UserService) *SettingsHandler {
return &SettingsHandler{
config: config2.Get(),
config: conf.Get(),
userSrvc: userService,
}
}
@ -36,10 +36,10 @@ func (h *SettingsHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
}
// TODO: when alerts are present, other data will not be passed to the template
if handleAlerts(w, r, "settings.tpl.html") {
if handleAlerts(w, r, conf.SettingsTemplate) {
return
}
templates["settings.tpl.html"].Execute(w, data)
templates[conf.SettingsTemplate].Execute(w, data)
}
func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request) {
@ -51,32 +51,32 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request
var credentials models.CredentialsReset
if err := r.ParseForm(); err != nil {
respondAlert(w, "missing parameters", "", "settings.tpl.html", http.StatusBadRequest)
respondAlert(w, "missing parameters", "", conf.SettingsTemplate, http.StatusBadRequest)
return
}
if err := credentialsDecoder.Decode(&credentials, r.PostForm); err != nil {
respondAlert(w, "missing parameters", "", "settings.tpl.html", http.StatusBadRequest)
respondAlert(w, "missing parameters", "", conf.SettingsTemplate, http.StatusBadRequest)
return
}
if !utils.CheckPasswordBcrypt(user, credentials.PasswordOld, h.config.Security.PasswordSalt) {
respondAlert(w, "invalid credentials", "", "settings.tpl.html", http.StatusUnauthorized)
respondAlert(w, "invalid credentials", "", conf.SettingsTemplate, http.StatusUnauthorized)
return
}
if !credentials.IsValid() {
respondAlert(w, "invalid parameters", "", "settings.tpl.html", http.StatusBadRequest)
respondAlert(w, "invalid parameters", "", conf.SettingsTemplate, http.StatusBadRequest)
return
}
user.Password = credentials.PasswordNew
if err := utils.HashPassword(user, h.config.Security.PasswordSalt); err != nil {
respondAlert(w, "internal server error", "", "settings.tpl.html", http.StatusInternalServerError)
respondAlert(w, "internal server error", "", conf.SettingsTemplate, http.StatusInternalServerError)
return
}
if _, err := h.userSrvc.Update(user); err != nil {
respondAlert(w, "internal server error", "", "settings.tpl.html", http.StatusInternalServerError)
respondAlert(w, "internal server error", "", conf.SettingsTemplate, http.StatusInternalServerError)
return
}
@ -86,7 +86,7 @@ func (h *SettingsHandler) PostCredentials(w http.ResponseWriter, r *http.Request
}
encoded, err := h.config.Security.SecureCookie.Encode(models.AuthCookieKey, login)
if err != nil {
respondAlert(w, "internal server error", "", "settings.tpl.html", http.StatusInternalServerError)
respondAlert(w, "internal server error", "", conf.SettingsTemplate, http.StatusInternalServerError)
return
}
@ -110,7 +110,7 @@ func (h *SettingsHandler) PostResetApiKey(w http.ResponseWriter, r *http.Request
user := r.Context().Value(models.UserKey).(*models.User)
if _, err := h.userSrvc.ResetApiKey(user); err != nil {
respondAlert(w, "internal server error", "", "settings.tpl.html", http.StatusInternalServerError)
respondAlert(w, "internal server error", "", conf.SettingsTemplate, http.StatusInternalServerError)
return
}
@ -126,7 +126,7 @@ func (h *SettingsHandler) PostToggleBadges(w http.ResponseWriter, r *http.Reques
user := r.Context().Value(models.UserKey).(*models.User)
if _, err := h.userSrvc.ToggleBadges(user); err != nil {
respondAlert(w, "internal server error", "", "settings.tpl.html", http.StatusInternalServerError)
respondAlert(w, "internal server error", "", conf.SettingsTemplate, http.StatusInternalServerError)
return
}

View File

@ -1,7 +1,7 @@
package routes
import (
config2 "github.com/muety/wakapi/config"
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
"github.com/muety/wakapi/utils"
@ -10,13 +10,13 @@ import (
type SummaryHandler struct {
summarySrvc *services.SummaryService
config *config2.Config
config *conf.Config
}
func NewSummaryHandler(summaryService *services.SummaryService) *SummaryHandler {
return &SummaryHandler{
summarySrvc: summaryService,
config: config2.Get(),
config: conf.Get(),
}
}
@ -44,13 +44,13 @@ func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
summary, err, status := h.loadUserSummary(r)
if err != nil {
respondAlert(w, err.Error(), "", "summary.tpl.html", status)
respondAlert(w, err.Error(), "", conf.SummaryTemplate, status)
return
}
user := r.Context().Value(models.UserKey).(*models.User)
if user == nil {
respondAlert(w, "unauthorized", "", "summary.tpl.html", http.StatusUnauthorized)
respondAlert(w, "unauthorized", "", conf.SummaryTemplate, http.StatusUnauthorized)
return
}
@ -60,7 +60,7 @@ func (h *SummaryHandler) GetIndex(w http.ResponseWriter, r *http.Request) {
ApiKey: user.ApiKey,
}
templates["summary.tpl.html"].Execute(w, vm)
templates[conf.SummaryTemplate].Execute(w, vm)
}
func (h *SummaryHandler) loadUserSummary(r *http.Request) (*models.Summary, error, int) {

View File

@ -3,7 +3,7 @@ import random
import string
import sys
from datetime import datetime, timedelta
from typing import List
from typing import List, NoneType
import requests
@ -36,7 +36,7 @@ class Heartbeat:
self.is_write: bool = is_write
self.branch: str = branch
self.type: str = type
self.category: str = None
self.category: str | NoneType = None
def generate_data(n: int) -> List[Heartbeat]:
@ -45,7 +45,7 @@ def generate_data(n: int) -> List[Heartbeat]:
projects: List[str] = [randomword(random.randint(5, 10)) for _ in range(5)]
languages: List[str] = list(LANGUAGES.keys())
for i in range(n):
for _ in range(n):
p: str = random.choice(projects)
l: str = random.choice(languages)
f: str = randomword(random.randint(2, 8))
@ -77,7 +77,7 @@ def post_data_sync(data: List[Heartbeat], url: str):
def randomword(length: int) -> str:
letters = string.ascii_lowercase
return ''.join(random.choice(letters) for i in range(length))
return ''.join(random.choice(letters) for _ in range(length))
if __name__ == '__main__':

View File

@ -12,7 +12,7 @@ import (
)
const (
aggregateIntervalDays int = 1 // TODO: Make configurable
aggregateIntervalDays int = 1
)
type AggregationService struct {

View File

@ -37,6 +37,7 @@ type Interval struct {
End time.Time
}
// TODO: simplify!
func (srv *SummaryService) Construct(from, to time.Time, user *models.User, recompute bool) (*models.Summary, error) {
var existingSummaries []*models.Summary
var cacheKey string

View File

@ -242,8 +242,8 @@ function equalizeHeights() {
})
}
function getTotal(data) {
let total = data.reduce((acc, d) => acc + d.total, 0)
function getTotal(items) {
let total = items.reduce((acc, d) => acc + d.total, 0)
document.getElementById('total-span').innerText = total.toString().toHHMMSS()
}

View File

@ -1 +1 @@
1.12.2
1.12.3

View File

@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
{{ template "head.tpl.html" . }}

View File

@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
{{ template "head.tpl.html" . }}

View File

@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
{{ template "head.tpl.html" . }}
@ -86,7 +87,7 @@
<div class="flex flex-col mb-4">
<div class="flex justify-between my-2">
<div>
<img class="with-url-src" src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=blue&label=today"/>
<img class="with-url-src" src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=blue&label=today" alt="Shields.io badge"/>
</div>
<span class="with-url-inner text-xs bg-gray-900 rounded py-1 px-2 font-mono whitespace-no-wrap overflow-auto" style="max-width: 300px;">
https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:today&style=flat-square&color=blue&label=today
@ -94,7 +95,7 @@
</div>
<div class="flex justify-between my-2">
<div>
<img class="with-url-src" src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=blue&label=last 30d"/>
<img class="with-url-src" src="https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=blue&label=last 30d" alt="Shields.io badge"/>
</div>
<span class="with-url-inner text-xs bg-gray-900 rounded py-1 px-2 font-mono whitespace-no-wrap overflow-auto" style="max-width: 300px;">
https://img.shields.io/endpoint?url=%s/api/compat/shields/v1/{{ .User.ID }}/interval:30_days&style=flat-square&color=blue&label=last 30d
@ -104,7 +105,7 @@
<p>You can also add <span class="text-xs bg-gray-900 rounded py-1 px-2 font-mono">/project:your-cool-project</span> to the URL to filter by project.</p>
{{ else }}
<p>You have the ability to create badges from your coding statistics using <a href="https://shields.io" target="_blank" class="border-b border-green-800">Shields.io</a>. To do so, you need to grant public, unauthorized access to the respective endpoint.</p>
<p>You have the ability to create badges from your coding statistics using <a href="https://shields.io" target="_blank" class="border-b border-green-800" rel="noopener noreferrer">Shields.io</a>. To do so, you need to grant public, unauthorized access to the respective endpoint.</p>
<div class="flex justify-around mt-4">
<span class="font-mono font-normal bg-gray-900 p-1 rounded whitespace-no-wrap">GET /api/compat/shields/v1</span>
<button type="submit" class="py-1 px-2 rounded bg-green-700 hover:bg-green-800 text-white text-xs" title="Make endpoint public to enable badges">

View File

@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
{{ template "head.tpl.html" . }}
@ -19,9 +20,11 @@
<p class="text-sm text-gray-300">
💡 In order to use Wakapi, you need to create an account.
After successful signup, you still need to set up the <a href="https://wakatime.com" target="_blank"
rel="noopener noreferrer"
class="border-b border-green-700">WakaTime</a>
client tools.
Please refer to <a href="https://github.com/muety/wakapi#client-setup" target="_blank"
rel="noopener noreferrer"
class="border-b border-green-700">this readme section</a> for instructions.
You will be able to view you <strong>API Key</strong> once you log in.
</p>

View File

@ -1,4 +1,5 @@
<html>
<!DOCTYPE html>
<html lang="en">
{{ template "head.tpl.html" . }}
@ -69,7 +70,7 @@
</div>
<canvas id="chart-projects"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<img src="assets/images/no_data.svg" class="w-20" alt="No data"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div>
@ -82,7 +83,7 @@
</div>
<canvas id="chart-os"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<img src="assets/images/no_data.svg" class="w-20" alt="No data"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div>
@ -95,7 +96,7 @@
</div>
<canvas id="chart-language"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<img src="assets/images/no_data.svg" class="w-20" alt="No data"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div>
@ -108,7 +109,7 @@
</div>
<canvas id="chart-editor"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<img src="assets/images/no_data.svg" class="w-20" alt="No data"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div>
@ -121,7 +122,7 @@
</div>
<canvas id="chart-machine"></canvas>
<div class="hidden placeholder-container flex items-center justify-center h-full flex-col">
<img src="assets/images/no_data.svg" class="w-20"/>
<img src="assets/images/no_data.svg" class="w-20" alt="No data"/>
<span class="text-sm mt-4">No data available ...</span>
</div>
</div>