From 99d62fcb47e8a308211fd7db229c247b9f6309a9 Mon Sep 17 00:00:00 2001 From: mlabusch Date: Wed, 21 Jun 2017 15:25:18 +0200 Subject: [PATCH] [Task]: add comments + comment quality saving --- README.md | 16 +- cmd/stock/main.go | 8 +- config_monolith.conf | 24 - contrib/good_availablity.svg | 5 +- .../microservice_stock/chapter/Struktur.tex | 9 +- .../microservice_stock/documentation.pdf | Bin 376595 -> 376587 bytes http/good.go | 18 +- http/good_lock.go | 19 +- http/good_lock_test.go | 2 + http/good_show_test.go | 4 +- http/good_temp.go | 6 +- http/good_test.go | 4 +- lib/database/database.go | 14 +- lib/http/io.go | 2 +- lib/worker/worker.go | 2 +- lib/worker/worker_test.go | 4 +- models/config.go | 24 +- models/duration.go | 6 +- models/good.go | 18 +- models/structstorage.go | 4 - .../domain/DataTransferObjectFactory.java | 197 +- .../monolith/web/HomepageController.java | 8 +- .../de/mstock/monolith/web/ProductDTO.java | 1 + .../src/main/resources/templates/product.html | 3 + .../main/resources/templates/stockadmin.html | 32 - runtime/auth.go | 8 +- runtime/cache_worker_test.go | 2 +- runtime/good_fouled.go | 2 +- runtime/good_fouled_test.go | 2 +- runtime/good_release_test.go | 2 +- runtime/productcache_test.go | 2 +- runtime/runtime.go | 5 - test/testrest.go | 7 +- webroot/api-test/product/1/index.html | 4 +- webroot/api-test/product/2/index.html | 4 +- webroot/api-test/product/3/index.html | 4 +- webroot/api-test/product/4/index.html | 4 +- webroot/api-test/product/5/index.html | 4 +- webroot/api-test/product/6/index.html | 4 +- webroot/api-test/product/index.html | 12 +- webroot/dummy_cart/index.html | 145 +- webroot/index.html | 67 +- .../themes/default/assets/fonts/icons.svg | 4045 +++++++++-------- webroot/static/html/item-add.html | 44 +- webroot/static/html/item.html | 50 +- webroot/static/html/list.html | 32 +- webroot/static/html/statistics.html | 32 +- 47 files changed, 2435 insertions(+), 2476 deletions(-) delete mode 100644 config_monolith.conf delete mode 100644 models/structstorage.go delete mode 100644 monolith/src/main/resources/templates/stockadmin.html delete mode 100644 runtime/runtime.go diff --git a/README.md b/README.md index 1ce3dcd..3de911a 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/cmd/stock/main.go b/cmd/stock/main.go index ecf5c76..1cda8f3 100644 --- a/cmd/stock/main.go +++ b/cmd/stock/main.go @@ -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) diff --git a/config_monolith.conf b/config_monolith.conf deleted file mode 100644 index 2229050..0000000 --- a/config_monolith.conf +++ /dev/null @@ -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/" diff --git a/contrib/good_availablity.svg b/contrib/good_availablity.svg index ca93384..4712224 100644 --- a/contrib/good_availablity.svg +++ b/contrib/good_availablity.svg @@ -1,8 +1,7 @@ - - - + + {{if eq .Count 0}} diff --git a/documentation/microservice_stock/chapter/Struktur.tex b/documentation/microservice_stock/chapter/Struktur.tex index 357d59f..92a63f8 100644 --- a/documentation/microservice_stock/chapter/Struktur.tex +++ b/documentation/microservice_stock/chapter/Struktur.tex @@ -58,8 +58,9 @@ 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\_show.go}: Funktionen für die Auflistung und Zählung der vorhandenen Waren sowie die Feststellung ihrer Verfügbarkeit + \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 \end{itemize} @@ -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} diff --git a/documentation/microservice_stock/documentation.pdf b/documentation/microservice_stock/documentation.pdf index 362a2843ae486e24a0cb5ad2f4e906a99c223359..841596a089b709e3baec8a3a2dbe6124f45cfeb5 100644 GIT binary patch delta 20358 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ℜ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 createProductDTOs(List products, Locale locale) { - List productDTOs = new ArrayList<>(products.size()); - NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale); - for (Product product : products) { - productDTOs.add(createProductDTO(product, locale, numberFormat)); + /** + * Creates a Data Transfer Object (DTO). + * + * @param category database entity + * @param locale the requested locale + * @return DTO + */ + public CategoryDTO createCategoryDTO(Category category, Locale locale) { + CategoryI18n i18n = category.getI18n().get(locale.getLanguage()); + CategoryDTO categoryDTO = new CategoryDTO(); + categoryDTO.setName(i18n.getName()); + categoryDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment()); + return categoryDTO; } - return productDTOs; - } - /** - * Creates Data Transfer Objects (DTOs) without loading their reviews. - * - * @param products database entities - * @param locale the requested locale - * @return DTOs - */ - public List createProductWithoutReviewsDTOs(List products, Locale locale) { - List productDTOs = new ArrayList<>(products.size()); - NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale); - for (Product product : products) { - productDTOs.add(createProductWithoutReviewsDTO(product, locale, numberFormat)); + /** + * Creates a Data Transfer Object (DTO). + * + * @param product database entity + * @param locale the requested locale + * @return DTO + */ + public ProductDTO createProductDTO(Product product, Locale locale) { + return createProductDTO(product, locale, NumberFormat.getCurrencyInstance(locale)); } - return productDTOs; - } - private ProductDTO createProductWithoutReviewsDTO(Product product, Locale locale, - NumberFormat numberFormat) { - ProductI18n i18n = product.getI18n().get(locale.getLanguage()); - String price = numberFormat.format(i18n.getPrice()); - ProductDTO productDTO = new ProductDTO(); - productDTO.setId(product.getId()); - productDTO.setItemNumber(product.getItemNumber()); - productDTO.setUnit(product.getUnit()); - productDTO.setName(i18n.getName()); - productDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment()); - productDTO.setPrice(price); - productDTO.setDescription(i18n.getDescription()); - return productDTO; - } - - /** - * Creates a Data Transfer Object (DTO). - * - * @param review database entity - * @return DTO - */ - public ReviewDTO createReviewDTO(Review review) { - ReviewDTO dto = new ReviewDTO(); - dto.setLanguage(review.getLocaleLanguage()); - dto.setRatingStars(review.getRatingStars()); - dto.setFirstName(review.getFirstName()); - dto.setLastName(review.getLastName()); - dto.setText(review.getText()); - return dto; - } - - private List createReviewDTOs(List reviews) { - List ratingDTOs = new ArrayList<>(reviews.size()); - for (Review review : reviews) { - ratingDTOs.add(createReviewDTO(review)); + private ProductDTO createProductDTO(Product product, Locale locale, NumberFormat numberFormat) { + ProductDTO productDTO = createProductWithoutReviewsDTO(product, locale, numberFormat); + ProductI18n i18n = product.getI18n().get(locale.getLanguage()); + productDTO.setReviews(createReviewDTOs(i18n.getReviews())); + return productDTO; + } + + /** + * Creates Data Transfer Objects (DTOs). + * + * @param products database entities + * @param locale the requested locale + * @return DTOs + */ + public List createProductDTOs(List products, Locale locale) { + List productDTOs = new ArrayList<>(products.size()); + NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale); + for (Product product : products) { + productDTOs.add(createProductDTO(product, locale, numberFormat)); + } + return productDTOs; + } + + /** + * Creates Data Transfer Objects (DTOs) without loading their reviews. + * + * @param products database entities + * @param locale the requested locale + * @return DTOs + */ + public List createProductWithoutReviewsDTOs(List products, Locale locale) { + List productDTOs = new ArrayList<>(products.size()); + NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale); + for (Product product : products) { + productDTOs.add(createProductWithoutReviewsDTO(product, locale, numberFormat)); + } + return productDTOs; + } + + private ProductDTO createProductWithoutReviewsDTO(Product product, Locale locale, + NumberFormat numberFormat) { + 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()); + productDTO.setName(i18n.getName()); + productDTO.setPrettyUrlFragment(i18n.getPrettyUrlFragment()); + productDTO.setPrice(price); + productDTO.setDescription(i18n.getDescription()); + return productDTO; + } + + /** + * Creates a Data Transfer Object (DTO). + * + * @param review database entity + * @return DTO + */ + public ReviewDTO createReviewDTO(Review review) { + ReviewDTO dto = new ReviewDTO(); + dto.setLanguage(review.getLocaleLanguage()); + dto.setRatingStars(review.getRatingStars()); + dto.setFirstName(review.getFirstName()); + dto.setLastName(review.getLastName()); + dto.setText(review.getText()); + return dto; + } + + private List createReviewDTOs(List reviews) { + List ratingDTOs = new ArrayList<>(reviews.size()); + for (Review review : reviews) { + ratingDTOs.add(createReviewDTO(review)); + } + return Collections.unmodifiableList(ratingDTOs); } - return Collections.unmodifiableList(ratingDTOs); - } } diff --git a/monolith/src/main/java/de/mstock/monolith/web/HomepageController.java b/monolith/src/main/java/de/mstock/monolith/web/HomepageController.java index 19d0aea..5754576 100644 --- a/monolith/src/main/java/de/mstock/monolith/web/HomepageController.java +++ b/monolith/src/main/java/de/mstock/monolith/web/HomepageController.java @@ -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 + * @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; } /** diff --git a/monolith/src/main/java/de/mstock/monolith/web/ProductDTO.java b/monolith/src/main/java/de/mstock/monolith/web/ProductDTO.java index d14dafd..a7d3245 100644 --- a/monolith/src/main/java/de/mstock/monolith/web/ProductDTO.java +++ b/monolith/src/main/java/de/mstock/monolith/web/ProductDTO.java @@ -15,6 +15,7 @@ public class ProductDTO { private String description; private List reviews; + // Addition: int id, getId() and setID() public int getId() { return id; } diff --git a/monolith/src/main/resources/templates/product.html b/monolith/src/main/resources/templates/product.html index d221277..9b2d0bf 100644 --- a/monolith/src/main/resources/templates/product.html +++ b/monolith/src/main/resources/templates/product.html @@ -31,7 +31,10 @@

