Browse Source

Shop basket progress

Vova Tkach 5 years ago
parent
commit
17fb705d57

+ 98 - 0
engine/basket/basket.go

@@ -0,0 +1,98 @@
+package basket
+
+import (
+	"sync"
+
+	"golang-fave/engine/sqlw"
+)
+
+type Basket struct {
+	sync.RWMutex
+	hosts map[string]*onehost
+}
+
+func New() *Basket {
+	b := Basket{}
+	b.hosts = map[string]*onehost{}
+	return &b
+}
+
+func (this *Basket) Info(host, session_id string, db *sqlw.DB, currency_id int) string {
+	if host == "" || session_id == "" {
+		return (&dResponse{IsError: true, Msg: "basket_host_or_session_not_set", Message: ""}).String()
+	}
+
+	// Load currency here
+
+	this.Lock()
+	defer this.Unlock()
+	if h, ok := this.hosts[host]; ok == true {
+		if s, ok := h.sessions[session_id]; ok == true {
+			s.Info(db, currency_id)
+			return s.String()
+		} else {
+			return (&dResponse{IsError: false, Msg: "basket_is_empty", Message: ""}).String()
+		}
+	} else {
+		return (&dResponse{IsError: false, Msg: "basket_is_empty", Message: ""}).String()
+	}
+}
+
+func (this *Basket) Plus(host, session_id string, db *sqlw.DB, product_id int) string {
+	if host == "" || session_id == "" {
+		return (&dResponse{IsError: true, Msg: "basket_host_or_session_not_set", Message: ""}).String()
+	}
+
+	this.Lock()
+	defer this.Unlock()
+
+	if h, ok := this.hosts[host]; ok == true {
+		if s, ok := h.sessions[session_id]; ok == true {
+			s.Plus(db, product_id)
+		}
+	} else {
+		s := &session{}
+		s.Products = map[int]*product{}
+		s.Plus(db, product_id)
+		h := &onehost{}
+		h.sessions = map[string]*session{}
+		h.sessions[session_id] = s
+		this.hosts[host] = h
+	}
+
+	return (&dResponse{IsError: false, Msg: "basket_product_plus", Message: ""}).String()
+}
+
+func (this *Basket) Minus(host, session_id string, db *sqlw.DB, product_id int) string {
+	if host == "" || session_id == "" {
+		return (&dResponse{IsError: true, Msg: "basket_host_or_session_not_set", Message: ""}).String()
+	}
+
+	this.Lock()
+	defer this.Unlock()
+
+	if h, ok := this.hosts[host]; ok == true {
+		if s, ok := h.sessions[session_id]; ok == true {
+			s.Minus(db, product_id)
+		}
+	}
+
+	return (&dResponse{IsError: false, Msg: "basket_product_minus", Message: ""}).String()
+}
+
+func (this *Basket) Remove(host, session_id string, db *sqlw.DB, product_id int) string {
+	if host == "" || session_id == "" {
+		return (&dResponse{IsError: true, Msg: "basket_host_or_session_not_set", Message: ""}).String()
+	}
+
+	this.Lock()
+	defer this.Unlock()
+
+	if h, ok := this.hosts[host]; ok == true {
+		if s, ok := h.sessions[session_id]; ok == true {
+			s.Remove(db, product_id)
+		}
+	}
+
+	return (&dResponse{IsError: false, Msg: "basket_product_remove", Message: ""}).String()
+}

+ 13 - 0
engine/basket/currency.go

@@ -0,0 +1,13 @@
+package basket
+
+// import (
+// 	"encoding/json"
+// )
+
+type currency struct {
+	Id          int     `json:"id"`
+	Name        string  `json:"name"`
+	Coefficient float64 `json:"coefficient"`
+	Code        string  `json:"code"`
+	Symbol      string  `json:"symbol"`
+}

+ 19 - 0
engine/basket/dresponse.go

