From 21859eec82d581b6fe5b503f329ef388cdf38905 Mon Sep 17 00:00:00 2001 From: Martin Geno Date: Tue, 4 Apr 2017 23:21:05 +0200 Subject: [PATCH] [TASK] response available as json or svg template --- cmd/stock/main.go | 1 + config_example.conf | 2 ++ contrib/good_availablity.svg | 7 ++++++ http/good.go | 40 +++++++++++++++++++++++++++++++ http/good_temp.go | 37 +++++++++++++++++++++++++++++ http/good_temp_test.go | 17 +++++++++++++ http/good_test.go | 46 +++++++++++++++++++++++++++++++++++- http/main.go | 1 + lib/log/main.go | 2 ++ models/config.go | 7 +++--- models/duration_test.go | 4 +++- models/good.go | 2 +- models/good_test.go | 4 ++++ 13 files changed, 164 insertions(+), 6 deletions(-) create mode 100644 contrib/good_availablity.svg create mode 100644 http/good_temp.go create mode 100644 http/good_temp_test.go diff --git a/cmd/stock/main.go b/cmd/stock/main.go index 6f7442b..a1f9862 100644 --- a/cmd/stock/main.go +++ b/cmd/stock/main.go @@ -26,6 +26,7 @@ func main() { // load config config = models.ReadConfigFile(configFile) + web.GoodAvailablityTemplate = config.GoodAvailablityTemplate log.Log.Info("Starting rezension monolith") diff --git a/config_example.conf b/config_example.conf index 6581a6d..ef50a03 100644 --- a/config_example.conf +++ b/config_example.conf @@ -1,5 +1,7 @@ webserver_bind = ":8080" +good_availablity_template = "contrib/good_availablity.svg" + [database] type = "sqlite3" # logging = true diff --git a/contrib/good_availablity.svg b/contrib/good_availablity.svg new file mode 100644 index 0000000..1b94bd8 --- /dev/null +++ b/contrib/good_availablity.svg @@ -0,0 +1,7 @@ + + + + + + {{procent .Count 10}}% + diff --git a/http/good.go b/http/good.go index b6450f2..40c2739 100644 --- a/http/good.go +++ b/http/good.go @@ -4,6 +4,7 @@ import ( "net/http" "strconv" + logrus "github.com/Sirupsen/logrus" "goji.io/pat" "github.com/genofire/hs_master-kss-monolith/lib/database" @@ -31,3 +32,42 @@ func listGoods(w http.ResponseWriter, r *http.Request) { lib.Write(w, list) log.Info("done") } + +func getGoodAvailablityCount(w http.ResponseWriter, r *http.Request) (int, *logrus.Entry) { + log := logger.HTTP(r) + id, err := strconv.ParseInt(pat.Param(r, "productid"), 10, 64) + if err != nil { + log.Warn("wrong productid format") + http.Error(w, "wrong productid", http.StatusNotAcceptable) + return -1, log + } + log = log.WithField("productid", id) + product := models.Product{ID: id} + ok, err := product.Exists() + if err != nil { + log.Warn("product could not verified on other microservice") + http.Error(w, "product could not verified on other microservice", http.StatusGatewayTimeout) + } + if !ok { + log.Warn("product did not exists anymore") + http.Error(w, "product did not exists anymore", http.StatusNotFound) + return -1, log + } + var count float64 + (&models.Good{}).FilterAvailable(database.Read.Where("product_id = ?", product.ID)).Count(&count) + return int(count), log +} +func getGoodAvailablity(w http.ResponseWriter, r *http.Request) { + count, log := getGoodAvailablityCount(w, r) + if count < 0 { + return + } + log = log.WithField("type", r.Header.Get("Content-Type")) + switch r.Header.Get("Content-Type") { + case "application/json": + lib.Write(w, count) + default: + getGoodAvailablitySVG(w, count) + } + log.Info("done") +} diff --git a/http/good_temp.go b/http/good_temp.go new file mode 100644 index 0000000..58894ce --- /dev/null +++ b/http/good_temp.go @@ -0,0 +1,37 @@ +package http + +import ( + "bytes" + "io" + "net/http" + "os" + "text/template" +) + +var GoodAvailablityTemplate string + +func tempProcent(value, max int) int { + return value * 100 / max +} + +func tempProcessRadius(value, max, radius int) float64 { + return (1 - float64(value)/float64(max)) * float64(radius) * 2 * 3.14 +} + +func getGoodAvailablitySVG(w http.ResponseWriter, count int) { + + t := template.New("some") + t = t.Funcs(template.FuncMap{"procent": tempProcent, + "process_radius": tempProcessRadius, + }) + buf := bytes.NewBuffer(nil) + f, _ := os.Open(GoodAvailablityTemplate) // Error handling elided for brevity. + io.Copy(buf, f) // Error handling elided for brevity. + f.Close() + + s := string(buf.Bytes()) + t.Parse(s) + + w.Header().Set("Content-Type", "image/svg+xml") + t.Execute(w, map[string]interface{}{"Count": count}) +} diff --git a/http/good_temp_test.go b/http/good_temp_test.go new file mode 100644 index 0000000..1c685f4 --- /dev/null +++ b/http/good_temp_test.go @@ -0,0 +1,17 @@ +package http + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestTempFuncs(t *testing.T) { + assert := assert.New(t) + resultInt := tempProcent(3, 9) + assert.Equal(33, resultInt) + + // TODO is there a other way to calc this? + resultFloat := tempProcessRadius(3, 9, 0) + assert.Equal(float64(0), resultFloat) +} diff --git a/http/good_test.go b/http/good_test.go index cfe7f34..f62b152 100644 --- a/http/good_test.go +++ b/http/good_test.go @@ -2,7 +2,9 @@ package http import ( "net/http" + "net/http/httptest" "testing" + "time" "github.com/genofire/hs_master-kss-monolith/lib/database" "github.com/genofire/hs_master-kss-monolith/models" @@ -10,7 +12,7 @@ import ( "github.com/genofire/hs_master-kss-monolith/test" ) -func TestGood(t *testing.T) { +func TestListGood(t *testing.T) { assertion, router := test.Init(t) BindAPI(router) @@ -33,3 +35,45 @@ func TestGood(t *testing.T) { test.Close() } + +func TestGetGoodAvailable(t *testing.T) { + now := time.Now() + assertion, router := test.Init(t) + + BindAPI(router) + session := test.NewSession(router) + + result, w := session.JSONRequest("GET", "/api/good/availablity/a", nil) + assertion.Equal(http.StatusNotAcceptable, w.StatusCode) + + result, w = session.JSONRequest("GET", "/api/good/availablity/1", nil) + assertion.Equal(http.StatusOK, w.StatusCode) + assertion.Equal(float64(0), result) + + database.Write.Create(&models.Good{ + ProductID: 3, + Comment: "blub", + LockedAt: &now, + LockedSecret: "hidden", + }) + database.Write.Create(&models.Good{ + ProductID: 3, + Comment: "blub", + }) + database.Write.Create(&models.Good{ + ProductID: 3, + Comment: "blub", + }) + + result, w = session.JSONRequest("GET", "/api/good/availablity/3", nil) + assertion.Equal(http.StatusOK, w.StatusCode) + assertion.Equal(float64(2), result) + + req, _ := http.NewRequest("GET", "/api/good/availablity/3", nil) + req.Header.Set("Content-Type", "image/svg+xml") + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + assertion.Equal(http.StatusOK, w.StatusCode) + + test.Close() +} diff --git a/http/main.go b/http/main.go index 25f413c..a2003aa 100644 --- a/http/main.go +++ b/http/main.go @@ -8,4 +8,5 @@ import ( func BindAPI(router *goji.Mux) { router.HandleFunc(pat.Get("/api/status"), status) router.HandleFunc(pat.Get("/api/good/:productid"), listGoods) + router.HandleFunc(pat.Get("/api/good/availablity/:productid"), getGoodAvailablity) } diff --git a/lib/log/main.go b/lib/log/main.go index 83badc6..c9df52d 100644 --- a/lib/log/main.go +++ b/lib/log/main.go @@ -9,6 +9,8 @@ import ( var Log *logger.Logger +type Logger logger.Entry + func init() { Log = logger.New() // Enable fallback if core logger is used: diff --git a/models/config.go b/models/config.go index de21b2b..9bca021 100644 --- a/models/config.go +++ b/models/config.go @@ -11,9 +11,10 @@ import ( //Config the config File of this daemon type Config struct { - WebserverBind string `toml:"webserver_bind"` - Database database.Config `toml:"database"` - GoodRelease struct { + WebserverBind string `toml:"webserver_bind"` + Database database.Config `toml:"database"` + GoodAvailablityTemplate string `toml:"good_availablity_template"` + GoodRelease struct { After Duration `toml:"after"` Timer Duration `toml:"timer"` } `toml:"good_release"` diff --git a/models/duration_test.go b/models/duration_test.go index 7496877..1296054 100644 --- a/models/duration_test.go +++ b/models/duration_test.go @@ -11,11 +11,13 @@ func TestDuration(t *testing.T) { assert := assert.New(t) var tests = []struct { - input string + input interface{} err string duration time.Duration }{ + {3, "invalid duration: \"%!s(int=3)\"", 0}, {"", "invalid duration: \"\"", 0}, + {"am", "unable to parse duration am: strconv.Atoi: parsing \"a\": invalid syntax", 0}, {"1x", "invalid duration unit: x", 0}, {"1s", "", time.Second}, {"73s", "", time.Second * 73}, diff --git a/models/good.go b/models/good.go index e774f8b..56c41fd 100644 --- a/models/good.go +++ b/models/good.go @@ -26,7 +26,7 @@ type Good struct { } func (g *Good) FilterAvailable(db *gorm.DB) *gorm.DB { - return db.Where("locked_secret is NULL deleted_at is NULL and send_at is NULL") + return db.Model(g).Where("locked_secret == '' OR locked_secret is NULL") } func (g *Good) Lock(secret string) { diff --git a/models/good_test.go b/models/good_test.go index 1d0163c..af4e238 100644 --- a/models/good_test.go +++ b/models/good_test.go @@ -3,6 +3,7 @@ package models import ( "testing" + "github.com/genofire/hs_master-kss-monolith/lib/database" "github.com/stretchr/testify/assert" ) @@ -21,4 +22,7 @@ func TestGood(t *testing.T) { good.Unlock("blub_secret") assert.False(good.IsLock()) + + assert.NotNil(good.FilterAvailable(database.Read)) + }