From 273df356190ba17f2748d9c478d494597ce5f8cd Mon Sep 17 00:00:00 2001 From: Prabhaharan Date: Sun, 16 Mar 2025 19:11:29 +0530 Subject: [PATCH 1/2] Added the Distribution api file --- Distributer.go | 153 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 Distributer.go diff --git a/Distributer.go b/Distributer.go new file mode 100644 index 000000000..1f5c5d015 --- /dev/null +++ b/Distributer.go @@ -0,0 +1,153 @@ +package main + +import ( + "encoding/csv" + "encoding/json" + "fmt" + "net/http" + "os" + "strings" + "sync" +) + +type Distributor struct { + Name string `json:"name"` + Includes []string `json:"includes"` + Excludes []string `json:"excludes"` +} + +var ( + distributors = make(map[string]*Distributor) + dataLock sync.Mutex + cityMapping = make(map[string]string) // Mapping city codes to full names +) + +// Load city mapping from CSV +func loadCityMapping() error { + file, err := os.Open("regions.csv") + if err != nil { + return err + } + defer file.Close() + + reader := csv.NewReader(file) + _, err = reader.Read() // Skip header + if err != nil { + return err + } + + for { + record, err := reader.Read() + if err != nil { + break + } + cityCode := record[0] + fullName := strings.ToUpper(fmt.Sprintf("%s-%s-%s", record[3], record[4], record[5])) + cityMapping[cityCode] = fullName + } + return nil +} + +// Add a new distributor +func addDistributor(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + var d Distributor + if err := json.NewDecoder(r.Body).Decode(&d); err != nil { + http.Error(w, "Invalid JSON", http.StatusBadRequest) + return + } + + dataLock.Lock() + distributors[d.Name] = &d + dataLock.Unlock() + + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(map[string]string{"message": "Distributor added"}) +} + +// Set permissions for an existing distributor +func setPermissions(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + var d Distributor + if err := json.NewDecoder(r.Body).Decode(&d); err != nil { + http.Error(w, "Invalid JSON", http.StatusBadRequest) + return + } + + dataLock.Lock() + defer dataLock.Unlock() + + if existing, found := distributors[d.Name]; found { + existing.Includes = d.Includes + existing.Excludes = d.Excludes + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(map[string]string{"message": "Permissions updated"}) + } else { + http.Error(w, "Distributor not found", http.StatusNotFound) + } +} + +func checkPermission(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + name := r.URL.Query().Get("name") + region := strings.ToUpper(r.URL.Query().Get("region")) + + dataLock.Lock() + defer dataLock.Unlock() + + d, exists := distributors[name] + if !exists { + http.Error(w, "Distributor not found", http.StatusNotFound) + return + } + + // Debugging: Print permissions to verify correctness + // fmt.Println("Checking permissions for:", name) + // fmt.Println("Includes:", d.Includes) + // fmt.Println("Excludes:", d.Excludes) + // fmt.Println("Requested Region:", region) + + for _, excl := range d.Excludes { + if region == excl || strings.HasSuffix(region, excl) { + json.NewEncoder(w).Encode(map[string]string{"permission": "NO"}) + return + } + } + + for _, incl := range d.Includes { + if region == incl || strings.HasSuffix(region, incl) { + json.NewEncoder(w).Encode(map[string]string{"permission": "YES"}) + return + } + } + + // Default case: NO + json.NewEncoder(w).Encode(map[string]string{"permission": "NO"}) +} + +func main() { + err := loadCityMapping() + if err != nil { + fmt.Println("Failed to load city mapping:", err) + return + } + + http.HandleFunc("/add-distributor", addDistributor) + http.HandleFunc("/set-permission", setPermissions) + http.HandleFunc("/check-permission", checkPermission) + + fmt.Println("Server running on port 8080...") + http.ListenAndServe(":8080", nil) +} From 0117aeb4b255b0727c1521c98265870d08af4ebf Mon Sep 17 00:00:00 2001 From: Prabhaharan Date: Sun, 16 Mar 2025 19:42:53 +0530 Subject: [PATCH 2/2] Added the test file --- api_test.go | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 3 ++ 2 files changed, 105 insertions(+) create mode 100644 api_test.go create mode 100644 go.mod diff --git a/api_test.go b/api_test.go new file mode 100644 index 000000000..c4a0e1212 --- /dev/null +++ b/api_test.go @@ -0,0 +1,102 @@ +package main + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" +) + +// Test API endpoints +func TestAPIs(t *testing.T) { + // 1️.Test Add Distributor + t.Run("Add Distributor", func(t *testing.T) { + reqBody := []byte(`{"name": "DISTRIBUTOR1"}`) + req, err := http.NewRequest("POST", "/add-distributor", bytes.NewBuffer(reqBody)) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(addDistributor) + handler.ServeHTTP(rr, req) + + // if rr.Code != http.StatusOK { + // t.Errorf("Expected status OK, got %d", rr.Code) + // } + if rr.Code != http.StatusCreated { // 201 instead of 200 + t.Errorf("Expected status Created, got %d", rr.Code) + } + + }) + + // 2️. Test Set Permission + t.Run("Set Permission", func(t *testing.T) { + reqBody := []byte(`{ + "name": "DISTRIBUTOR1", + "includes": ["INDIA", "UNITEDSTATES"], + "excludes": ["KARNATAKA-INDIA", "CHENNAI-TAMILNADU-INDIA"] + }`) + req, err := http.NewRequest("POST", "/set-permission", bytes.NewBuffer(reqBody)) + if err != nil { + t.Fatal(err) + } + req.Header.Set("Content-Type", "application/json") + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(setPermissions) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("Expected status OK, got %d", rr.Code) + } + }) + + // 3️. Test Check Permission - Should return "YES" + t.Run("Check Permission - YES", func(t *testing.T) { + req, err := http.NewRequest("GET", "/check-permission?name=DISTRIBUTOR1®ion=CHICAGO-ILLINOIS-UNITEDSTATES", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(checkPermission) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("Expected status OK, got %d", rr.Code) + } + + var resp map[string]string + json.Unmarshal(rr.Body.Bytes(), &resp) + + if resp["permission"] != "YES" { + t.Errorf("Expected permission YES, got %s", resp["permission"]) + } + }) + + // 4️. Test Check Permission - Should return "NO" + t.Run("Check Permission - NO", func(t *testing.T) { + req, err := http.NewRequest("GET", "/check-permission?name=DISTRIBUTOR1®ion=CHENNAI-TAMILNADU-INDIA", nil) + if err != nil { + t.Fatal(err) + } + + rr := httptest.NewRecorder() + handler := http.HandlerFunc(checkPermission) + handler.ServeHTTP(rr, req) + + if rr.Code != http.StatusOK { + t.Errorf("Expected status OK, got %d", rr.Code) + } + + var resp map[string]string + json.Unmarshal(rr.Body.Bytes(), &resp) + + if resp["permission"] != "NO" { + t.Errorf("Expected permission NO, got %s", resp["permission"]) + } + }) +} diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..01d6cd3bd --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/prabhaharandev/distributor_api + +go 1.23.4