@@ -0,0 +1,19 @@
+package basket
+
+import (
+	"encoding/json"
+)
+
+type dResponse struct {
+	IsError bool   `json:"error"`
+	Msg     string `json:"msg"`
+	Message string `json:"message"`
+}
+
+func (this *dResponse) String() string {
+	json, err := json.Marshal(this)
+	if err != nil {
+		return `{"msg":"basket_engine_error","message":"` + err.Error() + `"}`
+	}
+	return string(json)
+}

+ 5 - 0
engine/basket/host.go

@@ -0,0 +1,5 @@
+package basket
+
+type onehost struct {
+	sessions map[string]*session
+}

+ 14 - 0
engine/basket/product.go

@@ -0,0 +1,14 @@
+package basket
+
+// import (
+// 	"encoding/json"
+// )
+
+type product struct {
+	Id       int     `json:"id"`
+	Name     string  `json:"name"`
+	Image    string  `json:"image"`
+	Price    float64 `json:"price"`
+	Quantity int     `json:"quantity"`
+	Sum      float64 `json:"sum"`
+}

+ 51 - 0
engine/basket/session.go

@@ -0,0 +1,51 @@
+package basket
+
+import (
+	"encoding/json"
+
+	"golang-fave/engine/sqlw"
+)
+
+type session struct {
+	Products map[int]*product `json:"products"`
+	Currency *currency        `json:"currency"`
+	Total    float64          `json:"total"`
+}
+
+func (this *session) String() string {
+	json, err := json.Marshal(this)
+	if err != nil {
+		return `{"msg":"basket_engine_error","message":"` + err.Error() + `"}`
+	}
+	return string(json)
+}
+
+func (this *session) Info(db *sqlw.DB, currency_id int) {
+	// Update prices
+	// Update total
+}
+
+func (this *session) Plus(db *sqlw.DB, product_id int) {
+	if p, ok := this.Products[product_id]; ok == true {
+		p.Quantity++
+		return
+	}
+	// Check and insert
+	// Load from DB
+}
+
+func (this *session) Minus(db *sqlw.DB, product_id int) {
+	if p, ok := this.Products[product_id]; ok == true {
+		if p.Quantity > 1 {
+			p.Quantity--
+		} else {
+			delete(this.Products, product_id)
+		}
+	}
+}
+
+func (this *session) Remove(db *sqlw.DB, product_id int) {
+	if _, ok := this.Products[product_id]; ok == true {
+		delete(this.Products, product_id)
+	}
+}

+ 3 - 2
engine/engine.go

