genofire/hs_monolith
genofire
/
hs_monolith
Archived
1
0
Fork 0

[Task]: add comments + comment quality saving

This commit is contained in:
mlabusch 2017-06-21 15:25:18 +02:00
parent d38839c4f9
commit 99d62fcb47
47 changed files with 2435 additions and 2476 deletions

View File

@ -1,5 +1,5 @@
# Stock-Microservice
This is a microservice cutted out of a [Monolith](https://gitlab.com/matthiasstock/monolith).
This microservice is cut out of a [Monolith](https://gitlab.com/matthiasstock/monolith).
[![Build Status](https://travis-ci.org/genofire/hs_master-kss-monolith.svg?branch=master)](https://travis-ci.org/genofire/hs_master-kss-monolith) [![CircleCI](https://circleci.com/gh/genofire/hs_master-kss-monolith/tree/master.svg?style=svg)](https://circleci.com/gh/genofire/hs_master-kss-monolith/tree/master) [![Coverage Status](https://coveralls.io/repos/github/genofire/hs_master-kss-monolith/badge.svg?branch=master)](https://coveralls.io/github/genofire/hs_master-kss-monolith?branch=master) [![GoDoc](https://godoc.org/github.com/genofire/hs_master-kss-monolith?status.svg)](https://godoc.org/github.com/genofire/hs_master-kss-monolith)
@ -9,14 +9,14 @@ This is a microservice cutted out of a [Monolith](https://gitlab.com/matthiassto
* [Easy dummy Shop-Cart in browser-cache](https://stock.pub.warehost.de/dummy_cart/)
## Features of this stock mircoservice
* The main functionality of the microservice is to store the goods with their storage location and the date, when they are too old to be sell.
* The main functionality of the microservice is to store goods with their storage location and the date, when they are too old to sell.
* Functionality of the admin frontend
* Add new goods to the stock
* Manually remove a single goods from the stock, for example when they are rancid
* Remove single goods from the stock, when they are send to a costumer
* Block goods from the stock, when a costumer adds them to his cart
* Manually remove a single good from the stock, for example when it is fouled
* Remove a single good from the stock, when it is send to a costumer
* Block goods from the stock, when a costumer adds them to his shop-cart
* Functionality of the costumer frontend
* Show the store with a traffic light food labelling
* Show the stock of a product with a traffic light food labelling system
* Optional Features
* Admin frontend: display of a statistic on the amount and average of goods in the stock
* Admin frontend: display a traffic light food labelling for each good, which indicates whether the good is too old
* Admin frontend: display of a statistic of the current and average amount of goods in the stock
* Admin frontend: display a traffic light food labelling system for each good, which indicates whether the good is too old

View File

@ -1,4 +1,4 @@
// Package that containts the cmd binary of the microservice to run it
// Package that contains the cmd binary of the microservice to run it
package main
import (
@ -50,13 +50,15 @@ func main() {
}
grw := runtime.NewGoodReleaseWorker(config.GoodRelease)
cw := runtime.NewCacheWorker()
fw := worker.NewWorker(config.FouledDeleter.Duration, func() { runtime.GoodFouled() })
fw := worker.NewWorker(config.FouledDeleter.Duration, func() {
runtime.GoodFouled()
})
go grw.Start()
go cw.Start()
if config.FouledDeleter.Duration != time.Duration(0) {
go fw.Start()
}
// Startwebsrver
// Start webserver
router := goji.NewMux()
web.BindAPI(router)

View File

@ -1,24 +0,0 @@
# bind the webserver to a dynamic ports
webserver_bind = ":65000"
webroot = "webroot"
good_availablity_template = "contrib/good_availablity.svg"
[database]
type = "sqlite3"
# logging = true
connection = "file::memory:?mode=memory&cache=shared"
# For Master-Slave cluster
# read_connection = ""
[good_release]
every = "5m"
after = "30m"
[cache_clean]
every = "5m"
after = "30m"
[microservice_dependencies]
product = "http://localhost:65000/api-test/product/%d/"
permission = "http://localhost:65000/api-test/session/%s/%d/"

View File

@ -1,8 +1,7 @@
<!-- SVG to show the current stock with a traffic light food labeling system -->
<!-- Used functions -->
<!-- process_radius ANZAHL MAXANZAHL RADIUS -->
<!-- procent ANZAHL MAXANZAHL -->
<!-- ex. {procent .Count 10}%-->
<!-- procent ANZAHL MAXANZAHL ex. {procent .Count 10}%-->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<g class="arcs">
{{if eq .Count 0}}

Before

Width:  |  Height:  |  Size: 854 B

After

Width:  |  Height:  |  Size: 840 B

View File

@ -58,7 +58,8 @@ Die Packages und Go-Files des Application Layers umfassen die Logik des Microser
\paragraph{http:} Go-Files, die die Anwendungslogik (Funktionen) und die API-Routen beinhalten
\begin{itemize}
\item \texttt{bindapi.go}: Funktionen, die für das Binden der URL-Pfade notwendig sind
\item \texttt{good.go}: Funktionen für die Verwaltung der Waren im Warenbestand
\item \texttt{good.go}: Funktionen für das Hinzufügen von Waren zum Warenbestand und die Anzeige, ob eine Ware abgelaufen ist
\item \texttt{good\_lock.go}: Funktionen für das Blockieren von Waren, die sich im Warenkorb befinden
\item \texttt{good\_show.go}: Funktionen für die Auflistung und Zählung der vorhandenen Waren sowie die Feststellung ihrer Verfügbarkeit
\item \texttt{good\_temp.go}: Hilfsfunktionen, die für die Darstellung des Warenbestandes als Ampel im Kunden-Frontend benötigt werden
\item \texttt{status.go}: Funktion, die den Status des Microservice abfragt
@ -77,9 +78,9 @@ Die Packages und Go-Files des Application Layers umfassen die Logik des Microser
\begin{itemize}
\item \texttt{auth.go}: Hilfsfunktionen zur Prüfung, ob eine Berechtigung für den Zugriff vorliegt
\item \texttt{cache\_worker.go}: Hilfsfunktionen für das Löschen und Anlegen von Cache-Workers
\item \texttt{good\_fouled.go}: Hilfsfunktion, um abgelaufene Waren automatisch aus dem Warenbestand zu entfernen
\item \texttt{good\_release.go}: Hilfsfunktionen zum Blockieren und Entsperren von Waren
\item \texttt{productcache.go}: Hilfsfunktionen zum Anlegen eines Caches für Produkte
\item \texttt{runtime.go}: Übergreifende Hintergrundfunktionalitäten
\end{itemize}
@ -122,7 +123,7 @@ connection = "file::memory:?mode=memory&cache=shared"
\newpage
\subsection{Integrierte Tests}
\label{subsec: Integrierte Test}
Neben den bisherigen Packages, die bereits Whitebox-Tests umfassen, ist in dem Package \textbf{\texttt{test}} ein weiteres Go-File (\texttt{testRest.go}) enthalten. Dieses setzt einen Test des Webservers um, bei dem auf Testdaten eines Produktkataloges zurückgegriffen wird. Mit Hilfe der integrierten Tests wird in der hier beschriebenen Version eine Code-Coverage von 100\% erreicht, das heißt jedes Stück Code wird mindestens einmal zur Ausführung gebracht.
Neben den bisherigen Packages, die bereits Whitebox-Tests umfassen, ist in dem Package \textbf{\texttt{test}} ein weiteres Go-File (\texttt{testrest.go}) enthalten. Dieses setzt einen Test des Webservers um, bei dem auf Testdaten eines Produktkataloges zurückgegriffen wird. Mit Hilfe der integrierten Tests wird in der hier beschriebenen Version eine Code-Coverage von 100\% erreicht, das heißt jedes Stück Code wird mindestens einmal zur Ausführung gebracht.
\subsection{Anpassung des Monolithen}
\label{subsec: Anpassung des Monolithen}

View File

@ -29,7 +29,7 @@ func addGood(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(pat.Param(r, "productid"), 10, 64)
if err != nil {
log.Warn("false product id format")
http.Error(w, "the product id is false", http.StatusNotAcceptable)
http.Error(w, "the product id has a false format", http.StatusNotAcceptable)
return
}
log = log.WithField("productid", id)
@ -40,7 +40,7 @@ func addGood(w http.ResponseWriter, r *http.Request) {
return
}
if !ok {
log.Warn("false product, product not found")
log.Warn("product not found")
http.Error(w, "the product was not found", http.StatusNotFound)
return
}
@ -66,7 +66,7 @@ func addGood(w http.ResponseWriter, r *http.Request) {
}
if db.Error != nil {
log.Error("database not able to write", db.Error)
log.Error("database unable to write", db.Error)
http.Error(w, "the product could not be written into the database", http.StatusInternalServerError)
}
lib.Write(w, &obj)
@ -90,8 +90,8 @@ func delGood(w http.ResponseWriter, r *http.Request) {
good.ID = id
db := good.FilterAvailable(database.Read).First(&good)
if db.RecordNotFound() {
log.Warnf("good could not found: %s", db.Error)
http.Error(w, "the good could not found", http.StatusNotFound)
log.Warnf("could not find good: %s", db.Error)
http.Error(w, "the good was not found", http.StatusNotFound)
return
}
good.ManuelleDelete = true
@ -99,8 +99,8 @@ func delGood(w http.ResponseWriter, r *http.Request) {
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)
log.Warnf("could not delete good: %s", db.Error)
http.Error(w, "the good could not be deleted", http.StatusInternalServerError)
return
}
log.Info("done")

View File

@ -1,3 +1,4 @@
// Package that contains all api routes of this microservice
package http
import (
@ -14,6 +15,7 @@ type LockGood struct {
Count int `json:"count"`
}
// Function to lock goods
func lockGoods(w http.ResponseWriter, r *http.Request) {
log := logger.HTTP(r)
secret := r.Header.Get("secret")
@ -37,8 +39,8 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
}
if len(goods) <= 0 {
log.Warn("try to log nothing")
http.Error(w, "try to log nothing", http.StatusBadRequest)
log.Warn("tried to log nothing")
http.Error(w, "tried to log nothing", http.StatusBadRequest)
return
}
@ -47,9 +49,9 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
for _, good := range goods {
if good.ProductID <= 0 {
log.Warn("try to log nothing")
log.Warn("tried to log nothing")
tx.Rollback()
http.Error(w, "try to log nothing", http.StatusBadRequest)
http.Error(w, "tried to log nothing", http.StatusBadRequest)
return
}
for i := 0; i < good.Count; i++ {
@ -68,7 +70,7 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
if db.Error != nil || db.RowsAffected != 1 {
http.Error(w, "the good was not found in database", http.StatusInternalServerError)
tx.Rollback()
log.Panic("more then one good locked: ", db.Error)
log.Panic("there is more than one good locked: ", db.Error)
return
}
count += 1
@ -81,6 +83,7 @@ func lockGoods(w http.ResponseWriter, r *http.Request) {
}
// Function to release locked goods
func releaseGoods(w http.ResponseWriter, r *http.Request) {
log := logger.HTTP(r)
secret := r.Header.Get("secret")
@ -91,14 +94,14 @@ func releaseGoods(w http.ResponseWriter, r *http.Request) {
result := db.RowsAffected
if err != nil {
log.Warn("database error during release goods: ", err)
http.Error(w, "secret could not validate", http.StatusInternalServerError)
log.Warn("database error during the release of goods: ", err)
http.Error(w, "the secret could not be validated", http.StatusInternalServerError)
return
}
if result <= 0 {
log.Warn("no goods found")
http.Error(w, "no goods found to release", http.StatusNotFound)
http.Error(w, "there are no goods to release", http.StatusNotFound)
return
}

View File

@ -11,6 +11,7 @@ import (
"github.com/genofire/hs_master-kss-monolith/test"
)
// Function to test lockGoods()
func TestLockGoods(t *testing.T) {
assertion, router := test.Init(t)
good := &models.Good{
@ -58,6 +59,7 @@ func TestLockGoods(t *testing.T) {
test.Close()
}
// Function to test releaseGoods()
func TestReleaseGoods(t *testing.T) {
now := time.Now()
assertion, router := test.Init(t)

View File

@ -38,7 +38,7 @@ func TestListGood(t *testing.T) {
test.Close()
}
// Function to getGoodAvailability() and getGoodAvailabilityCount()
// Function to test getGoodAvailability() and getGoodAvailabilityCount()
func TestGetGoodAvailable(t *testing.T) {
now := time.Now()
assertion, router := test.Init(t)
@ -99,7 +99,7 @@ func TestGetGoodAvailable(t *testing.T) {
}
// Function to getGoodFreshness()
// Function to test getGoodFreshness()
func TestGetGoodFreshness(t *testing.T) {
now := time.Now().Add(36 * time.Hour)
assertion, router := test.Init(t)

View File

@ -9,12 +9,12 @@ import (
"text/template"
)
// Path to the svg image template, that shows the availablity or freshness of a given good
// Path to the svg image template, that shows the availability or freshness of a given good
// with a traffic light food labeling system
var GoodAvailabilityTemplate string
var GoodFreshnessTemplate string
// Function to calculate a percent value from a given value and an maximum value
// Function to calculate a percent value from a given value and a maximum value
func tempPercent(value, max int) int {
return value * 100 / max
}

View File

@ -73,14 +73,14 @@ func TestAddGood(t *testing.T) {
runtime.HasPermission("testsessionkey", runtime.PermissionCreateGood)
runtime.CleanCache()
// Test gatewaytimeout on product exists
// Test the gatewaytimeout on product exists
_, w = session.JSONRequest("POST", "/api/good/1", good)
assertion.Equal(http.StatusGatewayTimeout, w.StatusCode)
time.Sleep(time.Duration(10) * time.Millisecond)
runtime.CleanCache()
// Test gatewaytimeout on permission exists
// Test the gatewaytimeout on permission exists
_, w = session.JSONRequest("POST", "/api/good/1", good)
assertion.Equal(http.StatusGatewayTimeout, w.StatusCode)

View File

@ -23,13 +23,13 @@ var (
// Configuration of the database connection
type Config struct {
// type of the database, currently supports sqlite and postgres
// Type of the database (currently supports sqlite and postgres)
Type string
// connection configuration
// Connection configuration
Connection string
// create another connection for reading only
// Create another connection for reading only
ReadConnection string
// enable logging of the generated sql string
// Enable logging of the generated sql string
Logging bool
}

View File

@ -1,4 +1,4 @@
// Package with a lib for cronjobs to run in background
// Package with a lib for cronjobs to run in the background
package worker
import "time"

View File

@ -1,4 +1,4 @@
// Package with a lib for cronjobs to run in background
// Package with a lib for cronjobs to run in the background
package worker
import (

View File

@ -22,14 +22,14 @@ type Config struct {
GoodRelease GoodReleaseConfig `toml:"good_release"`
CacheClean CacheWorkerConfig `toml:"cache_clean"`
// path to the svg image templates to show the availablity and freshness
// path to the SVG image templates to show the availability and freshness
// of a given good with a traffic light food labeling system
GoodAvailabilityTemplate string `toml:"good_availablity_template"`
GoodFreshnessTemplate string `toml:"good_freshness_template"`
FouledDeleter Duration `toml:"fouled_deleted"`
// URLs to other microservices that this services uses
// URLs to other microservices, which this service uses
MicroserviceDependencies struct {
Product string `toml:"product"`
Permission string `toml:"permission"`
@ -48,7 +48,7 @@ type CacheWorkerConfig struct {
type GoodReleaseConfig struct {
// Run worker every Duration
Every Duration `toml:"every"`
// Unlock those which are not used since Duration
// Unlock those, which are not used since Duration
After Duration `toml:"after"`
}

View File

@ -10,7 +10,7 @@ import (
"github.com/genofire/hs_master-kss-monolith/lib/database"
)
// Goods managed in this stock microservice
// Type of goods managed in this stock microservice
type Good struct {
ID int64 `json:"id"`
ProductID int64 `json:"product_id"`

View File

@ -1,4 +0,0 @@
// Package with the mostly static content (models) of this microservice
package models
// Store all the structs

View File

@ -86,6 +86,7 @@ public class DataTransferObjectFactory {
ProductI18n i18n = product.getI18n().get(locale.getLanguage());
String price = numberFormat.format(i18n.getPrice());
ProductDTO productDTO = new ProductDTO();
// Addition: productDTO.setID()
productDTO.setId(product.getId());
productDTO.setItemNumber(product.getItemNumber());
productDTO.setUnit(product.getUnit());

View File

@ -17,16 +17,18 @@ public class HomepageController {
@Autowired
private ShopService shopService;
// Addition: contant with the address of the stock microservice adminfrontend
private final String STOCKADMINFRONTENDTEMPLATE = "https://stock.pub.warehost.de/index.html";
/**
* Redirect
* Redirect to stock admin frontend
*
* @param model Template model
* @return The constant template name for the stock admin frontend.
*/
@RequestMapping(value = "/stockadmin", method = RequestMethod.GET)
public String redirect(Model model) {return "redirect:"+ this.STOCKADMINFRONTENDTEMPLATE;
public String redirect(Model model) {
return "redirect:" + this.STOCKADMINFRONTENDTEMPLATE;
}
/**

View File

@ -15,6 +15,7 @@ public class ProductDTO {
private String description;
private List<ReviewDTO> reviews;
// Addition: int id, getId() and setID()
public int getId() {
return id;
}

View File

@ -31,7 +31,10 @@
</div>
<div class="col-md-8">
<h2 th:text="${product.name}">Product Name</h2>
<!-- Addition: traffic light food labeling system of the stock microservice -->
<img width="10%" class="icon" th:src="${'https://stock.pub.warehost.de/api/good/availablity/'+product.id}"/>
<p class="text-info text-uppercase" th:text="${product.price}">0,00 Euro</p>
<p class="lead" th:text="${product.description}">Description.</p>
<div th:replace="fragments/reviews :: reviews"></div>

View File

@ -1,32 +0,0 @@
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/skeleton :: head">
<meta charset="utf-8" />
<meta http-equiv="refresh" content="5; URL=http://localhost:65000/"/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="../static/css/bootstrap.min.css" rel="stylesheet" />
<link href="../static/css/mosh.css" rel="stylesheet" />
</head>
<body>
<div th:replace="fragments/skeleton :: navigation">
<div class="container">
<nav>Navigation</nav>
</div>
</div>
<div class="container product">
<div class="row info">
<p align="center"><a href="http://localhost:65000/">If the automatic redirection to the stock management admin
front end does not work, click here.</a></p>
</div>
<footer th:replace="fragments/skeleton :: footer">
<p>&copy; 2017</p>
</footer>
</div>
<script src="../static/js/jquery-3.1.1.min.js"
th:src="@{/js/jquery-3.1.1.min.js}"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="../static/js/bootstrap.min.js"
th:src="@{/js/bootstrap.min.js}"></script>
</body>
</html>

View File

@ -10,20 +10,20 @@ import (
"sync"
)
// URL to the microservice which manages permissions
// URL to the microservice, which manages permissions
var PermissionURL string
// Type of permission
type Permission int
// Some permissions (the real permissions need to come from the permission microservice)
// Some permissions (the real permissions need to come from a permission microservice)
const (
// permission to add goods to the stock
// e.g. if a good is received and now available to sell
// e.g. if a good is received and now available for selling
PermissionCreateGood = 1
// permission to delete goods from the stock
// e.g. if a good becomes fouled and has to be removed
// e.g. if a good becomes fouled and has to be removed manually
PermissionDeleteGood = 2
)

View File

@ -8,7 +8,7 @@ import (
"github.com/genofire/hs_master-kss-monolith/models"
)
// Function to remove automaticle goods after the are fouled
// Function to automatically remove goods, if they are fouled
func GoodFouled() int {
var goods []*models.Good
var g models.Good

View File

@ -11,7 +11,7 @@ import (
"github.com/genofire/hs_master-kss-monolith/models"
)
// Function to test the unlocking of goods
// Function to test fouledDelete()
func TestFouledDelete(t *testing.T) {
assert := assert.New(t)
database.Open(database.Config{

View File

@ -11,7 +11,7 @@ import (
"github.com/genofire/hs_master-kss-monolith/models"
)
// Function to test the unlocking of goods
// Function to test goodRelease()
func TestGoodRelease(t *testing.T) {
assert := assert.New(t)
database.Open(database.Config{

View File

@ -9,7 +9,7 @@ import (
"github.com/stretchr/testify/assert"
)
// Function to test, if and which products exist (get information from the products catalogue)
// Function to test, if and which products exist (get information from the product catalogue)
func TestProductExists(t *testing.T) {
assert := assert.New(t)

View File

@ -1,5 +0,0 @@
// Package with supporting functionality to run the microservice
package runtime
// some mingled functionality to handle in background

View File

@ -25,6 +25,7 @@ type MockTransport struct {
running bool
}
// Function to use the http handler
func (t *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
if !t.running {
return nil, errors.New("mock a error")
@ -33,9 +34,13 @@ func (t *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) {
t.Handler.ServeHTTP(w, req)
return w.Result(), nil
}
// Function to start the http handler
func (t *MockTransport) Start() {
t.running = true
}
// Function to close/stop the http handler
func (t *MockTransport) Close() {
t.running = false
}
@ -73,7 +78,7 @@ func Close() {
mock.Close()
}
// Handle a test session with cookies
// Struct to dandle a test session with cookies
type Request struct {
req *http.Request
cookies []*http.Cookie

View File

@ -30,7 +30,9 @@
<i class="dropdown icon"></i>
<div class="default text">Select Product</div>
<div class="menu">
<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}}</div>
<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}}
</div>
</div>
</div>
</div>
@ -192,6 +194,7 @@
};
}]);
</script>
</body>
</html>

View File

@ -33,6 +33,7 @@
<script>
webshims.setOptions('forms-ext', {types: 'date'});
webshims.polyfill('forms forms-ext');
</script>
<script src="/node_modules/angular/angular.min.js"></script>
<script src="/node_modules/angular-animate/angular-animate.min.js"></script>

View File

@ -2668,4 +2668,5 @@ q14 3 26.5 -5t15.5 -23zM1691 1033q15 -22 10.5 -49t-26.5 -43q-22 -15 -49 -10t-42
<glyph glyph-name="lessequal" unicode="&#xf500;" horiz-adv-x="1792"
/>
</font>
</defs></svg>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 434 KiB

After

Width:  |  Height:  |  Size: 451 KiB