Product Name

+ + +

0,00 Euro

Description.

diff --git a/monolith/src/main/resources/templates/stockadmin.html b/monolith/src/main/resources/templates/stockadmin.html deleted file mode 100644 index f80b4b6..0000000 --- a/monolith/src/main/resources/templates/stockadmin.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - -
-
- -
-
- - - - - - \ No newline at end of file diff --git a/runtime/auth.go b/runtime/auth.go index f567dff..e0461ee 100644 --- a/runtime/auth.go +++ b/runtime/auth.go @@ -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 ) diff --git a/runtime/cache_worker_test.go b/runtime/cache_worker_test.go index 7476f51..40f00e5 100644 --- a/runtime/cache_worker_test.go +++ b/runtime/cache_worker_test.go @@ -8,7 +8,7 @@ import ( "github.com/genofire/hs_master-kss-monolith/models" ) -// Function to test the cache Worker +// Function to test the cacheWorker func TestCacheWorker(t *testing.T) { productExistCache[2] = boolMicroServiceCache{LastCheck: time.Now(), Value: true} diff --git a/runtime/good_fouled.go b/runtime/good_fouled.go index a62d43c..b062452 100644 --- a/runtime/good_fouled.go +++ b/runtime/good_fouled.go @@ -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 diff --git a/runtime/good_fouled_test.go b/runtime/good_fouled_test.go index f8f67c4..89bb34a 100644 --- a/runtime/good_fouled_test.go +++ b/runtime/good_fouled_test.go @@ -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{ diff --git a/runtime/good_release_test.go b/runtime/good_release_test.go index 1cbf305..8f18093 100644 --- a/runtime/good_release_test.go +++ b/runtime/good_release_test.go @@ -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{ diff --git a/runtime/productcache_test.go b/runtime/productcache_test.go index d541715..b0b00cc 100644 --- a/runtime/productcache_test.go +++ b/runtime/productcache_test.go @@ -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) diff --git a/runtime/runtime.go b/runtime/runtime.go deleted file mode 100644 index 2049f4a..0000000 --- a/runtime/runtime.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package with supporting functionality to run the microservice -package runtime - -// some mingled functionality to handle in background - diff --git a/test/testrest.go b/test/testrest.go index eb0185f..1a73189 100644 --- a/test/testrest.go +++ b/test/testrest.go @@ -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 diff --git a/webroot/api-test/product/1/index.html b/webroot/api-test/product/1/index.html index 80376f8..d7ae1c0 100644 --- a/webroot/api-test/product/1/index.html +++ b/webroot/api-test/product/1/index.html @@ -1,4 +1,4 @@ { - "id": 1, - "title": "Kiwi" +"id": 1, +"title": "Kiwi" } diff --git a/webroot/api-test/product/2/index.html b/webroot/api-test/product/2/index.html index 00526ed..00332d5 100644 --- a/webroot/api-test/product/2/index.html +++ b/webroot/api-test/product/2/index.html @@ -1,4 +1,4 @@ { - "id": 2, - "title": "Blueberries" +"id": 2, +"title": "Blueberries" } diff --git a/webroot/api-test/product/3/index.html b/webroot/api-test/product/3/index.html index bf6a229..f10251a 100644 --- a/webroot/api-test/product/3/index.html +++ b/webroot/api-test/product/3/index.html @@ -1,4 +1,4 @@ { - "id": 3, - "title": "Cherries" +"id": 3, +"title": "Cherries" } diff --git a/webroot/api-test/product/4/index.html b/webroot/api-test/product/4/index.html index 923db88..df11269 100644 --- a/webroot/api-test/product/4/index.html +++ b/webroot/api-test/product/4/index.html @@ -1,4 +1,4 @@ { - "id": 4, - "title": "Potatoes" +"id": 4, +"title": "Potatoes" } diff --git a/webroot/api-test/product/5/index.html b/webroot/api-test/product/5/index.html index 1a4844b..926d7e0 100644 --- a/webroot/api-test/product/5/index.html +++ b/webroot/api-test/product/5/index.html @@ -1,4 +1,4 @@ { - "id": 5, - "title": "Tomatoes" +"id": 5, +"title": "Tomatoes" } diff --git a/webroot/api-test/product/6/index.html b/webroot/api-test/product/6/index.html index 9ddd068..bbef7ed 100644 --- a/webroot/api-test/product/6/index.html +++ b/webroot/api-test/product/6/index.html @@ -1,4 +1,4 @@ { - "id": 6, - "title": "Rhubarb" +"id": 6, +"title": "Rhubarb" } diff --git a/webroot/api-test/product/index.html b/webroot/api-test/product/index.html index 80b7db2..47d53fe 100644 --- a/webroot/api-test/product/index.html +++ b/webroot/api-test/product/index.html @@ -1,8 +1,8 @@ [ - {"id":1, "title": "Kiwi"}, - {"id":2, "title": "Blueberries"}, - {"id":3, "title": "Cherries"}, - {"id":4, "title": "Potatoes"}, - {"id":5, "title": "Tomatoes"}, - {"id":6, "title": "Rhubarb"} +{"id":1, "title": "Kiwi"}, +{"id":2, "title": "Blueberries"}, +{"id":3, "title": "Cherries"}, +{"id":4, "title": "Potatoes"}, +{"id":5, "title": "Tomatoes"}, +{"id":6, "title": "Rhubarb"} ] diff --git a/webroot/dummy_cart/index.html b/webroot/dummy_cart/index.html index e320443..5db4836 100644 --- a/webroot/dummy_cart/index.html +++ b/webroot/dummy_cart/index.html @@ -1,79 +1,81 @@ - - - - - - microStock Dummy Cart + + + + + + microStock Dummy Cart - - -
-
-
-
- -
-
- -
-
- -
-
-
- - - - - - - - - - - - - - - -
CountProduct
{{item.count}}{{getProduct(item.product_id).title}} -
-
-
- -
-
-

© 2017 MM / Go - Team

+
- - - - - - - + + + + + + + + diff --git a/webroot/index.html b/webroot/index.html index cbb3565..29134b5 100644 --- a/webroot/index.html +++ b/webroot/index.html @@ -1,48 +1,49 @@ - - - - - - Stock Admin + + + + + + Stock Admin - -
+
-