@@ -7,6 +7,7 @@ import (
 
 	"golang-fave/assets"
 	"golang-fave/cblocks"
+	"golang-fave/engine/basket"
 	"golang-fave/engine/mysqlpool"
 	"golang-fave/engine/wrapper"
 	"golang-fave/logger"
@@ -21,8 +22,8 @@ type Engine struct {
 	Mods *modules.Modules
 }
 
-func Response(mp *mysqlpool.MySqlPool, l *logger.Logger, m *modules.Modules, w http.ResponseWriter, r *http.Request, s *session.Session, c *cblocks.CacheBlocks, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp string) bool {
-	wrap := wrapper.New(l, w, r, s, c, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp, mp)
+func Response(mp *mysqlpool.MySqlPool, sb *basket.Basket, l *logger.Logger, m *modules.Modules, w http.ResponseWriter, r *http.Request, s *session.Session, c *cblocks.CacheBlocks, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp string) bool {
+	wrap := wrapper.New(l, w, r, s, c, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp, mp, sb)
 	eng := &Engine{
 		Wrap: wrap,
 		Mods: m,

+ 12 - 1
engine/wrapper/wrapper.go

@@ -14,6 +14,7 @@ import (
 
 	"golang-fave/cblocks"
 	"golang-fave/consts"
+	"golang-fave/engine/basket"
 	"golang-fave/engine/mysqlpool"
 	"golang-fave/engine/sqlw"
 	"golang-fave/engine/wrapper/config"
@@ -50,13 +51,14 @@ type Wrapper struct {
 	CurrModule      string
 	CurrSubModule   string
 	MSPool          *mysqlpool.MySqlPool
+	ShopBasket      *basket.Basket
 	Config          *config.Config
 
 	DB   *sqlw.DB
 	User *utils.MySql_user
 }
 
-func New(l *logger.Logger, w http.ResponseWriter, r *http.Request, s *session.Session, c *cblocks.CacheBlocks, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp string, mp *mysqlpool.MySqlPool) *Wrapper {
+func New(l *logger.Logger, w http.ResponseWriter, r *http.Request, s *session.Session, c *cblocks.CacheBlocks, host, port, chost, dirConfig, dirHtdocs, dirLogs, dirTemplate, dirTmp string, mp *mysqlpool.MySqlPool, sb *basket.Basket) *Wrapper {
 
 	conf := config.ConfigNew()
 	if err := conf.ConfigRead(dirConfig + string(os.PathSeparator) + "config.json"); err != nil {
@@ -81,6 +83,7 @@ func New(l *logger.Logger, w http.ResponseWriter, r *http.Request, s *session.Se
 		CurrModule:    "",
 		CurrSubModule: "",
 		MSPool:        mp,
+		ShopBasket:    sb,
 		Config:        conf,
 	}
 }
@@ -302,6 +305,14 @@ func (this *Wrapper) SendEmail(email, subject, message string) error {
 	return nil
 }
 
+func (this *Wrapper) GetSessionId() string {
+	cookie, err := this.R.Cookie("session")
+	if err == nil && len(cookie.Value) == 40 {
+		return cookie.Value
+	}
+	return ""
+}
+
 func (this *Wrapper) RecreateProductXmlFile() error {
 	trigger := strings.Join([]string{this.DTmp, "trigger.xml.run"}, string(os.PathSeparator))
 	if !utils.IsFileExists(trigger) {

+ 5 - 1
main.go

@@ -12,6 +12,7 @@ import (
 	"golang-fave/consts"
 	"golang-fave/domains"
 	"golang-fave/engine"
+	"golang-fave/engine/basket"
 	"golang-fave/engine/mysqlpool"
 	"golang-fave/logger"
 	"golang-fave/modules"
@@ -113,6 +114,9 @@ func main() {
 	// Init cache blocks
 	cbs := cblocks.New()
 
+	// Shop basket
+	sb := basket.New()
+
 	// Init and start web server
 	bootstrap.Start(lg.Handler, fmt.Sprintf("%s:%d", consts.ParamHost, consts.ParamPort), 9, consts.AssetsPath, func(w http.ResponseWriter, r *http.Request, o interface{}) {
 		w.Header().Set("Server", "fave.pro/"+consts.ServerVersion)
@@ -201,7 +205,7 @@ func main() {
 
 		// Logic
 		if mp != nil {
-			if engine.Response(mp, lg, mods, w, r, sess, cbs, host, port, curr_host, vhost_dir_config, vhost_dir_htdocs, vhost_dir_logs, vhost_dir_template, vhost_dir_tmp) {
+			if engine.Response(mp, sb, lg, mods, w, r, sess, cbs, host, port, curr_host, vhost_dir_config, vhost_dir_htdocs, vhost_dir_logs, vhost_dir_template, vhost_dir_tmp) {
 				return
 			}
 		}

+ 3 - 3
modules/module_api.go

@@ -31,16 +31,16 @@ func (this *Modules) RegisterModule_Api() *Module {
 				// Response
 				target_file := wrap.DHtdocs + string(os.PathSeparator) + "products.xml"
 				if !utils.IsFileExists(target_file) {
+					wrap.W.WriteHeader(http.StatusServiceUnavailable)
 					wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
 					wrap.W.Header().Set("Content-Type", "text/xml; charset=utf-8")
-					wrap.W.WriteHeader(http.StatusServiceUnavailable)
 					wrap.W.Write([]byte("In progress..."))
 				} else {
 					http.ServeFile(wrap.W, wrap.R, target_file)
 				}
 			} else {
-				wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
 				wrap.W.WriteHeader(http.StatusServiceUnavailable)
+				wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
 				wrap.W.Write([]byte("Disabled!"))
 			}
 		} else if len(wrap.UrlArgs) == 1 {
@@ -51,8 +51,8 @@ func (this *Modules) RegisterModule_Api() *Module {
 			}
 
 			// Some info
-			wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
 			wrap.W.WriteHeader(http.StatusOK)
+			wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
 			wrap.W.Write([]byte("Fave engine API mount point!"))
 		} else {
 			// User error 404 page

+ 22 - 0
modules/module_shop.go

@@ -444,6 +444,28 @@ func (this *Modules) RegisterModule_Shop() *Module {
 			// Render template
 			wrap.RenderFrontEnd("shop-category", fetdata.New(wrap, false, row, rou), http.StatusOK)
 			return
+		} else if len(wrap.UrlArgs) >= 3 && wrap.UrlArgs[0] == "shop" && wrap.UrlArgs[1] == "basket" && (wrap.UrlArgs[2] == "info" || wrap.UrlArgs[2] == "add" || wrap.UrlArgs[2] == "update" || wrap.UrlArgs[2] == "remove") {
+			if wrap.UrlArgs[2] == "info" {
+				wrap.W.WriteHeader(http.StatusOK)
+				wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+				wrap.W.Write([]byte(wrap.ShopBasket.Info(wrap.CurrHost, wrap.GetSessionId(), wrap.DB, 1)))
+				return
+			} else if wrap.UrlArgs[2] == "plus" && len(wrap.UrlArgs) == 4 && utils.IsNumeric(wrap.UrlArgs[3]) {
+				wrap.W.WriteHeader(http.StatusOK)
+				wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+				wrap.W.Write([]byte(wrap.ShopBasket.Plus(wrap.CurrHost, wrap.GetSessionId(), wrap.DB, utils.StrToInt(wrap.UrlArgs[3]))))
+				return
+			} else if wrap.UrlArgs[2] == "minus" && len(wrap.UrlArgs) == 4 && utils.IsNumeric(wrap.UrlArgs[3]) {
+				wrap.W.WriteHeader(http.StatusOK)
+				wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+				wrap.W.Write([]byte(wrap.ShopBasket.Minus(wrap.CurrHost, wrap.GetSessionId(), wrap.DB, utils.StrToInt(wrap.UrlArgs[3]))))
+				return
+			} else if wrap.UrlArgs[2] == "remove" && len(wrap.UrlArgs) == 4 && utils.IsNumeric(wrap.UrlArgs[3]) {
+				wrap.W.WriteHeader(http.StatusOK)
+				wrap.W.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate")
+				wrap.W.Write([]byte(wrap.ShopBasket.Remove(wrap.CurrHost, wrap.GetSessionId(), wrap.DB, utils.StrToInt(wrap.UrlArgs[3]))))
+				return
+			}
 		} else if len(wrap.UrlArgs) == 2 && wrap.UrlArgs[0] == "shop" && wrap.UrlArgs[1] != "" {
 			// Shop product
 			row := &utils.MySql_shop_product{}

+ 1 - 1
modules/modules.go

@@ -353,7 +353,7 @@ func (this *Modules) XXXFrontEnd(wrap *wrapper.Wrapper) bool {
 			}
 			start := time.Now()
 			mod.Front(wrap)
-			if !(mod.Info.Mount == "api") {
+			if !(mod.Info.Mount == "api" || (mod.Info.Mount == "shop" && len(wrap.UrlArgs) >= 3 && wrap.UrlArgs[1] == "basket")) {
 				wrap.W.Write([]byte(fmt.Sprintf("<!-- %.3f ms -->", time.Now().Sub(start).Seconds())))
 			}
 			return true