genofire/hs_monolith
genofire
/
hs_monolith
Archived
1
0
Fork 0

[TASK] add buy option (delete without tag - by secret)

This commit is contained in:
Martin Geno 2017-06-23 17:09:03 +02:00
parent ca0d349c04
commit 9c57445eeb
No known key found for this signature in database
GPG Key ID: F0D39A37E925E941
7 changed files with 160 additions and 23 deletions

View File

@ -8,7 +8,7 @@ fouled_deleted = "0m"
[database] [database]
type = "sqlite3" type = "sqlite3"
#logging = true logging = true
connection = "file::memory:?mode=memory&cache=shared" connection = "file::memory:?mode=memory&cache=shared"
# For Master-Slave cluster # For Master-Slave cluster
# read_connection = "" # read_connection = ""

View File

@ -20,4 +20,5 @@ func BindAPI(router *goji.Mux) {
router.HandleFunc(pat.Post("/api/goods/locking"), lockGoods) router.HandleFunc(pat.Post("/api/goods/locking"), lockGoods)
router.HandleFunc(pat.Delete("/api/goods/locking"), releaseGoods) router.HandleFunc(pat.Delete("/api/goods/locking"), releaseGoods)
router.HandleFunc(pat.Put("/api/goods/locking"), delLockedGoods)
} }

View File

@ -3,6 +3,7 @@ package http
import ( import (
"net/http" "net/http"
"time"
"github.com/genofire/hs_master-kss-monolith/lib/database" "github.com/genofire/hs_master-kss-monolith/lib/database"
lib "github.com/genofire/hs_master-kss-monolith/lib/http" lib "github.com/genofire/hs_master-kss-monolith/lib/http"
@ -45,12 +46,12 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
} }
tx := database.Write.Begin() tx := database.Write.Begin()
defer tx.Rollback()
count := int64(0) count := int64(0)
for _, good := range goods { for _, good := range goods {
if good.ProductID <= 0 { if good.ProductID <= 0 {
log.Warn("tried to log nothing") log.Warn("tried to log nothing")
tx.Rollback()
http.Error(w, "tried to log nothing", http.StatusBadRequest) http.Error(w, "tried to log nothing", http.StatusBadRequest)
return return
} }
@ -59,7 +60,6 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
db := g.FilterAvailable(tx).First(g) db := g.FilterAvailable(tx).First(g)
if db.RecordNotFound() { if db.RecordNotFound() {
log.Warn("good not found") log.Warn("good not found")
tx.Rollback()
http.Error(w, "the good was not found in database", http.StatusNotFound) http.Error(w, "the good was not found in database", http.StatusNotFound)
return return
} }
@ -69,7 +69,6 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
if db.Error != nil || db.RowsAffected != 1 { if db.Error != nil || db.RowsAffected != 1 {
http.Error(w, "the good was not found in database", http.StatusInternalServerError) http.Error(w, "the good was not found in database", http.StatusInternalServerError)
tx.Rollback()
log.Panic("there is more than one good locked: ", db.Error) log.Panic("there is more than one good locked: ", db.Error)
return return
} }
@ -85,11 +84,71 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
// Function to release locked goods // Function to release locked goods
func releaseGoods(w http.ResponseWriter, r *http.Request) { func releaseGoods(w http.ResponseWriter, r *http.Request) {
log := logger.HTTP(r)
secret := r.Header.Get("secret")
if secret == "" {
log.Warn("no secred for locking given")
http.Error(w, "no secred for locking given", http.StatusBadRequest)
return
}
log = log.WithField("lSecret", secret)
var goods []*LockGood
err := lib.Read(r, &goods)
if err != nil {
log.Warn(err.Error())
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if len(goods) <= 0 {
log.Warn("tried to log nothing")
http.Error(w, "tried to log nothing", http.StatusBadRequest)
return
}
tx := database.Write.Begin()
defer tx.Rollback()
for _, good := range goods {
if good.ProductID <= 0 {
log.Warn("tried to log nothing")
http.Error(w, "tried to release nothing", http.StatusBadRequest)
return
}
for i := 0; i < good.Count; i++ {
g := &models.Good{}
db := tx.Where(map[string]interface{}{"product_id": good.ProductID, "locked_secret": secret}).First(g)
if db.RecordNotFound() {
log.Warn("good not found")
http.Error(w, "the good was not found in database", http.StatusNotFound)
return
}
g.Unlock(secret)
db = tx.Save(g)
if db.Error != nil || db.RowsAffected != 1 {
http.Error(w, "the good was not found in database", http.StatusInternalServerError)
log.Panic("there is more than one good released: ", db.Error)
return
}
}
}
lib.Write(w, true)
tx.Commit()
log.Info("done")
}
// Function to del locked goods
func delLockedGoods(w http.ResponseWriter, r *http.Request) {
log := logger.HTTP(r) log := logger.HTTP(r)
secret := r.Header.Get("secret") secret := r.Header.Get("secret")
log = log.WithField("lSecret", secret) log = log.WithField("lSecret", secret)
db := database.Write.Model(&models.Good{}).Where(&models.Good{LockedSecret: secret}).Updates(map[string]interface{}{"locked_secret": nil, "locked_at": nil}) db := database.Write.Model(&models.Good{}).Where(&models.Good{LockedSecret: secret}).Updates(map[string]interface{}{"deleted_at": time.Now(), "locked_secret": ""})
err := db.Error err := db.Error
result := db.RowsAffected result := db.RowsAffected
@ -101,7 +160,7 @@ func releaseGoods(w http.ResponseWriter, r *http.Request) {
if result <= 0 { if result <= 0 {
log.Warn("no goods found") log.Warn("no goods found")
http.Error(w, "there are no goods to release", http.StatusNotFound) http.Error(w, "there are no goods to buy", http.StatusNotFound)
return return
} }

View File

@ -60,7 +60,54 @@ func TestLockGoods(t *testing.T) {
} }
// Function to test releaseGoods() // Function to test releaseGoods()
func TestReleaseGoods(t *testing.T) { func TestReleaseLockGoods(t *testing.T) {
assertion, router := test.Init(t)
good := &models.Good{
ProductID: 3,
Comment: "blabla",
LockedSecret: "hiddenLockTest",
}
database.Write.Create(good)
BindAPI(router)
session := test.NewSession(router)
_, w := session.JSONRequest("DELETE", "/api/goods/locking", []interface{}{LockGood{ProductID: 3, Count: 1}})
assertion.Equal(http.StatusBadRequest, w.StatusCode)
session.Header["secret"] = "hiddenLockTest"
_, w = session.JSONRequest("DELETE", "/api/goods/locking", 13)
assertion.Equal(http.StatusBadRequest, w.StatusCode)
_, w = session.JSONRequest("DELETE", "/api/goods/locking", nil)
assertion.Equal(http.StatusBadRequest, w.StatusCode)
_, w = session.JSONRequest("DELETE", "/api/goods/locking", []interface{}{LockGood{ProductID: 0, Count: 2}})
assertion.Equal(http.StatusBadRequest, w.StatusCode)
_, w = session.JSONRequest("DELETE", "/api/goods/locking", []interface{}{LockGood{ProductID: 3, Count: 2}})
assertion.Equal(http.StatusNotFound, w.StatusCode)
result, w := session.JSONRequest("DELETE", "/api/goods/locking", []interface{}{LockGood{ProductID: 3, Count: 1}})
assertion.Equal(http.StatusOK, w.StatusCode)
resultBool := result.(bool)
assertion.True(resultBool)
_, w = session.JSONRequest("DELETE", "/api/goods/locking", []interface{}{LockGood{ProductID: 3, Count: 1}})
assertion.Equal(http.StatusNotFound, w.StatusCode)
database.Close()
assertion.Panics(func() {
_, w = session.JSONRequest("DELETE", "/api/goods/locking", []interface{}{LockGood{ProductID: 3, Count: 1}})
assertion.Equal(http.StatusInternalServerError, w.StatusCode)
})
test.Close()
}
func TestDelLockGoods(t *testing.T) {
now := time.Now() now := time.Now()
assertion, router := test.Init(t) assertion, router := test.Init(t)
@ -75,18 +122,18 @@ func TestReleaseGoods(t *testing.T) {
session := test.NewSession(router) session := test.NewSession(router)
session.Header["secret"] = "a" session.Header["secret"] = "a"
result, w := session.JSONRequest("DELETE", "/api/goods/locking", nil) result, w := session.JSONRequest("PUT", "/api/goods/locking", nil)
assertion.Equal(http.StatusNotFound, w.StatusCode) assertion.Equal(http.StatusNotFound, w.StatusCode)
session.Header["secret"] = "hidden" session.Header["secret"] = "hidden"
result, w = session.JSONRequest("DELETE", "/api/goods/locking", nil) result, w = session.JSONRequest("PUT", "/api/goods/locking", nil)
assertion.Equal(http.StatusOK, w.StatusCode) assertion.Equal(http.StatusOK, w.StatusCode)
resultMap := result.(map[string]interface{}) resultMap := result.(map[string]interface{})
count := resultMap["count"] count := resultMap["count"]
assertion.Equal(float64(1), count) assertion.Equal(float64(1), count)
database.Close() database.Close()
result, w = session.JSONRequest("DELETE", "/api/goods/locking", nil) result, w = session.JSONRequest("PUT", "/api/goods/locking", nil)
assertion.Equal(http.StatusInternalServerError, w.StatusCode) assertion.Equal(http.StatusInternalServerError, w.StatusCode)
test.Close() test.Close()

View File

@ -16,6 +16,9 @@ var GoodFreshnessTemplate string
// Function to calculate a percent value from a given value and a maximum value // Function to calculate a percent value from a given value and a maximum value
func tempPercent(value, max int) int { func tempPercent(value, max int) int {
if value >= max {
return 100
}
return value * 100 / max return value * 100 / max
} }

View File

@ -13,6 +13,9 @@ func TestTempFuncs(t *testing.T) {
resultInt := tempPercent(3, 9) resultInt := tempPercent(3, 9)
assert.Equal(33, resultInt) assert.Equal(33, resultInt)
resultInt = tempPercent(13, 9)
assert.Equal(100, resultInt)
// TODO is there a other way to calc this? // TODO is there a other way to calc this?
resultFloat := tempProcessRadius(3, 9, 0) resultFloat := tempProcessRadius(3, 9, 0)
assert.Equal(float64(0), resultFloat) assert.Equal(float64(0), resultFloat)

View File

@ -31,7 +31,7 @@
<div class="default text">Select Product</div> <div class="default text">Select Product</div>
<div class="menu"> <div class="menu">
<div class="item" ng-repeat="item in products" data-value="{{item.id}}"><img class="icon" <div class="item" ng-repeat="item in products" data-value="{{item.id}}"><img class="icon"
ng-src="{{'/api/good/availablity/'+item.id| reloadSrc}}"/>{{item.title}} ng-src="{{'/api/good/availablity/'+item.id| reloadSrc}}"/>{{item.name}}
</div> </div>
</div> </div>
</div> </div>
@ -55,13 +55,14 @@
<tbody> <tbody>
<tr ng-repeat="item in cart"> <tr ng-repeat="item in cart">
<td>{{item.count}}</td> <td>{{item.count}}</td>
<td>{{getProduct(item.product_id).title}}</td> <td>{{getProduct(item.product_id).name}}</td>
<td> <td>
<div class="ui button icon" ng-click="del(item)"><i class="icon trash"></i></div> <div class="ui button icon" ng-click="del(item)"><i class="icon trash"></i></div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<button class="ui icon button" tabindex="0" ng-click="buy()"><i class="icon shop"></i>Buy</button>
</div> </div>
<footer class="ui vertical footer segment"> <footer class="ui vertical footer segment">
@ -81,7 +82,8 @@
'products': '/api-test/product/', 'products': '/api-test/product/',
'productById': '/api-test/product/%d/', 'productById': '/api-test/product/%d/',
'lockGoods': '/api/goods/locking', 'lockGoods': '/api/goods/locking',
'unlockGoods': '/api/goods/locking' 'unlockGoods': '/api/goods/locking',
'buyGoods': '/api/goods/locking',
} }
}; };
@ -127,8 +129,9 @@
}) })
.controller('MainCtrl',['$scope', '$http',function($scope, $http) { .controller('MainCtrl',['$scope', '$http',function($scope, $http) {
$scope.products = []; $scope.products = [];
$scope.goods = {count:1}; $scope.goods = {count: 1};
$scope.cart = []; $scope.cart = [];
let secret = createUUID();
$http.get(config.microservice_dependencies.products).then(function(res) { $http.get(config.microservice_dependencies.products).then(function(res) {
$scope.products = res.data; $scope.products = res.data;
@ -136,19 +139,24 @@
function load() { function load() {
const tmp = JSON.parse(localStorage.getItem("cart")); const tmp = JSON.parse(localStorage.getItem("cart"));
const secretTmp = JSON.parse(localStorage.getItem("cart"));
if(tmp) { if(tmp) {
$scope.cart = tmp.map((item) => { $scope.cart = tmp.map((item) => {
delete item.$$hashKey delete item.$$hashKey
return item; return item;
}); });
} }
if(secretTmp && secretTmp === "") {
secret = secretTmp;
} }
function save(){ }
localStorage.setItem("cart",JSON.stringify($scope.cart)); function save() {
localStorage.setItem("cart", JSON.stringify($scope.cart));
localStorage.setItem("secret", secret);
} }
load(); load();
$scope.getProduct = function getProduct(id){ $scope.getProduct = function getProduct(id) {
if(id) { if(id) {
return $scope.products.filter((item) => item.id === id)[0]; return $scope.products.filter((item) => item.id === id)[0];
} }
@ -156,7 +164,6 @@
$scope.add = function add() { $scope.add = function add() {
$scope.goods.product_id = selectedProduct; $scope.goods.product_id = selectedProduct;
const secret = createUUID();
$http({ $http({
method: 'POST', method: 'POST',
headers: { headers: {
@ -166,10 +173,9 @@
data: [$scope.goods] data: [$scope.goods]
}).then(function(res) { }).then(function(res) {
console.log('add', $scope.goods); console.log('add', $scope.goods);
$scope.goods.secret = secret;
$scope.cart.push($scope.goods); $scope.cart.push($scope.goods);
save(); save();
$scope.goods = {count:1}; $scope.goods = {count: 1};
}); });
}; };
@ -177,9 +183,11 @@
$http({ $http({
method: 'DELETE', method: 'DELETE',
headers: { headers: {
'secret': entry.secret 'secret': secret,
'Content-Type': 'application/json',
}, },
url: config.microservice_dependencies.unlockGoods url: config.microservice_dependencies.unlockGoods,
data: [entry]
}).then(function(res) { }).then(function(res) {
console.log('del', entry); console.log('del', entry);
$scope.cart = $scope.cart.filter((item) => item !== entry); $scope.cart = $scope.cart.filter((item) => item !== entry);
@ -187,9 +195,25 @@
}); });
}; };
$scope.buy = function buy() {
$http({
method: 'PUT',
headers: {
'secret': secret
},
url: config.microservice_dependencies.buyGoods,
}).then(function(res) {
console.log('buy');
$scope.reset();
},function(err) {
console.warn('buy', err);
});
};
$scope.reset = function reset() { $scope.reset = function reset() {
console.log("reset"); console.log("reset");
localStorage.setItem("cart","[]"); localStorage.setItem("cart", "[]");
localStorage.setItem("secret", createUUID());
load(); load();
}; };