[TASK] response available as json or svg template
This commit is contained in:
parent
9b10999cde
commit
21859eec82
|
@ -26,6 +26,7 @@ func main() {
|
||||||
|
|
||||||
// load config
|
// load config
|
||||||
config = models.ReadConfigFile(configFile)
|
config = models.ReadConfigFile(configFile)
|
||||||
|
web.GoodAvailablityTemplate = config.GoodAvailablityTemplate
|
||||||
|
|
||||||
log.Log.Info("Starting rezension monolith")
|
log.Log.Info("Starting rezension monolith")
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
webserver_bind = ":8080"
|
webserver_bind = ":8080"
|
||||||
|
|
||||||
|
good_availablity_template = "contrib/good_availablity.svg"
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
type = "sqlite3"
|
type = "sqlite3"
|
||||||
# logging = true
|
# logging = true
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||||
|
<g class="arcs">
|
||||||
|
<circle cx="50" cy="50" r="40" fill="#fff" stroke="#aaa" stroke-width="5"/>
|
||||||
|
<circle cx="50" cy="50" r="40" fill="none" stroke="#26b" stroke-width="5" stroke-dasharray="251.33" stroke-dashoffset="{{process_radius .Count 10 40}}"/>
|
||||||
|
</g>
|
||||||
|
<text x="50" y="58" fill="#555" text-anchor="middle" style="font: 500 20px Roboto,Verdana,sans-serif;">{{procent .Count 10}}%</text>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 495 B |
40
http/good.go
40
http/good.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
logrus "github.com/Sirupsen/logrus"
|
||||||
"goji.io/pat"
|
"goji.io/pat"
|
||||||
|
|
||||||
"github.com/genofire/hs_master-kss-monolith/lib/database"
|
"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)
|
lib.Write(w, list)
|
||||||
log.Info("done")
|
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")
|
||||||
|
}
|
||||||
|
|
|
@ -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})
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -2,7 +2,9 @@ package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/genofire/hs_master-kss-monolith/lib/database"
|
"github.com/genofire/hs_master-kss-monolith/lib/database"
|
||||||
"github.com/genofire/hs_master-kss-monolith/models"
|
"github.com/genofire/hs_master-kss-monolith/models"
|
||||||
|
@ -10,7 +12,7 @@ import (
|
||||||
"github.com/genofire/hs_master-kss-monolith/test"
|
"github.com/genofire/hs_master-kss-monolith/test"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGood(t *testing.T) {
|
func TestListGood(t *testing.T) {
|
||||||
assertion, router := test.Init(t)
|
assertion, router := test.Init(t)
|
||||||
|
|
||||||
BindAPI(router)
|
BindAPI(router)
|
||||||
|
@ -33,3 +35,45 @@ func TestGood(t *testing.T) {
|
||||||
|
|
||||||
test.Close()
|
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()
|
||||||
|
}
|
||||||
|
|
|
@ -8,4 +8,5 @@ import (
|
||||||
func BindAPI(router *goji.Mux) {
|
func BindAPI(router *goji.Mux) {
|
||||||
router.HandleFunc(pat.Get("/api/status"), status)
|
router.HandleFunc(pat.Get("/api/status"), status)
|
||||||
router.HandleFunc(pat.Get("/api/good/:productid"), listGoods)
|
router.HandleFunc(pat.Get("/api/good/:productid"), listGoods)
|
||||||
|
router.HandleFunc(pat.Get("/api/good/availablity/:productid"), getGoodAvailablity)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
|
|
||||||
var Log *logger.Logger
|
var Log *logger.Logger
|
||||||
|
|
||||||
|
type Logger logger.Entry
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Log = logger.New()
|
Log = logger.New()
|
||||||
// Enable fallback if core logger is used:
|
// Enable fallback if core logger is used:
|
||||||
|
|
|
@ -11,9 +11,10 @@ import (
|
||||||
|
|
||||||
//Config the config File of this daemon
|
//Config the config File of this daemon
|
||||||
type Config struct {
|
type Config struct {
|
||||||
WebserverBind string `toml:"webserver_bind"`
|
WebserverBind string `toml:"webserver_bind"`
|
||||||
Database database.Config `toml:"database"`
|
Database database.Config `toml:"database"`
|
||||||
GoodRelease struct {
|
GoodAvailablityTemplate string `toml:"good_availablity_template"`
|
||||||
|
GoodRelease struct {
|
||||||
After Duration `toml:"after"`
|
After Duration `toml:"after"`
|
||||||
Timer Duration `toml:"timer"`
|
Timer Duration `toml:"timer"`
|
||||||
} `toml:"good_release"`
|
} `toml:"good_release"`
|
||||||
|
|
|
@ -11,11 +11,13 @@ func TestDuration(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
var tests = []struct {
|
var tests = []struct {
|
||||||
input string
|
input interface{}
|
||||||
err string
|
err string
|
||||||
duration time.Duration
|
duration time.Duration
|
||||||
}{
|
}{
|
||||||
|
{3, "invalid duration: \"%!s(int=3)\"", 0},
|
||||||
{"", "invalid duration: \"\"", 0},
|
{"", "invalid duration: \"\"", 0},
|
||||||
|
{"am", "unable to parse duration am: strconv.Atoi: parsing \"a\": invalid syntax", 0},
|
||||||
{"1x", "invalid duration unit: x", 0},
|
{"1x", "invalid duration unit: x", 0},
|
||||||
{"1s", "", time.Second},
|
{"1s", "", time.Second},
|
||||||
{"73s", "", time.Second * 73},
|
{"73s", "", time.Second * 73},
|
||||||
|
|
|
@ -26,7 +26,7 @@ type Good struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Good) FilterAvailable(db *gorm.DB) *gorm.DB {
|
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) {
|
func (g *Good) Lock(secret string) {
|
||||||
|
|
|
@ -3,6 +3,7 @@ package models
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/genofire/hs_master-kss-monolith/lib/database"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -21,4 +22,7 @@ func TestGood(t *testing.T) {
|
||||||
|
|
||||||
good.Unlock("blub_secret")
|
good.Unlock("blub_secret")
|
||||||
assert.False(good.IsLock())
|
assert.False(good.IsLock())
|
||||||
|
|
||||||
|
assert.NotNil(good.FilterAvailable(database.Read))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue