diff --git a/.env b/.env index e4e8f39..8fe69fd 100644 --- a/.env +++ b/.env @@ -21,6 +21,10 @@ AUTH_JWT_SECRET=5c020e6ed3d8d6e67e5804d67c83c4bd5ae474df749af6d63d8f20e7e2ba29b3 AUTH_JWT_EXPIRATION=86400 AUTH_REFRESH_EXPIRATION=604800 +# Meili search +MEILISEARCH_URL=http://localhost:7700 +MEILISEARCH_API_KEY=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 + # Google Translate Client GOOGLE_APPLICATION_CREDENTIALS=./google-cred.json GOOGLE_CLOUD_PROJECT_ID=translation-343517 diff --git a/Taskfile.yml b/Taskfile.yml index 43351b4..285cef7 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -72,11 +72,23 @@ vars: MP_SMTP_AUTH_ACCEPT_ANY: true MP_SMTP_AUTH_ALLOW_INSECURE: true MP_ENABLE_SPAMASSASSIN: postmark - MP_VERBOSE: true + MP_VERBOSE: true + meilisearch: + image: getmeili/meilisearch:latest + container_name: meilisearch + restart: unless-stopped + ports: + - 7700:7700 + volumes: + - meilisearch:/data.ms + environment: + MEILI_MASTER_KEY: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + volumes: db_data: - mailpit_data: + mailpit_data: + meilisearch: includes: diff --git a/app/delivery/web/api/restricted/meiliSearch.go b/app/delivery/web/api/restricted/meiliSearch.go new file mode 100644 index 0000000..d40a38e --- /dev/null +++ b/app/delivery/web/api/restricted/meiliSearch.go @@ -0,0 +1,55 @@ +package restricted + +import ( + "strconv" + + "git.ma-al.com/goc_daniel/b2b/app/service/meiliService" + "git.ma-al.com/goc_daniel/b2b/app/utils/i18n" + "git.ma-al.com/goc_daniel/b2b/app/utils/nullable" + "git.ma-al.com/goc_daniel/b2b/app/utils/response" + "git.ma-al.com/goc_daniel/b2b/app/utils/responseErrors" + "github.com/gofiber/fiber/v3" +) + +type MeiliSearchHandler struct { + meiliService *meiliService.MeiliService +} + +func NewMeiliSearchHandler() *MeiliSearchHandler { + meiliService := meiliService.New() + return &MeiliSearchHandler{ + meiliService: meiliService, + } +} + +func MeiliSearchHandlerRoutes(r fiber.Router) fiber.Router { + handler := NewMeiliSearchHandler() + + r.Get("/test", handler.Test) + + return r +} + +func (h *MeiliSearchHandler) Test(c fiber.Ctx) error { + + id_shop_attribute := c.Query("shopID") + id_shop, err := strconv.Atoi(id_shop_attribute) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)). + JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) + } + + id_lang, err := strconv.Atoi(c.Cookies("lang_id", "2")) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(responseErrors.ErrBadAttribute)). + JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, responseErrors.ErrBadAttribute))) + } + + test, err := h.meiliService.Test(uint(id_shop), uint(id_lang)) + if err != nil { + return c.Status(responseErrors.GetErrorStatus(err)). + JSON(response.Make(nullable.GetNil(""), 0, responseErrors.GetErrorCode(c, err))) + } + + return c.JSON(response.Make(&test, 0, i18n.T_(c, response.Message_OK))) +} diff --git a/app/delivery/web/init.go b/app/delivery/web/init.go index 7c8cd63..30a372a 100644 --- a/app/delivery/web/init.go +++ b/app/delivery/web/init.go @@ -106,6 +106,10 @@ func (s *Server) Setup() error { menu := s.restricted.Group("/menu") restricted.MenuHandlerRoutes(menu) + // meili search (restricted) + meiliSearch := s.restricted.Group("/meili-search") + restricted.MeiliSearchHandlerRoutes(meiliSearch) + // // Restricted routes example // restricted := s.api.Group("/restricted") // restricted.Use(middleware.AuthMiddleware()) diff --git a/app/service/meiliService/meiliService.go b/app/service/meiliService/meiliService.go new file mode 100644 index 0000000..ab717ff --- /dev/null +++ b/app/service/meiliService/meiliService.go @@ -0,0 +1,72 @@ +package meiliService + +import ( + "fmt" + "os" + "strconv" + + "github.com/meilisearch/meilisearch-go" +) + +type MeiliService struct { + meiliClient meilisearch.ServiceManager +} + +func New() *MeiliService { + meiliURL := os.Getenv("MEILISEARCH_URL") + meiliAPIKey := os.Getenv("MEILISEARCH_API_KEY") + + client := meilisearch.New( + meiliURL, + meilisearch.WithAPIKey(meiliAPIKey), + ) + + return &MeiliService{ + meiliClient: client, + } +} + +// ==================================== FOR DEBUG ONLY ==================================== +func (s *MeiliService) Test(id_shop uint, id_lang uint) (meilisearch.SearchResponse, error) { + indexName := "products_lang" + strconv.FormatInt(int64(id_lang), 10) + + searchReq := &meilisearch.SearchRequest{ + Limit: 3, + } + + // Perform search + results, err := s.meiliClient.Index(indexName).Search("walek", searchReq) + if err != nil { + fmt.Printf("Meilisearch error: %v\n", err) + return meilisearch.SearchResponse{}, err + } + + fmt.Printf("Search results for query 'walek' in %s: %d hits\n", indexName, len(results.Hits)) + + return *results, nil +} + +// Search performs a full-text search on the specified index +func (s *MeiliService) Search(indexName string, query string, limit int) (meilisearch.SearchResponse, error) { + searchReq := &meilisearch.SearchRequest{ + Limit: int64(limit), + } + + results, err := s.meiliClient.Index(indexName).Search(query, searchReq) + if err != nil { + fmt.Printf("Meilisearch search error: %v\n", err) + return meilisearch.SearchResponse{}, err + } + + return *results, nil +} + +// HealthCheck checks if Meilisearch is healthy and accessible +func (s *MeiliService) HealthCheck() (*meilisearch.Health, error) { + health, err := s.meiliClient.Health() + if err != nil { + return nil, fmt.Errorf("meilisearch health check failed: %w", err) + } + + return health, nil +} diff --git a/go.mod b/go.mod index 0dc9c19..7632dfb 100644 --- a/go.mod +++ b/go.mod @@ -29,6 +29,7 @@ require ( github.com/google/s2a-go v0.1.9 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect github.com/googleapis/gax-go/v2 v2.15.0 // indirect + github.com/meilisearch/meilisearch-go v0.36.1 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect diff --git a/go.sum b/go.sum index 3e65cda..6b02711 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,8 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/meilisearch/meilisearch-go v0.36.1 h1:mJTCJE5g7tRvaqKco6DfqOuJEjX+rRltDEnkEC02Y0M= +github.com/meilisearch/meilisearch-go v0.36.1/go.mod h1:hWcR0MuWLSzHfbz9GGzIr3s9rnXLm1jqkmHkJPbUSvM= github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/openai/openai-go/v3 v3.28.0 h1:2+FfrCVMdGXSQrBv1tLWtokm+BU7+3hJ/8rAHPQ63KM= diff --git a/i18n/migrations/20260302163100_routes.sql b/i18n/migrations/20260302163100_routes.sql index 6369d6a..a2f41a7 100644 --- a/i18n/migrations/20260302163100_routes.sql +++ b/i18n/migrations/20260302163100_routes.sql @@ -6,16 +6,16 @@ CREATE TABLE IF NOT EXISTS b2b_tracker_routes ( path VARCHAR(255) NULL, component VARCHAR(255) NOT NULL COMMENT 'path to component file', layout VARCHAR(50) DEFAULT 'default' COMMENT "'default' | 'empty'", - meta JSON DEFAULT '{}' , + meta JSON DEFAULT '{}', is_active BOOLEAN DEFAULT TRUE, sort_order INT DEFAULT 0, - parent_id INT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + parent_id INT NULL, -ALTER TABLE b2b_tracker_routes - ADD CONSTRAINT fk_parent - FOREIGN KEY (parent_id) REFERENCES b2b_tracker_routes(id) - ON DELETE SET NULL; + CONSTRAINT fk_parent + FOREIGN KEY (parent_id) + REFERENCES b2b_tracker_routes(id) + ON DELETE SET NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT IGNORE INTO b2b_tracker_routes (name, path, component, layout, meta, is_active, sort_order, parent_id) diff --git a/i18n/migrations/20260302163122_create_tables.sql b/i18n/migrations/20260302163122_create_tables.sql index 168b7e8..6113dfe 100644 --- a/i18n/migrations/20260302163122_create_tables.sql +++ b/i18n/migrations/20260302163122_create_tables.sql @@ -113,13 +113,6 @@ CREATE UNIQUE INDEX IF NOT EXISTS uk_refresh_tokens_token_hash ON b2b_refresh_to CREATE INDEX IF NOT EXISTS idx_refresh_tokens_customer_id ON b2b_refresh_tokens (customer_id); --- insert sample admin user admin@ma-al.com/Maal12345678 - -INSERT IGNORE INTO b2b_customers (id, email, password, first_name, last_name, role, provider, provider_id, avatar_url, is_active, email_verified, email_verification_token, email_verification_expires, password_reset_token, password_reset_expires, last_password_reset_request, last_login_at, lang_id, country_id, created_at, updated_at, deleted_at) -VALUES - (1, 'admin@ma-al.com', '$2a$10$Owy9DjrS0l3Fz4XoOvh5pulgmOMqdwXmb7hYE9BovnSuWS2plGr82', 'Super', 'Admin', 'admin', 'local', '', '', 1, 1, NULL, NULL, '', NULL, NULL, NULL, 1, 1, '2026-03-02 16:55:10.252740', '2026-03-02 16:55:10.252740', NULL); -ALTER TABLE b2b_customers AUTO_INCREMENT = 1; - -- countries CREATE TABLE IF NOT EXISTS b2b_countries ( id INT AUTO_INCREMENT PRIMARY KEY,