[TASK] delete good and fouled timer
This commit is contained in:
parent
64379f77ad
commit
b6ade49a41
|
@ -7,11 +7,13 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/NYTimes/gziphandler"
|
"github.com/NYTimes/gziphandler"
|
||||||
goji "goji.io"
|
goji "goji.io"
|
||||||
"goji.io/pat"
|
"goji.io/pat"
|
||||||
|
|
||||||
|
"github.com/genofire/golang-lib/worker"
|
||||||
web "github.com/genofire/hs_master-kss-monolith/http"
|
web "github.com/genofire/hs_master-kss-monolith/http"
|
||||||
"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/lib/log"
|
"github.com/genofire/hs_master-kss-monolith/lib/log"
|
||||||
|
@ -48,8 +50,12 @@ func main() {
|
||||||
}
|
}
|
||||||
grw := runtime.NewGoodReleaseWorker(config.GoodRelease)
|
grw := runtime.NewGoodReleaseWorker(config.GoodRelease)
|
||||||
cw := runtime.NewCacheWorker()
|
cw := runtime.NewCacheWorker()
|
||||||
|
fw := worker.NewWorker(config.FouledDeleter.Duration, func() { runtime.GoodFouled() })
|
||||||
go grw.Start()
|
go grw.Start()
|
||||||
go cw.Start()
|
go cw.Start()
|
||||||
|
if config.FouledDeleter.Duration != time.Duration(0) {
|
||||||
|
go fw.Start()
|
||||||
|
}
|
||||||
// Startwebsrver
|
// Startwebsrver
|
||||||
router := goji.NewMux()
|
router := goji.NewMux()
|
||||||
web.BindAPI(router)
|
web.BindAPI(router)
|
||||||
|
@ -77,6 +83,7 @@ func main() {
|
||||||
srv.Close()
|
srv.Close()
|
||||||
grw.Close()
|
grw.Close()
|
||||||
cw.Close()
|
cw.Close()
|
||||||
|
fw.Close()
|
||||||
database.Close()
|
database.Close()
|
||||||
|
|
||||||
log.Log.Info("received", sig)
|
log.Log.Info("received", sig)
|
||||||
|
|
|
@ -4,6 +4,8 @@ webroot = "webroot"
|
||||||
good_availablity_template = "contrib/good_availablity.svg"
|
good_availablity_template = "contrib/good_availablity.svg"
|
||||||
good_freshness_template = "contrib/good_freshness.svg"
|
good_freshness_template = "contrib/good_freshness.svg"
|
||||||
|
|
||||||
|
fouled_deleted = "0m"
|
||||||
|
|
||||||
[database]
|
[database]
|
||||||
type = "sqlite3"
|
type = "sqlite3"
|
||||||
# logging = true
|
# logging = true
|
||||||
|
|
|
@ -16,4 +16,5 @@ func BindAPI(router *goji.Mux) {
|
||||||
router.HandleFunc(pat.Get("/api/good/availablity/:productid"), getGoodAvailability)
|
router.HandleFunc(pat.Get("/api/good/availablity/:productid"), getGoodAvailability)
|
||||||
router.HandleFunc(pat.Get("/api/good/freshness/:goodid"), getGoodFreshness)
|
router.HandleFunc(pat.Get("/api/good/freshness/:goodid"), getGoodFreshness)
|
||||||
router.HandleFunc(pat.Post("/api/good/:productid"), http.PermissionHandler(addGood, runtime.HasPermission, runtime.PermissionCreateGood))
|
router.HandleFunc(pat.Post("/api/good/:productid"), http.PermissionHandler(addGood, runtime.HasPermission, runtime.PermissionCreateGood))
|
||||||
|
router.HandleFunc(pat.Delete("/api/good/:goodid"), http.PermissionHandler(delGood, runtime.HasPermission, runtime.PermissionDeleteGood))
|
||||||
}
|
}
|
||||||
|
|
30
http/good.go
30
http/good.go
|
@ -4,6 +4,7 @@ package http
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
"goji.io/pat"
|
"goji.io/pat"
|
||||||
|
|
||||||
|
@ -55,3 +56,32 @@ func addGood(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
log.Info("done")
|
log.Info("done")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function that returns the freshness of a good
|
||||||
|
func delGood(w http.ResponseWriter, r *http.Request) {
|
||||||
|
log := logger.HTTP(r)
|
||||||
|
id, err := strconv.ParseInt(pat.Param(r, "goodid"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Warn("wrong goodid format")
|
||||||
|
http.Error(w, "the good id has a false format", http.StatusNotAcceptable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log = log.WithField("goodid", id)
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
var good models.Good
|
||||||
|
good.ID = id
|
||||||
|
good.ManuelleDelete = true
|
||||||
|
good.DeletedAt = &now
|
||||||
|
db := database.Write.Save(&good)
|
||||||
|
if db.Error != nil {
|
||||||
|
log.Warnf("good could not delete: %s", db.Error)
|
||||||
|
http.Error(w, "the good could not delete", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if db.RowsAffected != 1 {
|
||||||
|
log.Warnf("good could not found: %s", db.Error)
|
||||||
|
http.Error(w, "the good could not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -72,3 +72,45 @@ func TestAddGood(t *testing.T) {
|
||||||
|
|
||||||
test.Close()
|
test.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to test delGood()
|
||||||
|
func TestDelGood(t *testing.T) {
|
||||||
|
assertion, router := test.Init(t)
|
||||||
|
|
||||||
|
BindAPI(router)
|
||||||
|
runtime.PermissionURL = "http://localhost:8080/api-test/session/%s/%d/"
|
||||||
|
session := test.NewSession(router)
|
||||||
|
|
||||||
|
good := models.Good{
|
||||||
|
ID: 3,
|
||||||
|
Comment: "blub",
|
||||||
|
}
|
||||||
|
|
||||||
|
database.Write.Create(&good)
|
||||||
|
|
||||||
|
_, w := session.JSONRequest("DELETE", "/api/good/1", nil)
|
||||||
|
assertion.Equal(http.StatusNonAuthoritativeInfo, w.StatusCode)
|
||||||
|
|
||||||
|
session.Login()
|
||||||
|
|
||||||
|
_, w = session.JSONRequest("DELETE", "/api/good/a", nil)
|
||||||
|
assertion.Equal(http.StatusNotAcceptable, w.StatusCode)
|
||||||
|
|
||||||
|
_, w = session.JSONRequest("DELETE", "/api/good/3", nil)
|
||||||
|
assertion.Equal(http.StatusOK, w.StatusCode)
|
||||||
|
|
||||||
|
_, w = session.JSONRequest("DELETE", "/api/good/3", nil)
|
||||||
|
assertion.Equal(http.StatusNotFound, w.StatusCode)
|
||||||
|
|
||||||
|
database.Close()
|
||||||
|
|
||||||
|
_, w = session.JSONRequest("DELETE", "/api/good/1", nil)
|
||||||
|
assertion.Equal(http.StatusInternalServerError, w.StatusCode)
|
||||||
|
|
||||||
|
session.Logout()
|
||||||
|
|
||||||
|
_, w = session.JSONRequest("DELETE", "/api/good/1", nil)
|
||||||
|
assertion.Equal(http.StatusForbidden, w.StatusCode)
|
||||||
|
|
||||||
|
test.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ type Config struct {
|
||||||
GoodAvailabilityTemplate string `toml:"good_availablity_template"`
|
GoodAvailabilityTemplate string `toml:"good_availablity_template"`
|
||||||
GoodFreshnessTemplate string `toml:"good_freshness_template"`
|
GoodFreshnessTemplate string `toml:"good_freshness_template"`
|
||||||
|
|
||||||
|
FouledDeleter Duration `toml:"fouled_deleted"`
|
||||||
|
|
||||||
// URLs to other microservices that this services uses
|
// URLs to other microservices that this services uses
|
||||||
MicroserviceDependencies struct {
|
MicroserviceDependencies struct {
|
||||||
Product string `toml:"product"`
|
Product string `toml:"product"`
|
||||||
|
|
|
@ -24,7 +24,8 @@ type Good struct {
|
||||||
LockedSecret string `json:"-"`
|
LockedSecret string `json:"-"`
|
||||||
// Make it unusable
|
// Make it unusable
|
||||||
DeletedAt *time.Time `json:"-"`
|
DeletedAt *time.Time `json:"-"`
|
||||||
Sended bool `json:"-"`
|
ManuelleDelete bool `json:"-"`
|
||||||
|
FouledDelete bool `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to generate a database and select locked goods with a filter
|
// Function to generate a database and select locked goods with a filter
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Package with supporting functionality to run the microservice
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/genofire/hs_master-kss-monolith/lib/database"
|
||||||
|
"github.com/genofire/hs_master-kss-monolith/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Function to remove automaticle goods after the are fouled
|
||||||
|
func GoodFouled() int {
|
||||||
|
var goods []*models.Good
|
||||||
|
var g models.Good
|
||||||
|
g.FilterAvailable(database.Read).Where("fouled_at <= ?", time.Now()).Find(&goods)
|
||||||
|
now := time.Now()
|
||||||
|
|
||||||
|
for _, good := range goods {
|
||||||
|
good.FouledDelete = true
|
||||||
|
good.DeletedAt = &now
|
||||||
|
database.Write.Save(&good)
|
||||||
|
}
|
||||||
|
return len(goods)
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
// Package with supporting functionality to run the microservice
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/genofire/hs_master-kss-monolith/lib/database"
|
||||||
|
"github.com/genofire/hs_master-kss-monolith/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Function to test the unlocking of goods
|
||||||
|
func TestFouledDelete(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
database.Open(database.Config{
|
||||||
|
Type: "sqlite3",
|
||||||
|
Logging: true,
|
||||||
|
Connection: ":memory:",
|
||||||
|
})
|
||||||
|
|
||||||
|
now := time.Now().Add(-time.Hour * 48)
|
||||||
|
good := models.Good{
|
||||||
|
FouledAt: &now,
|
||||||
|
}
|
||||||
|
database.Write.Create(&good)
|
||||||
|
|
||||||
|
good = models.Good{
|
||||||
|
FouledAt: &now,
|
||||||
|
}
|
||||||
|
database.Write.Create(&good)
|
||||||
|
|
||||||
|
count := GoodFouled()
|
||||||
|
assert.Equal(2, count, "not fouled")
|
||||||
|
|
||||||
|
good = models.Good{
|
||||||
|
FouledAt: &now,
|
||||||
|
}
|
||||||
|
database.Write.Create(&good)
|
||||||
|
|
||||||
|
now = time.Now().Add(time.Hour * 48)
|
||||||
|
good = models.Good{
|
||||||
|
FouledAt: &now,
|
||||||
|
}
|
||||||
|
database.Write.Create(&good)
|
||||||
|
|
||||||
|
count = GoodFouled()
|
||||||
|
assert.Equal(1, count, "fouled")
|
||||||
|
|
||||||
|
database.Close()
|
||||||
|
}
|
|
@ -12,12 +12,12 @@ import (
|
||||||
// Function to create a Worker and to unlock goods
|
// Function to create a Worker and to unlock goods
|
||||||
func NewGoodReleaseWorker(grc models.GoodReleaseConfig) *worker.Worker {
|
func NewGoodReleaseWorker(grc models.GoodReleaseConfig) *worker.Worker {
|
||||||
return worker.NewWorker(grc.Every.Duration, func() {
|
return worker.NewWorker(grc.Every.Duration, func() {
|
||||||
goodRelease(grc.After.Duration)
|
GoodRelease(grc.After.Duration)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to unlock goods after a specified time
|
// Function to unlock goods after a specified time
|
||||||
func goodRelease(unlockAfter time.Duration) int64 {
|
func GoodRelease(unlockAfter time.Duration) int64 {
|
||||||
res := database.Write.Model(&models.Good{}).Where("locked_secret is not NULL and locked_at < ?", time.Now().Add(-unlockAfter)).Updates(map[string]interface{}{"locked_secret": "", "locked_at": nil})
|
res := database.Write.Model(&models.Good{}).Where("locked_secret is not NULL and locked_at < ?", time.Now().Add(-unlockAfter)).Updates(map[string]interface{}{"locked_secret": "", "locked_at": nil})
|
||||||
return res.RowsAffected
|
return res.RowsAffected
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,13 +25,13 @@ func TestGoodRelease(t *testing.T) {
|
||||||
LockedSecret: "never used",
|
LockedSecret: "never used",
|
||||||
}
|
}
|
||||||
database.Write.Create(&good)
|
database.Write.Create(&good)
|
||||||
count := goodRelease(time.Duration(3) * time.Second)
|
count := GoodRelease(time.Duration(3) * time.Second)
|
||||||
assert.Equal(int64(0), count, "no locked in timeout")
|
assert.Equal(int64(0), count, "no locked in timeout")
|
||||||
|
|
||||||
older := now.Add(-time.Duration(10) * time.Minute)
|
older := now.Add(-time.Duration(10) * time.Minute)
|
||||||
good.LockedAt = &older
|
good.LockedAt = &older
|
||||||
database.Write.Save(&good)
|
database.Write.Save(&good)
|
||||||
count = goodRelease(time.Duration(3) * time.Second)
|
count = GoodRelease(time.Duration(3) * time.Second)
|
||||||
assert.Equal(int64(1), count, "unlock after timeout")
|
assert.Equal(int64(1), count, "unlock after timeout")
|
||||||
|
|
||||||
grw := NewGoodReleaseWorker(models.GoodReleaseConfig{
|
grw := NewGoodReleaseWorker(models.GoodReleaseConfig{
|
||||||
|
@ -41,4 +41,6 @@ func TestGoodRelease(t *testing.T) {
|
||||||
go grw.Start()
|
go grw.Start()
|
||||||
time.Sleep(time.Duration(15) * time.Millisecond)
|
time.Sleep(time.Duration(15) * time.Millisecond)
|
||||||
grw.Close()
|
grw.Close()
|
||||||
|
|
||||||
|
database.Close()
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue