Refactoring

This commit is contained in:
Daniil Gentili 2023-05-01 19:25:16 +02:00
parent 9bd3f35cc7
commit 345adcf479
Signed by: danog
GPG key ID: 8C1BE3B34B230CA7
7 changed files with 51 additions and 28 deletions

View file

@ -1,7 +1,7 @@
# options for analysis running # options for analysis running
run: run:
# timeout for analysis, e.g. 30s, 5m, default is 1m # timeout for analysis, e.g. 30s, 5m, default is 1m
timeout: 5m timeout: 10m
# output configuration options # output configuration options
output: output:

View file

@ -5,7 +5,10 @@ COPY --from=0 /usr/bin/golangci-lint /usr/bin/golangci-lint
RUN apk add --no-cache gcc libc-dev RUN apk add --no-cache gcc libc-dev
WORKDIR /app WORKDIR /app
COPY src /app/ COPY src /app/src
COPY go.mod /app/
COPY go.sum /app/
COPY .golangci.yml /app/
RUN golangci-lint run RUN golangci-lint run
RUN go test ./src/... RUN go test ./src/...

View file

@ -31,18 +31,21 @@ func (config *Config) queryHistory(entityID string, startTime, endTime time.Time
req, err := http.NewRequestWithContext( req, err := http.NewRequestWithContext(
ctx, ctx,
http.MethodGet, http.MethodGet,
config.HomeAssistant.BaseURL+ fmt.Sprintf(
"/api/history/period/"+url.QueryEscape(startTime.Format(time.RFC3339))+ "%s/api/history/period/%s?filter_entity_id=%s&end_time=%s",
"?filter_entity_id="+entityID+ config.HomeAssistant.BaseURL,
"&end_time="+url.QueryEscape(endTime.Format(time.RFC3339)), url.QueryEscape(startTime.Format(time.RFC3339)),
nil, entityID,
url.QueryEscape(endTime.Format(time.RFC3339)),
),
http.NoBody,
) )
cancel() cancel()
if err != nil { if err != nil {
return HistoryResult{}, err return HistoryResult{}, err
} }
req.Header.Add("Authorization", "Bearer "+config.HomeAssistant.ApiKey) req.Header.Add("Authorization", "Bearer "+config.HomeAssistant.APIKey)
client := &http.Client{} client := &http.Client{}
resp, err := client.Do(req) resp, err := client.Do(req)
@ -239,7 +242,7 @@ func fillMissing(days []DayData, startTime, endTime time.Time) []DayData {
previousDay time.Time previousDay time.Time
defaultDay time.Time defaultDay time.Time
previousValue float32 previousValue float32
ret []DayData ret = make([]DayData, 0, len(days))
currentTime = time.Now() currentTime = time.Now()
) )

View file

@ -27,7 +27,7 @@ type Config struct {
type HomeAssistant struct { type HomeAssistant struct {
InstallationDate time.Time `json:"installation_date"` InstallationDate time.Time `json:"installation_date"`
BaseURL string `json:"base_url"` BaseURL string `json:"base_url"`
ApiKey string `json:"api_key"` APIKey string `json:"api_key"`
} }
type Sensors struct { type Sensors struct {
PolledSmartEnergySummation string `json:"polled_smart_energy_summation"` PolledSmartEnergySummation string `json:"polled_smart_energy_summation"`
@ -54,7 +54,7 @@ func formatURL(url string) (string, error) {
} }
url = strings.TrimSuffix(url, "/") url = strings.TrimSuffix(url, "/")
test := regexp.MustCompile(`(?m)https?:\/\/[^/]*`).ReplaceAllString(url, "") test := regexp.MustCompile(`(?m)https?://[^/]*`).ReplaceAllString(url, "")
if test != "" { if test != "" {
return "", errBadHAFormat return "", errBadHAFormat
} }
@ -128,9 +128,9 @@ func (config *Config) isAuthorized(c *fiber.Ctx) bool {
return c.Cookies("admin_username") == config.Administrator.Username && c.Cookies("admin_password_hash") == config.Administrator.PasswordHash return c.Cookies("admin_username") == config.Administrator.Username && c.Cookies("admin_password_hash") == config.Administrator.PasswordHash
} }
func (config *Config) equals(new *Config) bool { func (config *Config) Equals(c *Config) bool {
return reflect.DeepEqual(new.HomeAssistant, config.HomeAssistant) && return reflect.DeepEqual(c.HomeAssistant, config.HomeAssistant) &&
reflect.DeepEqual(new.Sensors, config.Sensors) && reflect.DeepEqual(c.Sensors, config.Sensors) &&
reflect.DeepEqual(new.Administrator, config.Administrator) && reflect.DeepEqual(c.Administrator, config.Administrator) &&
reflect.DeepEqual(new.Dashboard, config.Dashboard) reflect.DeepEqual(c.Dashboard, config.Dashboard)
} }

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"database/sql"
"errors" "errors"
"log" "log"
"time" "time"
@ -62,18 +63,26 @@ func (config *Config) refreshCacheFromPast(pastTime time.Time) error {
return err return err
} }
stmtReplace, err := config.db.Prepare("INSERT OR REPLACE INTO cache(time, green_energy_percentage, energy_consumption) values(?,?,?)")
if err != nil {
return err
}
defer stmtReplace.Close()
stmtIgnore, err := config.db.Prepare("INSERT OR IGNORE INTO cache(time, green_energy_percentage, energy_consumption) values(?,?,?)")
if err != nil {
return err
}
defer stmtIgnore.Close()
for key, day := range greenEnergyPercentage { for key, day := range greenEnergyPercentage {
var action2 string var stmt *sql.Stmt
if greenEnergyPercentage[key].Value != 0 && historyPolledSmartEnergySummation[key].Value != 0 { if greenEnergyPercentage[key].Value != 0 && historyPolledSmartEnergySummation[key].Value != 0 {
action2 = "REPLACE" stmt = stmtReplace
} else { } else {
action2 = "IGNORE" stmt = stmtIgnore
} }
stmt, err := config.db.Prepare("INSERT OR " + action2 + " INTO cache(time, green_energy_percentage, energy_consumption) values(?,?,?)")
if err != nil {
return err
}
_, err = stmt.Exec(day.DayTime.Unix(), greenEnergyPercentage[key].Value, historyPolledSmartEnergySummation[key].Value) _, err = stmt.Exec(day.DayTime.Unix(), greenEnergyPercentage[key].Value, historyPolledSmartEnergySummation[key].Value)
if err != nil { if err != nil {
return err return err
@ -101,10 +110,13 @@ func (config *Config) readHistory() (History, error) {
) )
err = rows.Scan(&date, &greenEnergyPercentage, &polledSmartEnergyConsumption) err = rows.Scan(&date, &greenEnergyPercentage, &polledSmartEnergyConsumption)
if err != nil { if err != nil {
return nil, err return History{}, err
} }
ret = append(ret, HistoryEntry{date, greenEnergyPercentage, polledSmartEnergyConsumption}) ret = append(ret, HistoryEntry{date, greenEnergyPercentage, polledSmartEnergyConsumption})
} }
if rows.Err() != nil {
return History{}, rows.Err()
}
return ret, nil return ret, nil
} }

View file

@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"html"
"html/template" "html/template"
"math" "math"
"os" "os"
@ -48,7 +49,7 @@ func (config *Config) adminEndpoint(c *fiber.Ctx) error {
if err != nil { if err != nil {
return config.renderAdminPanel(c, Warning{ return config.renderAdminPanel(c, Warning{
Header: "An error occurred!", Header: "An error occurred!",
Body: err.Error(), Body: html.EscapeString(err.Error()),
}) })
} }
return config.renderAdminPanel(c, Warning{ return config.renderAdminPanel(c, Warning{
@ -81,6 +82,7 @@ func (config *Config) renderAdminPanel(c *fiber.Ctx, warning ...Warning) error {
} }
if len(warning) > 0 { if len(warning) > 0 {
// #nosec // TODO this is dangerous, even if we're escaping the only place where we're passing a non-literal
warning[0].BodyHTML = template.HTML(warning[0].Body) warning[0].BodyHTML = template.HTML(warning[0].Body)
return c.Render("admin", fiber.Map{ return c.Render("admin", fiber.Map{
"Defaults": config.getTemplateDefaults(), "Defaults": config.getTemplateDefaults(),
@ -116,7 +118,7 @@ func (config *Config) saveAdminForm(c *fiber.Ctx) error {
} }
form := &Config{ form := &Config{
HomeAssistant: HomeAssistant{ /*BaseURL to be filled later*/ ApiKey: c.FormValue("api_key"), InstallationDate: dayStart(parsedTime)}, HomeAssistant: HomeAssistant{ /*BaseURL to be filled later*/ APIKey: c.FormValue("api_key"), InstallationDate: dayStart(parsedTime)},
Sensors: Sensors{PolledSmartEnergySummation: c.FormValue("polled_smart_energy_summation"), FossilPercentage: c.FormValue("fossil_percentage")}, Sensors: Sensors{PolledSmartEnergySummation: c.FormValue("polled_smart_energy_summation"), FossilPercentage: c.FormValue("fossil_percentage")},
Administrator: Administrator{Username: c.FormValue("username") /*PasswordHash to be filled later*/}, Administrator: Administrator{Username: c.FormValue("username") /*PasswordHash to be filled later*/},
Dashboard: Dashboard{Theme: c.FormValue("theme"), Name: c.FormValue("name"), HeaderLinks: config.Dashboard.HeaderLinks, FooterLinks: config.Dashboard.FooterLinks}, Dashboard: Dashboard{Theme: c.FormValue("theme"), Name: c.FormValue("name"), HeaderLinks: config.Dashboard.HeaderLinks, FooterLinks: config.Dashboard.FooterLinks},
@ -134,7 +136,7 @@ func (config *Config) saveAdminForm(c *fiber.Ctx) error {
} }
form.HomeAssistant.BaseURL = fmtURL form.HomeAssistant.BaseURL = fmtURL
if form.equals(config) { if form.Equals(config) {
return errNoChanges return errNoChanges
} }
@ -149,7 +151,7 @@ func (config *Config) saveAdminForm(c *fiber.Ctx) error {
return err return err
} }
return os.WriteFile("config.json", js, 0o666) return os.WriteFile("config.json", js, 0o600)
} }
func averageExcludingCurrentDay(data []float32) float32 { func averageExcludingCurrentDay(data []float32) float32 {
@ -207,10 +209,12 @@ func templateDivide(num1, num2 float32) template.HTML {
powerOfTen := int(math.Floor(math.Log10(division))) powerOfTen := int(math.Floor(math.Log10(division)))
if powerOfTen >= -2 && powerOfTen <= 2 { if powerOfTen >= -2 && powerOfTen <= 2 {
// #nosec G203 // We're only printing floats
return template.HTML(strconv.FormatFloat(math.Round(division*100)/100, 'f', -1, 64)) return template.HTML(strconv.FormatFloat(math.Round(division*100)/100, 'f', -1, 64))
} }
preComma := division / math.Pow10(powerOfTen) preComma := division / math.Pow10(powerOfTen)
// #nosec G203 // We're only printing floats
return template.HTML(fmt.Sprintf("%s * 10<sup>%d</sup>", strconv.FormatFloat(math.Round(preComma*100)/100, 'f', -1, 64), powerOfTen)) return template.HTML(fmt.Sprintf("%s * 10<sup>%d</sup>", strconv.FormatFloat(math.Round(preComma*100)/100, 'f', -1, 64), powerOfTen))
} }
@ -218,5 +222,6 @@ func templateHTMLDateFormat(date time.Time) template.HTML {
if date.IsZero() { if date.IsZero() {
return "" return ""
} }
// #nosec G203 // We're only printing a date
return template.HTML(date.Format("2006-01-02")) return template.HTML(date.Format("2006-01-02"))
} }