From b6c0d45f04e7ec39a135d13489267784f4400671 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Fri, 17 Oct 2025 22:50:56 +0530 Subject: [PATCH 01/11] folders added --- api/controllers/permissions.go | 1 + api/go.mod | 3 +++ api/main.go | 11 +++++++++++ api/services/permission.go | 1 + api/services/region.go | 11 +++++++++++ api/utils/types.go | 7 +++++++ 6 files changed, 34 insertions(+) create mode 100644 api/controllers/permissions.go create mode 100644 api/go.mod create mode 100644 api/main.go create mode 100644 api/services/permission.go create mode 100644 api/services/region.go create mode 100644 api/utils/types.go diff --git a/api/controllers/permissions.go b/api/controllers/permissions.go new file mode 100644 index 000000000..2d3293679 --- /dev/null +++ b/api/controllers/permissions.go @@ -0,0 +1 @@ +package controllers diff --git a/api/go.mod b/api/go.mod new file mode 100644 index 000000000..134257519 --- /dev/null +++ b/api/go.mod @@ -0,0 +1,3 @@ +module distributor-permissions + +go 1.21.1 diff --git a/api/main.go b/api/main.go new file mode 100644 index 000000000..07332c180 --- /dev/null +++ b/api/main.go @@ -0,0 +1,11 @@ +package main + +import ( + "log" + "net/http" +) + +func main() { + log.Println("Server listening to port 3001") + http.ListenAndServe(":3001", nil) +} diff --git a/api/services/permission.go b/api/services/permission.go new file mode 100644 index 000000000..6d43c3366 --- /dev/null +++ b/api/services/permission.go @@ -0,0 +1 @@ +package service diff --git a/api/services/region.go b/api/services/region.go new file mode 100644 index 000000000..e6e6ad164 --- /dev/null +++ b/api/services/region.go @@ -0,0 +1,11 @@ +package service + +import "distributor-permissions/utils" + +type RegionReciever struct { + RegionsList map[string]utils.Region +} + +func (rr *RegionReciever) LoadAllRegions() { + +} diff --git a/api/utils/types.go b/api/utils/types.go new file mode 100644 index 000000000..4ec2cab29 --- /dev/null +++ b/api/utils/types.go @@ -0,0 +1,7 @@ +package utils + +type Region struct { + Country string `json:"country"` + State string `json:"state"` + City string `json:"city"` +} From 4d84567b259910d22533b7acc238abea56d65132 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Fri, 17 Oct 2025 23:54:23 +0530 Subject: [PATCH 02/11] added function to read data from csv file --- api/config/constants.go | 9 ++++++++ api/main.go | 19 ++++++++++++++++ api/services/region.go | 50 ++++++++++++++++++++++++++++++++++++++--- api/utils/types.go | 8 +++---- 4 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 api/config/constants.go diff --git a/api/config/constants.go b/api/config/constants.go new file mode 100644 index 000000000..019aaadc1 --- /dev/null +++ b/api/config/constants.go @@ -0,0 +1,9 @@ +package config + +const ( + COUNTRY int = iota + PROVINCE + CITY + + CitiesFilePath = "../cities.csv" +) diff --git a/api/main.go b/api/main.go index 07332c180..2d1fc1758 100644 --- a/api/main.go +++ b/api/main.go @@ -1,11 +1,30 @@ package main import ( + service "distributor-permissions/services" "log" "net/http" ) func main() { + rr := service.RegionReciever{} + err := rr.LoadAllRegions() + if err != nil { + log.Println("Error loading regions=>", err) + return + } + // file, err := os.Create("RegionsList.txt") + // if err != nil { + // log.Println("Error creating file=>", err) + // return + // } + // marshal, err := json.Marshal(rr.AllRegions) + // if err != nil { + // log.Println("Error in byte=>", err) + // return + // } + // file.Write(marshal) + // file.Close() log.Println("Server listening to port 3001") http.ListenAndServe(":3001", nil) } diff --git a/api/services/region.go b/api/services/region.go index e6e6ad164..cad2bce96 100644 --- a/api/services/region.go +++ b/api/services/region.go @@ -1,11 +1,55 @@ package service -import "distributor-permissions/utils" +import ( + "distributor-permissions/config" + "distributor-permissions/utils" + "encoding/csv" + "errors" + "io" + "log" + "os" + "strings" +) type RegionReciever struct { - RegionsList map[string]utils.Region + AllRegions map[string]utils.RegionsList } -func (rr *RegionReciever) LoadAllRegions() { +func (rr *RegionReciever) LoadAllRegions() error { + file, err := os.Open(config.CitiesFilePath) + if err != nil { + log.Printf("File :services/region.go\nFunc: LoadAllRegions\nInfo: Error while opening cities.csv file\nError:%v\n", err) + return err + } + defer file.Close() + csvReader := csv.NewReader(file) + if csvReader == nil { + log.Printf("File :services/region.go\nFunc: LoadAllRegions\nInfo: No data in cities.csv file\nError: no data \n") + return errors.New("no data in cities.csv file") + } + rr.AllRegions = map[string]utils.RegionsList{} + for { + data, err := csvReader.Read() + if err == io.EOF { + break + } + if err != nil { + log.Printf("File :services/region.go\nFunc: LoadAllRegions\nInfo: Error reading record from file\nError: %v \n", err) + return err + } + + city := strings.ToUpper(data[3]) + province := strings.ToUpper(data[4]) + country := strings.ToUpper(data[5]) + + if _, ok := rr.AllRegions[country]; !ok { + rr.AllRegions[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: make(map[string]utils.RegionsList)} + } + if _, ok := rr.AllRegions[country].Regions[province]; !ok { + rr.AllRegions[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: make(map[string]utils.RegionsList)} + } + rr.AllRegions[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} + } + return nil } diff --git a/api/utils/types.go b/api/utils/types.go index 4ec2cab29..c3b60490f 100644 --- a/api/utils/types.go +++ b/api/utils/types.go @@ -1,7 +1,7 @@ package utils -type Region struct { - Country string `json:"country"` - State string `json:"state"` - City string `json:"city"` +type RegionsList struct { + Name string + Type int + Regions map[string]RegionsList } From ff3b9d93165e9de4d7a6c05a631324bbd5c36be7 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Sat, 18 Oct 2025 02:44:49 +0530 Subject: [PATCH 03/11] initial include permission code --- api/main.go | 50 +++++++++++++++++++++ api/services/permission.go | 90 ++++++++++++++++++++++++++++++++++++++ api/utils/types.go | 6 +++ 3 files changed, 146 insertions(+) diff --git a/api/main.go b/api/main.go index 2d1fc1758..9fc53c17e 100644 --- a/api/main.go +++ b/api/main.go @@ -2,6 +2,8 @@ package main import ( service "distributor-permissions/services" + "distributor-permissions/utils" + "fmt" "log" "net/http" ) @@ -13,6 +15,54 @@ func main() { log.Println("Error loading regions=>", err) return } + + pr := &service.PermissionsReceiver{} + pr.Regions = rr.AllRegions + pr.DistributorPermissions = make(map[string]utils.DistributorData) + include := []string{"INDIA"} + exclude := []string{} + data, err := pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case1=> adding India", data) + + include = []string{"AFGHANISTAN"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case2=> adding AFGHANISTAN", data) + + include = []string{"AFGHANISTAN", "INDIA"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case3=> adding AFGHANISTAN, INDIA", data) + + include = []string{"BADAKHSHAN-AFGHANISTAN"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case4=> adding BADAKHSHAN-AFGHANISTAN", data) + + include = []string{"ASHKASHAM-BADAKHSHAN-AFGHANISTAN"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case5=> adding ASHKASHAM-BADAKHSHAN-AFGHANISTAN", data) + + include = []string{"ANDAMAN AND NICOBAR ISLANDS-INDIA"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case6=> adding ANDAMAN AND NICOBAR ISLANDS-INDIA", data) + + include = []string{"BAHARAK-BADAKHSHAN-AFGHANISTAN"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case5=> adding BAHARAK-BADAKHSHAN-AFGHANISTAN", data) + + include = []string{"BAH1111ARAK-BADAKHSHAN-AFGHANISTAN"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case5=> adding BAH111ARAK-BADAKHSHAN-AFGHANISTAN", data) + + include = []string{"ANDAMAN ANDY NICOBAR ISLANDS-INDIA"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case6=> adding ANDAMAN ANDY NICOBAR ISLANDS-INDIA", data) + + include = []string{"AFGHANISTAN555", "INDIA"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case3=> adding AFGHANISTAN555, INDIA", data) + + include = []string{"DARAYIM-BADAKHSHAN-AFGHANISTAN", "CHAKARAN-BADAKHSHAN-AFGHANISTAN"} + data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) + fmt.Println("case5=> adding DARAYIM-BADAKHSHAN-AFGHANISTAN CHAKARAN-BADAKHSHAN-AFGHANISTAN", data) // file, err := os.Create("RegionsList.txt") // if err != nil { // log.Println("Error creating file=>", err) diff --git a/api/services/permission.go b/api/services/permission.go index 6d43c3366..e9ac9c217 100644 --- a/api/services/permission.go +++ b/api/services/permission.go @@ -1 +1,91 @@ package service + +import ( + "distributor-permissions/config" + "distributor-permissions/utils" + "log" + "strings" +) + +type PermissionsReceiver struct { + DistributorPermissions map[string]utils.DistributorData + Regions map[string]utils.RegionsList +} + +func (pr *PermissionsReceiver) UpdateDistributorPermissions(distributor string, include, exclude []string) (utils.DistributorData, error) { + if _, ok := pr.DistributorPermissions[distributor]; !ok { + pr.DistributorPermissions[distributor] = utils.DistributorData{Name: distributor, Include: make(map[string]utils.RegionsList), Exclude: map[string]utils.RegionsList{}} + } + + for _, v := range include { + pr.updateRegionPermissions(v, distributor, true) + } + return pr.DistributorPermissions[distributor], nil +} + +func (pr *PermissionsReceiver) updateRegionPermissions(region string, distributor string, include bool) { + list := strings.Split(region, "-") + listLen := len(list) + if listLen == 1 { + if _, ok := pr.Regions[list[0]]; !ok { + log.Printf("File :services/permission.go\nFunc: UpdateRegionPermissions\nInfo: Region %v Not Found\n", region) + return + } + if include { + if _, ok := pr.DistributorPermissions[distributor].Include[list[0]]; !ok { + pr.addCountry(distributor, list[0], include) + } + } + } + if listLen == 2 { + if _, ok := pr.Regions[list[1]].Regions[list[0]]; !ok { + log.Printf("File :services/permission.go\nFunc: UpdateRegionPermissions\nInfo: Region %v Not Found\n", region) + return + } + if include { + if _, ok := pr.DistributorPermissions[distributor].Include[list[1]]; !ok { + pr.addCountry(distributor, list[1], include) + pr.addProvince(distributor, list[1], list[0], include) + + } else if _, ok := pr.DistributorPermissions[distributor].Include[list[1]].Regions[list[0]]; !ok { + pr.addProvince(distributor, list[1], list[0], include) + } + } + } + if listLen == 3 { + if _, ok := pr.Regions[list[2]].Regions[list[1]].Regions[list[0]]; !ok { + log.Printf("File :services/permission.go\nFunc: UpdateRegionPermissions\nInfo: Region %v Not Found\n", region) + return + } + if include { + if _, ok := pr.DistributorPermissions[distributor].Include[list[2]]; !ok { + pr.addCountry(distributor, list[2], include) + pr.addProvince(distributor, list[2], list[1], include) + pr.addCity(distributor, list[2], list[1], list[0], include) + } else if _, ok := pr.DistributorPermissions[distributor].Include[list[2]].Regions[list[1]]; !ok { + pr.addProvince(distributor, list[2], list[1], include) + pr.addCity(distributor, list[2], list[1], list[0], include) + } else { + pr.addCity(distributor, list[2], list[1], list[0], include) + + } + } + } +} + +func (pr *PermissionsReceiver) addCountry(distributor, country string, include bool) { + if include { + pr.DistributorPermissions[distributor].Include[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: map[string]utils.RegionsList{}} + } +} + +func (pr *PermissionsReceiver) addProvince(distributor, country, province string, include bool) { + if include { + pr.DistributorPermissions[distributor].Include[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: map[string]utils.RegionsList{}} + } +} +func (pr *PermissionsReceiver) addCity(distributor, country, province, city string, include bool) { + if include { + pr.DistributorPermissions[distributor].Include[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} + } +} diff --git a/api/utils/types.go b/api/utils/types.go index c3b60490f..62c390dc5 100644 --- a/api/utils/types.go +++ b/api/utils/types.go @@ -5,3 +5,9 @@ type RegionsList struct { Type int Regions map[string]RegionsList } + +type DistributorData struct { + Name string `json:"name"` + Include map[string]RegionsList `json:"include"` + Exclude map[string]RegionsList `json:"exclude"` +} From caf2c0c76fd607058489e51465897c0a0b83223a Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Sat, 18 Oct 2025 18:08:27 +0530 Subject: [PATCH 04/11] updated permission logic --- api/services/permission.go | 111 +++++++++++++++++++++++++++++++------ 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/api/services/permission.go b/api/services/permission.go index e9ac9c217..f2e9c6b25 100644 --- a/api/services/permission.go +++ b/api/services/permission.go @@ -18,74 +18,151 @@ func (pr *PermissionsReceiver) UpdateDistributorPermissions(distributor string, } for _, v := range include { - pr.updateRegionPermissions(v, distributor, true) + pr.updatePermissions(v, distributor, true) + } + for _, v := range exclude { + pr.updatePermissions(v, distributor, false) } return pr.DistributorPermissions[distributor], nil } -func (pr *PermissionsReceiver) updateRegionPermissions(region string, distributor string, include bool) { +func (pr *PermissionsReceiver) updatePermissions(region string, distributor string, include bool) { list := strings.Split(region, "-") listLen := len(list) if listLen == 1 { - if _, ok := pr.Regions[list[0]]; !ok { - log.Printf("File :services/permission.go\nFunc: UpdateRegionPermissions\nInfo: Region %v Not Found\n", region) + if !pr.isCountryAllowed(list[0]) { return } if include { if _, ok := pr.DistributorPermissions[distributor].Include[list[0]]; !ok { pr.addCountry(distributor, list[0], include) + delete(pr.DistributorPermissions[distributor].Exclude, list[0]) + } + } else { + if _, ok := pr.DistributorPermissions[distributor].Exclude[list[0]]; !ok { + pr.addCountry(distributor, list[0], include) + delete(pr.DistributorPermissions[distributor].Include, list[0]) } } } + if listLen == 2 { - if _, ok := pr.Regions[list[1]].Regions[list[0]]; !ok { - log.Printf("File :services/permission.go\nFunc: UpdateRegionPermissions\nInfo: Region %v Not Found\n", region) + if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; !pr.isProvinceAllowed(list[1], list[0]) && ok { + log.Printf("Country %s is excluded in the permission list of distributor %s\n", list[1], distributor) return } if include { if _, ok := pr.DistributorPermissions[distributor].Include[list[1]]; !ok { - pr.addCountry(distributor, list[1], include) - pr.addProvince(distributor, list[1], list[0], include) - + //***********should be allowed in country first so deleteing 2 lines and returning******************// + // pr.addCountry(distributor, list[1], include) + // pr.addProvince(distributor, list[1], list[0], include) + //delete(pr.DistributorPermissions[distributor].Exclude, list[1]) + log.Printf("Country %s not included in the permission list of distributor %s\n", list[1], distributor) + return } else if _, ok := pr.DistributorPermissions[distributor].Include[list[1]].Regions[list[0]]; !ok { pr.addProvince(distributor, list[1], list[0], include) + //delete(pr.DistributorPermissions[distributor].Exclude[list[1]].Regions, list[0]) } } + // else { + // if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; !ok { + // pr.addCountry(distributor, list[1], include) + // pr.addProvince(distributor, list[1], list[0], include) + // //delete(pr.DistributorPermissions[distributor].Include, list[1]) + // } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]].Regions[list[0]]; !ok { + // pr.addProvince(distributor, list[1], list[0], include) + // //delete(pr.DistributorPermissions[distributor].Include[list[1]].Regions, list[0]) + // } + // } } + if listLen == 3 { - if _, ok := pr.Regions[list[2]].Regions[list[1]].Regions[list[0]]; !ok { - log.Printf("File :services/permission.go\nFunc: UpdateRegionPermissions\nInfo: Region %v Not Found\n", region) + if !pr.isCityAllowed(list[2], list[1], list[0]) { + return + } + + _, isCountryExcluded := pr.DistributorPermissions[distributor].Exclude[list[2]] + _, isProvinceExcluded := pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]] + + if isCountryExcluded || isProvinceExcluded { + log.Printf("Country %s and/or Province %s excluded in the permission list of distributor %s\n", list[2], list[1], distributor) return } + if include { if _, ok := pr.DistributorPermissions[distributor].Include[list[2]]; !ok { - pr.addCountry(distributor, list[2], include) - pr.addProvince(distributor, list[2], list[1], include) - pr.addCity(distributor, list[2], list[1], list[0], include) + //***********should be allowed in country first so deleteing 2 lines and returning******************// + // pr.addCountry(distributor, list[2], include) + // pr.addProvince(distributor, list[2], list[1], include) + // pr.addCity(distributor, list[2], list[1], list[0], include) + //delete(pr.DistributorPermissions[distributor].Exclude, list[2]) + log.Printf("Country %s not included in the permission list of distributor %s\n", list[2], distributor) + return } else if _, ok := pr.DistributorPermissions[distributor].Include[list[2]].Regions[list[1]]; !ok { - pr.addProvince(distributor, list[2], list[1], include) - pr.addCity(distributor, list[2], list[1], list[0], include) + //***********should be allowed in province first so deleteing 2 lines and returning******************// + // pr.addProvince(distributor, list[2], list[1], include) + // pr.addCity(distributor, list[2], list[1], list[0], include) + //delete(pr.DistributorPermissions[distributor].Exclude[list[2]].Regions, list[1]) + log.Printf("Province %s of Country %s not included in the permission list of distributor %s\n", list[1], list[2], distributor) + return } else { pr.addCity(distributor, list[2], list[1], list[0], include) - + delete(pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]].Regions, list[0]) } } + // else { + // if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]]; !ok { + // pr.addCountry(distributor, list[2], include) + // pr.addProvince(distributor, list[2], list[1], include) + // pr.addCity(distributor, list[2], list[1], list[0], include) + // //delete(pr.DistributorPermissions[distributor].Include, list[2]) + // } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]]; !ok { + // pr.addProvince(distributor, list[2], list[1], include) + // pr.addCity(distributor, list[2], list[1], list[0], include) + // //delete(pr.DistributorPermissions[distributor].Include[list[2]].Regions, list[1]) + // } else { + // pr.addCity(distributor, list[2], list[1], list[0], include) + // //delete(pr.DistributorPermissions[distributor].Include[list[2]].Regions[list[1]].Regions, list[0]) + // } + // } + } } func (pr *PermissionsReceiver) addCountry(distributor, country string, include bool) { if include { pr.DistributorPermissions[distributor].Include[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: map[string]utils.RegionsList{}} + } else { + pr.DistributorPermissions[distributor].Exclude[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: map[string]utils.RegionsList{}} } } func (pr *PermissionsReceiver) addProvince(distributor, country, province string, include bool) { if include { pr.DistributorPermissions[distributor].Include[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: map[string]utils.RegionsList{}} + } else { + pr.DistributorPermissions[distributor].Exclude[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: map[string]utils.RegionsList{}} } } func (pr *PermissionsReceiver) addCity(distributor, country, province, city string, include bool) { if include { pr.DistributorPermissions[distributor].Include[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} + } else { + pr.DistributorPermissions[distributor].Exclude[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} } } + +func (pr *PermissionsReceiver) isCountryAllowed(country string) bool { + _, ok := pr.Regions[country] + return ok +} + +func (pr *PermissionsReceiver) isProvinceAllowed(country string, province string) bool { + _, ok := pr.Regions[country].Regions[province] + return ok +} + +func (pr *PermissionsReceiver) isCityAllowed(country, province, city string) bool { + _, ok := pr.Regions[country].Regions[province].Regions[city] + return ok +} From 60b82bd9ad7d08df0df25c5fecc0609e36275264 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Thu, 23 Oct 2025 00:43:03 +0530 Subject: [PATCH 05/11] completed permission function for distributor --- api/main.go | 47 +------- api/services/permission.go | 222 ++++++++++++++++++++++--------------- api/services/region.go | 38 +++++-- api/utils/types.go | 7 ++ 4 files changed, 169 insertions(+), 145 deletions(-) diff --git a/api/main.go b/api/main.go index 9fc53c17e..337cc9fc0 100644 --- a/api/main.go +++ b/api/main.go @@ -17,52 +17,13 @@ func main() { } pr := &service.PermissionsReceiver{} - pr.Regions = rr.AllRegions pr.DistributorPermissions = make(map[string]utils.DistributorData) - include := []string{"INDIA"} + pr.RegionR = &rr + include := []string{"AN-IN", "AP-IN"} exclude := []string{} - data, err := pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case1=> adding India", data) + data, err := pr.UpdateDistributorPermissions("DISTRIBUTOR2", include, exclude) + fmt.Printf("case1=> %+v", data) - include = []string{"AFGHANISTAN"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case2=> adding AFGHANISTAN", data) - - include = []string{"AFGHANISTAN", "INDIA"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case3=> adding AFGHANISTAN, INDIA", data) - - include = []string{"BADAKHSHAN-AFGHANISTAN"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case4=> adding BADAKHSHAN-AFGHANISTAN", data) - - include = []string{"ASHKASHAM-BADAKHSHAN-AFGHANISTAN"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case5=> adding ASHKASHAM-BADAKHSHAN-AFGHANISTAN", data) - - include = []string{"ANDAMAN AND NICOBAR ISLANDS-INDIA"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case6=> adding ANDAMAN AND NICOBAR ISLANDS-INDIA", data) - - include = []string{"BAHARAK-BADAKHSHAN-AFGHANISTAN"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case5=> adding BAHARAK-BADAKHSHAN-AFGHANISTAN", data) - - include = []string{"BAH1111ARAK-BADAKHSHAN-AFGHANISTAN"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case5=> adding BAH111ARAK-BADAKHSHAN-AFGHANISTAN", data) - - include = []string{"ANDAMAN ANDY NICOBAR ISLANDS-INDIA"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case6=> adding ANDAMAN ANDY NICOBAR ISLANDS-INDIA", data) - - include = []string{"AFGHANISTAN555", "INDIA"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case3=> adding AFGHANISTAN555, INDIA", data) - - include = []string{"DARAYIM-BADAKHSHAN-AFGHANISTAN", "CHAKARAN-BADAKHSHAN-AFGHANISTAN"} - data, err = pr.UpdateDistributorPermissions("DISTRIBUTOR1", include, exclude) - fmt.Println("case5=> adding DARAYIM-BADAKHSHAN-AFGHANISTAN CHAKARAN-BADAKHSHAN-AFGHANISTAN", data) // file, err := os.Create("RegionsList.txt") // if err != nil { // log.Println("Error creating file=>", err) diff --git a/api/services/permission.go b/api/services/permission.go index f2e9c6b25..543fd77ad 100644 --- a/api/services/permission.go +++ b/api/services/permission.go @@ -1,7 +1,6 @@ package service import ( - "distributor-permissions/config" "distributor-permissions/utils" "log" "strings" @@ -9,7 +8,7 @@ import ( type PermissionsReceiver struct { DistributorPermissions map[string]utils.DistributorData - Regions map[string]utils.RegionsList + RegionR *RegionReciever } func (pr *PermissionsReceiver) UpdateDistributorPermissions(distributor string, include, exclude []string) (utils.DistributorData, error) { @@ -26,143 +25,182 @@ func (pr *PermissionsReceiver) UpdateDistributorPermissions(distributor string, return pr.DistributorPermissions[distributor], nil } -func (pr *PermissionsReceiver) updatePermissions(region string, distributor string, include bool) { - list := strings.Split(region, "-") +func (pr *PermissionsReceiver) updatePermissions(regionCode string, distributor string, include bool) { + list := strings.Split(regionCode, "-") listLen := len(list) if listLen == 1 { - if !pr.isCountryAllowed(list[0]) { + // list[0] is country code + data, ok := pr.RegionR.IsCountryAllowed(list[0]) + if !ok { + log.Printf("Country %s is not available\n", list[0]) return } if include { if _, ok := pr.DistributorPermissions[distributor].Include[list[0]]; !ok { - pr.addCountry(distributor, list[0], include) - delete(pr.DistributorPermissions[distributor].Exclude, list[0]) + pr.addCountry(distributor, data, include) + } + //case1: exclude list has only country and no province and no cities eg:exclude:[IN], include:[IN] + //case2: exclude list has country and province , no cities eg:exclude:[KA-IN], include:[IN] // do nothing + //case3: exclude list has country, province and cities ef:exclude:[ANEKL_KA_IN], include:[IN] //do nothing + if countryPointer, ok := pr.DistributorPermissions[distributor].Exclude[list[0]]; ok { + if len(countryPointer.Regions) == 0 { + //case1: delete + delete(pr.DistributorPermissions[distributor].Exclude, list[0]) + } } } else { if _, ok := pr.DistributorPermissions[distributor].Exclude[list[0]]; !ok { - pr.addCountry(distributor, list[0], include) - delete(pr.DistributorPermissions[distributor].Include, list[0]) + pr.addCountry(distributor, data, include) } + //case1: include list has only country and no province and no cities eg:include:[IN], exclude:[IN] + //case2: include list has country and province , no cities eg:include:[KA-IN], exclude:[IN] + //case3: include list has country, province and cities ef:include:[ANEKL_KA_IN], exclude:[IN] + delete(pr.DistributorPermissions[distributor].Include, list[0]) } } if listLen == 2 { - if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; !pr.isProvinceAllowed(list[1], list[0]) && ok { - log.Printf("Country %s is excluded in the permission list of distributor %s\n", list[1], distributor) + // list[0] is province code + // list[1] is country code + cdata, pData, ok := pr.RegionR.IsProvinceAllowed(list[1], list[0]) + if !ok { + log.Printf("Country %s with province %s is not available\n", list[1], list[0]) return } if include { if _, ok := pr.DistributorPermissions[distributor].Include[list[1]]; !ok { - //***********should be allowed in country first so deleteing 2 lines and returning******************// - // pr.addCountry(distributor, list[1], include) - // pr.addProvince(distributor, list[1], list[0], include) - //delete(pr.DistributorPermissions[distributor].Exclude, list[1]) - log.Printf("Country %s not included in the permission list of distributor %s\n", list[1], distributor) - return + //if country is not included, include both country and province + pr.addCountry(distributor, cdata, include) + pr.addProvince(distributor, cdata.Code, pData, include) } else if _, ok := pr.DistributorPermissions[distributor].Include[list[1]].Regions[list[0]]; !ok { - pr.addProvince(distributor, list[1], list[0], include) - //delete(pr.DistributorPermissions[distributor].Exclude[list[1]].Regions, list[0]) + pr.addProvince(distributor, cdata.Code, pData, include) + } + + //deleting from exclude list + //case1: exclude list has only country eg: exclude:[IN] include:[MH-IN] + //case2: exclude list has country and one province mentioned in include list and no cities eg:= exclude=[MH-IN] include=[MH-IN] + //case3: exclude list has country and one province mentioned in include list and has cities eg:= exclude=[PUNE-MH-IN] include=[MH-IN] + //case4: exclude list has country and province mentioned in provinces and no cities eg:=exclude:[MH-IN, KA-IN] include:[MH-IN] + if countryPointer, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; ok { + if len(countryPointer.Regions) == 0 { + //case 1: delete country + delete(pr.DistributorPermissions[distributor].Exclude, list[1]) + } else if provincePtr, ok := countryPointer.Regions[list[0]]; ok { + if len(countryPointer.Regions) == 1 && len(provincePtr.Regions) == 0 { + //case 2: delete country + delete(pr.DistributorPermissions[distributor].Exclude, list[1]) + } else if len(provincePtr.Regions) == 0 { + //case 4: delete province + delete(countryPointer.Regions, list[0]) + } + //case 3: dont delete country or province + } + } + + } else { + if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; !ok { + //if country is not excluded, include both country and province + pr.addCountry(distributor, cdata, include) + pr.addProvince(distributor, cdata.Code, pData, include) + } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]].Regions[list[0]]; !ok { + pr.addProvince(distributor, cdata.Code, pData, include) + } + //deleting from include list + //case1:include list has only country: do nothing eg: include: IN exclude:AN-IN + //case2: include list has country and one province mentioned in exclude list and no cities eg: include: MH-IN exclude: MH-IN + //case3: include list has country and one province mentioned in exclude list and has cities eg:include: PUNE-MH-IN exclude: MH-IN + if countryPtr, ok := pr.DistributorPermissions[distributor].Include[list[1]]; ok { + //case2&3: delete province + delete(countryPtr.Regions, list[0]) } } - // else { - // if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; !ok { - // pr.addCountry(distributor, list[1], include) - // pr.addProvince(distributor, list[1], list[0], include) - // //delete(pr.DistributorPermissions[distributor].Include, list[1]) - // } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]].Regions[list[0]]; !ok { - // pr.addProvince(distributor, list[1], list[0], include) - // //delete(pr.DistributorPermissions[distributor].Include[list[1]].Regions, list[0]) - // } - // } } if listLen == 3 { - if !pr.isCityAllowed(list[2], list[1], list[0]) { - return - } - - _, isCountryExcluded := pr.DistributorPermissions[distributor].Exclude[list[2]] - _, isProvinceExcluded := pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]] - - if isCountryExcluded || isProvinceExcluded { - log.Printf("Country %s and/or Province %s excluded in the permission list of distributor %s\n", list[2], list[1], distributor) + //list[0] is city code + // list[1] is province code + // list[2] is country code + countryData, pData, cityData, ok := pr.RegionR.IsCityAllowed(list[2], list[1], list[0]) + if !ok { + log.Printf("Country %s with province %s and city %s is not available\n", list[2], list[1], list[0]) return } if include { if _, ok := pr.DistributorPermissions[distributor].Include[list[2]]; !ok { - //***********should be allowed in country first so deleteing 2 lines and returning******************// - // pr.addCountry(distributor, list[2], include) - // pr.addProvince(distributor, list[2], list[1], include) - // pr.addCity(distributor, list[2], list[1], list[0], include) - //delete(pr.DistributorPermissions[distributor].Exclude, list[2]) - log.Printf("Country %s not included in the permission list of distributor %s\n", list[2], distributor) - return + pr.addCountry(distributor, countryData, include) + pr.addProvince(distributor, countryData.Code, pData, include) + pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) } else if _, ok := pr.DistributorPermissions[distributor].Include[list[2]].Regions[list[1]]; !ok { - //***********should be allowed in province first so deleteing 2 lines and returning******************// - // pr.addProvince(distributor, list[2], list[1], include) - // pr.addCity(distributor, list[2], list[1], list[0], include) - //delete(pr.DistributorPermissions[distributor].Exclude[list[2]].Regions, list[1]) - log.Printf("Province %s of Country %s not included in the permission list of distributor %s\n", list[1], list[2], distributor) - return + pr.addProvince(distributor, countryData.Code, pData, include) + pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) + } else { + pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) + } + + //deleteing city from exclude list + //case1: exclude list has only country and no province eg:exclude:[IN] include:[PUNE-MH-IN] + //case2: exclude list has country and province and no cities eg:exclude:[MH-In] include:[PUNE-MH-IN] + //case3: exclude list has country and province with diff cities eg:exclude:[PUNE-MH-In, MUMBAI-MH-IN] include:[PUNE-MH-IN] + if countryPointer, ok := pr.DistributorPermissions[distributor].Exclude[list[2]]; ok { + if len(countryPointer.Regions) == 0 { + //case 1: delete country + delete(pr.DistributorPermissions[distributor].Exclude, list[2]) + } else if provincePtr, ok := countryPointer.Regions[list[1]]; ok { + //case 3: delete city + delete(provincePtr.Regions, list[0]) + if len(provincePtr.Regions) == 0 { + //case 2:delete province + delete(countryPointer.Regions, provincePtr.Code) + } + } + } + } else { + if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]]; !ok { + pr.addCountry(distributor, countryData, include) + pr.addProvince(distributor, countryData.Code, pData, include) + pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) + } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]]; !ok { + pr.addProvince(distributor, countryData.Code, pData, include) + pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) } else { - pr.addCity(distributor, list[2], list[1], list[0], include) - delete(pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]].Regions, list[0]) + pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) + } + + //deleteing city from include list + //case1: include list has only country and no province eg:include:[IN] exclude:[PUNE-MH-IN] // do nothing + //case2: include list has country and province and no cities eg:include:[MH-In] exclude:[PUNE-MH-IN] //do nothing + //case3: include list has country and province with diff cities eg:exclude:[PUNE-MH-In, MUMBAI-MH-IN] include:[PUNE-MH-IN] + if countryPointer, ok := pr.DistributorPermissions[distributor].Include[list[2]]; ok { + if provincePtr, ok := countryPointer.Regions[list[1]]; ok { + //case 3: delete city + delete(provincePtr.Regions, list[0]) + } } } - // else { - // if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]]; !ok { - // pr.addCountry(distributor, list[2], include) - // pr.addProvince(distributor, list[2], list[1], include) - // pr.addCity(distributor, list[2], list[1], list[0], include) - // //delete(pr.DistributorPermissions[distributor].Include, list[2]) - // } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]]; !ok { - // pr.addProvince(distributor, list[2], list[1], include) - // pr.addCity(distributor, list[2], list[1], list[0], include) - // //delete(pr.DistributorPermissions[distributor].Include[list[2]].Regions, list[1]) - // } else { - // pr.addCity(distributor, list[2], list[1], list[0], include) - // //delete(pr.DistributorPermissions[distributor].Include[list[2]].Regions[list[1]].Regions, list[0]) - // } - // } } } -func (pr *PermissionsReceiver) addCountry(distributor, country string, include bool) { +func (pr *PermissionsReceiver) addCountry(distributor string, data utils.Region, include bool) { if include { - pr.DistributorPermissions[distributor].Include[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor].Include[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} } else { - pr.DistributorPermissions[distributor].Exclude[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor].Exclude[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} } } -func (pr *PermissionsReceiver) addProvince(distributor, country, province string, include bool) { +func (pr *PermissionsReceiver) addProvince(distributor, countryCode string, data utils.Region, include bool) { if include { - pr.DistributorPermissions[distributor].Include[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor].Include[countryCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} } else { - pr.DistributorPermissions[distributor].Exclude[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor].Exclude[countryCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} } } -func (pr *PermissionsReceiver) addCity(distributor, country, province, city string, include bool) { +func (pr *PermissionsReceiver) addCity(distributor, countryCode, provinceCode string, data utils.Region, include bool) { if include { - pr.DistributorPermissions[distributor].Include[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} + pr.DistributorPermissions[distributor].Include[countryCode].Regions[provinceCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code} } else { - pr.DistributorPermissions[distributor].Exclude[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} + pr.DistributorPermissions[distributor].Exclude[countryCode].Regions[provinceCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code} } } - -func (pr *PermissionsReceiver) isCountryAllowed(country string) bool { - _, ok := pr.Regions[country] - return ok -} - -func (pr *PermissionsReceiver) isProvinceAllowed(country string, province string) bool { - _, ok := pr.Regions[country].Regions[province] - return ok -} - -func (pr *PermissionsReceiver) isCityAllowed(country, province, city string) bool { - _, ok := pr.Regions[country].Regions[province].Regions[city] - return ok -} diff --git a/api/services/region.go b/api/services/region.go index cad2bce96..069f14d0c 100644 --- a/api/services/region.go +++ b/api/services/region.go @@ -4,7 +4,6 @@ import ( "distributor-permissions/config" "distributor-permissions/utils" "encoding/csv" - "errors" "io" "log" "os" @@ -20,13 +19,13 @@ func (rr *RegionReciever) LoadAllRegions() error { file, err := os.Open(config.CitiesFilePath) if err != nil { log.Printf("File :services/region.go\nFunc: LoadAllRegions\nInfo: Error while opening cities.csv file\nError:%v\n", err) - return err + return nil } defer file.Close() csvReader := csv.NewReader(file) if csvReader == nil { log.Printf("File :services/region.go\nFunc: LoadAllRegions\nInfo: No data in cities.csv file\nError: no data \n") - return errors.New("no data in cities.csv file") + return nil } rr.AllRegions = map[string]utils.RegionsList{} for { @@ -36,20 +35,39 @@ func (rr *RegionReciever) LoadAllRegions() error { } if err != nil { log.Printf("File :services/region.go\nFunc: LoadAllRegions\nInfo: Error reading record from file\nError: %v \n", err) - return err + return nil } - + cityCode := strings.ToUpper(data[0]) + provinceCode := strings.ToUpper(data[1]) + countryCode := strings.ToUpper(data[2]) city := strings.ToUpper(data[3]) province := strings.ToUpper(data[4]) country := strings.ToUpper(data[5]) - if _, ok := rr.AllRegions[country]; !ok { - rr.AllRegions[country] = utils.RegionsList{Name: country, Type: config.COUNTRY, Regions: make(map[string]utils.RegionsList)} + if _, ok := rr.AllRegions[countryCode]; !ok { + rr.AllRegions[countryCode] = utils.RegionsList{Code: countryCode, Name: country, Type: config.COUNTRY, Regions: make(map[string]utils.RegionsList)} } - if _, ok := rr.AllRegions[country].Regions[province]; !ok { - rr.AllRegions[country].Regions[province] = utils.RegionsList{Name: province, Type: config.PROVINCE, Regions: make(map[string]utils.RegionsList)} + if _, ok := rr.AllRegions[countryCode].Regions[provinceCode]; !ok { + rr.AllRegions[countryCode].Regions[provinceCode] = utils.RegionsList{Code: provinceCode, Name: province, Type: config.PROVINCE, Regions: make(map[string]utils.RegionsList)} } - rr.AllRegions[country].Regions[province].Regions[city] = utils.RegionsList{Name: city, Type: config.CITY} + rr.AllRegions[countryCode].Regions[provinceCode].Regions[cityCode] = utils.RegionsList{Code: cityCode, Name: city, Type: config.CITY} } return nil } + +func (rr *RegionReciever) IsCountryAllowed(country string) (utils.Region, bool) { + data, ok := rr.AllRegions[country] + return utils.Region{Name: data.Name, Code: data.Code, Type: data.Type}, ok +} + +func (rr *RegionReciever) IsProvinceAllowed(country string, province string) (utils.Region, utils.Region, bool) { + cData, cok := rr.IsCountryAllowed(country) + pData, pok := rr.AllRegions[country].Regions[province] + return cData, utils.Region{Name: pData.Name, Code: pData.Code, Type: pData.Type}, cok && pok +} + +func (rr *RegionReciever) IsCityAllowed(country, province, city string) (utils.Region, utils.Region, utils.Region, bool) { + countryData, pData, cpOk := rr.IsProvinceAllowed(country, province) + cData, cok := rr.AllRegions[country].Regions[province].Regions[city] + return countryData, pData, utils.Region{Name: cData.Name, Code: cData.Code, Type: cData.Type}, cok && cpOk +} diff --git a/api/utils/types.go b/api/utils/types.go index 62c390dc5..066dd4441 100644 --- a/api/utils/types.go +++ b/api/utils/types.go @@ -3,6 +3,7 @@ package utils type RegionsList struct { Name string Type int + Code string Regions map[string]RegionsList } @@ -11,3 +12,9 @@ type DistributorData struct { Include map[string]RegionsList `json:"include"` Exclude map[string]RegionsList `json:"exclude"` } + +type Region struct { + Name string + Type int + Code string +} From 06a591b11e561281df6e41ffd757555b958a03b0 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Thu, 23 Oct 2025 17:28:03 +0530 Subject: [PATCH 06/11] updated permissions and region check functions --- api/services/distributors.go | 1 + api/services/permission.go | 260 ++++++++++++++++++----------------- api/services/region.go | 14 +- api/utils/types.go | 6 +- 4 files changed, 148 insertions(+), 133 deletions(-) create mode 100644 api/services/distributors.go diff --git a/api/services/distributors.go b/api/services/distributors.go new file mode 100644 index 000000000..6d43c3366 --- /dev/null +++ b/api/services/distributors.go @@ -0,0 +1 @@ +package service diff --git a/api/services/permission.go b/api/services/permission.go index 543fd77ad..566ad8f2d 100644 --- a/api/services/permission.go +++ b/api/services/permission.go @@ -13,7 +13,7 @@ type PermissionsReceiver struct { func (pr *PermissionsReceiver) UpdateDistributorPermissions(distributor string, include, exclude []string) (utils.DistributorData, error) { if _, ok := pr.DistributorPermissions[distributor]; !ok { - pr.DistributorPermissions[distributor] = utils.DistributorData{Name: distributor, Include: make(map[string]utils.RegionsList), Exclude: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor] = utils.DistributorData{Name: distributor, Include: make(map[string]bool), Exclude: make(map[string]bool)} } for _, v := range include { @@ -30,89 +30,42 @@ func (pr *PermissionsReceiver) updatePermissions(regionCode string, distributor listLen := len(list) if listLen == 1 { // list[0] is country code - data, ok := pr.RegionR.IsCountryAllowed(list[0]) + country, ok := pr.RegionR.IsCountryAllowed(strings.TrimSpace(list[0])) if !ok { log.Printf("Country %s is not available\n", list[0]) return } if include { - if _, ok := pr.DistributorPermissions[distributor].Include[list[0]]; !ok { - pr.addCountry(distributor, data, include) - } - //case1: exclude list has only country and no province and no cities eg:exclude:[IN], include:[IN] - //case2: exclude list has country and province , no cities eg:exclude:[KA-IN], include:[IN] // do nothing - //case3: exclude list has country, province and cities ef:exclude:[ANEKL_KA_IN], include:[IN] //do nothing - if countryPointer, ok := pr.DistributorPermissions[distributor].Exclude[list[0]]; ok { - if len(countryPointer.Regions) == 0 { - //case1: delete - delete(pr.DistributorPermissions[distributor].Exclude, list[0]) - } - } + pr.AddRegion(distributor, country.Code, include) } else { - if _, ok := pr.DistributorPermissions[distributor].Exclude[list[0]]; !ok { - pr.addCountry(distributor, data, include) - } - //case1: include list has only country and no province and no cities eg:include:[IN], exclude:[IN] - //case2: include list has country and province , no cities eg:include:[KA-IN], exclude:[IN] - //case3: include list has country, province and cities ef:include:[ANEKL_KA_IN], exclude:[IN] - delete(pr.DistributorPermissions[distributor].Include, list[0]) + pr.AddRegion(distributor, country.Code, include) + + //delete province+cities entries of country + suffix := "-" + country.Code + pr.DeleteRegion(distributor, suffix, true) } } if listLen == 2 { // list[0] is province code // list[1] is country code - cdata, pData, ok := pr.RegionR.IsProvinceAllowed(list[1], list[0]) + cdata, pData, ok := pr.RegionR.IsProvinceAllowed(strings.TrimSpace(list[1]), strings.TrimSpace(list[0])) if !ok { log.Printf("Country %s with province %s is not available\n", list[1], list[0]) return } + regionCode := pData.Code + "-" + cdata.Code if include { - if _, ok := pr.DistributorPermissions[distributor].Include[list[1]]; !ok { - //if country is not included, include both country and province - pr.addCountry(distributor, cdata, include) - pr.addProvince(distributor, cdata.Code, pData, include) - } else if _, ok := pr.DistributorPermissions[distributor].Include[list[1]].Regions[list[0]]; !ok { - pr.addProvince(distributor, cdata.Code, pData, include) - } - - //deleting from exclude list - //case1: exclude list has only country eg: exclude:[IN] include:[MH-IN] - //case2: exclude list has country and one province mentioned in include list and no cities eg:= exclude=[MH-IN] include=[MH-IN] - //case3: exclude list has country and one province mentioned in include list and has cities eg:= exclude=[PUNE-MH-IN] include=[MH-IN] - //case4: exclude list has country and province mentioned in provinces and no cities eg:=exclude:[MH-IN, KA-IN] include:[MH-IN] - if countryPointer, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; ok { - if len(countryPointer.Regions) == 0 { - //case 1: delete country - delete(pr.DistributorPermissions[distributor].Exclude, list[1]) - } else if provincePtr, ok := countryPointer.Regions[list[0]]; ok { - if len(countryPointer.Regions) == 1 && len(provincePtr.Regions) == 0 { - //case 2: delete country - delete(pr.DistributorPermissions[distributor].Exclude, list[1]) - } else if len(provincePtr.Regions) == 0 { - //case 4: delete province - delete(countryPointer.Regions, list[0]) - } - //case 3: dont delete country or province - } + if ok := pr.IsRegionExcluded(distributor, cdata.Code); ok { + log.Printf("Country %s is excluded\n", list[1]) + return } - + pr.AddRegion(distributor, regionCode, include) } else { - if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]]; !ok { - //if country is not excluded, include both country and province - pr.addCountry(distributor, cdata, include) - pr.addProvince(distributor, cdata.Code, pData, include) - } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[1]].Regions[list[0]]; !ok { - pr.addProvince(distributor, cdata.Code, pData, include) - } - //deleting from include list - //case1:include list has only country: do nothing eg: include: IN exclude:AN-IN - //case2: include list has country and one province mentioned in exclude list and no cities eg: include: MH-IN exclude: MH-IN - //case3: include list has country and one province mentioned in exclude list and has cities eg:include: PUNE-MH-IN exclude: MH-IN - if countryPtr, ok := pr.DistributorPermissions[distributor].Include[list[1]]; ok { - //case2&3: delete province - delete(countryPtr.Regions, list[0]) - } + pr.AddRegion(distributor, regionCode, include) + //delete city entries of the province + suffix := "-" + regionCode + pr.DeleteRegion(distributor, suffix, true) } } @@ -125,82 +78,137 @@ func (pr *PermissionsReceiver) updatePermissions(regionCode string, distributor log.Printf("Country %s with province %s and city %s is not available\n", list[2], list[1], list[0]) return } - + regionCode := cityData.Code + "-" + pData.Code + "-" + countryData.Code if include { - if _, ok := pr.DistributorPermissions[distributor].Include[list[2]]; !ok { - pr.addCountry(distributor, countryData, include) - pr.addProvince(distributor, countryData.Code, pData, include) - pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) - } else if _, ok := pr.DistributorPermissions[distributor].Include[list[2]].Regions[list[1]]; !ok { - pr.addProvince(distributor, countryData.Code, pData, include) - pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) - } else { - pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) + if ok := pr.IsRegionExcluded(distributor, countryData.Code); ok { + log.Printf("Country %s is excluded\n", list[2]) + return } - - //deleteing city from exclude list - //case1: exclude list has only country and no province eg:exclude:[IN] include:[PUNE-MH-IN] - //case2: exclude list has country and province and no cities eg:exclude:[MH-In] include:[PUNE-MH-IN] - //case3: exclude list has country and province with diff cities eg:exclude:[PUNE-MH-In, MUMBAI-MH-IN] include:[PUNE-MH-IN] - if countryPointer, ok := pr.DistributorPermissions[distributor].Exclude[list[2]]; ok { - if len(countryPointer.Regions) == 0 { - //case 1: delete country - delete(pr.DistributorPermissions[distributor].Exclude, list[2]) - } else if provincePtr, ok := countryPointer.Regions[list[1]]; ok { - //case 3: delete city - delete(provincePtr.Regions, list[0]) - if len(provincePtr.Regions) == 0 { - //case 2:delete province - delete(countryPointer.Regions, provincePtr.Code) - } - } + if ok := pr.IsRegionExcluded(distributor, pData.Code+"-"+countryData.Code); ok { + log.Printf("Country %s and province %s is excluded\n", list[2], list[1]) + return } + pr.AddRegion(distributor, regionCode, include) } else { - if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]]; !ok { - pr.addCountry(distributor, countryData, include) - pr.addProvince(distributor, countryData.Code, pData, include) - pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) - } else if _, ok := pr.DistributorPermissions[distributor].Exclude[list[2]].Regions[list[1]]; !ok { - pr.addProvince(distributor, countryData.Code, pData, include) - pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) - } else { - pr.addCity(distributor, countryData.Code, pData.Code, cityData, include) - } - - //deleteing city from include list - //case1: include list has only country and no province eg:include:[IN] exclude:[PUNE-MH-IN] // do nothing - //case2: include list has country and province and no cities eg:include:[MH-In] exclude:[PUNE-MH-IN] //do nothing - //case3: include list has country and province with diff cities eg:exclude:[PUNE-MH-In, MUMBAI-MH-IN] include:[PUNE-MH-IN] - if countryPointer, ok := pr.DistributorPermissions[distributor].Include[list[2]]; ok { - if provincePtr, ok := countryPointer.Regions[list[1]]; ok { - //case 3: delete city - delete(provincePtr.Regions, list[0]) - } - } + pr.AddRegion(distributor, regionCode, include) } } } -func (pr *PermissionsReceiver) addCountry(distributor string, data utils.Region, include bool) { +func (pr *PermissionsReceiver) AddRegion(distributor, region string, include bool) { if include { - pr.DistributorPermissions[distributor].Include[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor].Include[region] = true + delete(pr.DistributorPermissions[distributor].Exclude, region) } else { - pr.DistributorPermissions[distributor].Exclude[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} + pr.DistributorPermissions[distributor].Exclude[region] = true + delete(pr.DistributorPermissions[distributor].Include, region) } } -func (pr *PermissionsReceiver) addProvince(distributor, countryCode string, data utils.Region, include bool) { - if include { - pr.DistributorPermissions[distributor].Include[countryCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} - } else { - pr.DistributorPermissions[distributor].Exclude[countryCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code, Regions: map[string]utils.RegionsList{}} +func (pr *PermissionsReceiver) DeleteRegion(distributor, suffix string, fromInclude bool) { + if fromInclude { + for regionCode := range pr.DistributorPermissions[distributor].Include { + if strings.HasSuffix(regionCode, suffix) { + delete(pr.DistributorPermissions[distributor].Include, regionCode) + } + } } } -func (pr *PermissionsReceiver) addCity(distributor, countryCode, provinceCode string, data utils.Region, include bool) { - if include { - pr.DistributorPermissions[distributor].Include[countryCode].Regions[provinceCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code} - } else { - pr.DistributorPermissions[distributor].Exclude[countryCode].Regions[provinceCode].Regions[data.Code] = utils.RegionsList{Name: data.Name, Type: data.Type, Code: data.Code} + +func (pr *PermissionsReceiver) IsRegionExcluded(distributor, region string) bool { + _, ok := pr.DistributorPermissions[distributor].Exclude[region] + return ok +} + +func (pr *PermissionsReceiver) HasRegionPermission(distributor, regionCode string) bool { + list := strings.Split(regionCode, "-") + listLen := len(list) + switch listLen { + case 1: //done + country := strings.TrimSpace(list[0]) + //IsExcluded + if _, ok := pr.DistributorPermissions[distributor].Exclude[country]; ok { + return false + } + //IsIncluded + if _, ok := pr.DistributorPermissions[distributor].Include[country]; ok { + return true + } + + //includes any data under country + suffix := "-" + country + for regionCode := range pr.DistributorPermissions[distributor].Include { + if strings.HasSuffix(regionCode, suffix) { + return true + } + } + case 2: + country := strings.TrimSpace(list[1]) + province := strings.TrimSpace(list[0]) + pcCode := province + "-" + country + + //IsExcluded + //province level check + if _, ok := pr.DistributorPermissions[distributor].Exclude[pcCode]; ok { + return false + } + //country level check + if _, ok := pr.DistributorPermissions[distributor].Exclude[country]; ok { + return false + } + + //IsIncluded + //province level + if _, ok := pr.DistributorPermissions[distributor].Include[pcCode]; ok { + return true + } + //includes any city under province + suffix := "-" + pcCode + for regionCode := range pr.DistributorPermissions[distributor].Include { + if strings.HasSuffix(regionCode, suffix) { + return true + } + } + //country level + if _, ok := pr.DistributorPermissions[distributor].Include[country]; ok { + return true + } + case 3: + country := strings.TrimSpace(list[2]) + province := strings.TrimSpace(list[1]) + city := strings.TrimSpace(list[0]) + rCode := city + "-" + province + "-" + country + pCode := province + "-" + country + //Is excluded + //city level check + if _, ok := pr.DistributorPermissions[distributor].Exclude[rCode]; ok { + return false + } + //province level check + if _, ok := pr.DistributorPermissions[distributor].Exclude[pCode]; ok { + return false + } + //country check + if _, ok := pr.DistributorPermissions[distributor].Exclude[country]; ok { + return false + } + + //IsIncluded + //city level check + if _, ok := pr.DistributorPermissions[distributor].Include[rCode]; ok { + return true + } + //province level check + if _, ok := pr.DistributorPermissions[distributor].Include[pCode]; ok { + return true + } + //country check + if _, ok := pr.DistributorPermissions[distributor].Include[country]; ok { + return true + } + default: + return false } + return false } diff --git a/api/services/region.go b/api/services/region.go index 069f14d0c..2f1f5cff8 100644 --- a/api/services/region.go +++ b/api/services/region.go @@ -62,12 +62,18 @@ func (rr *RegionReciever) IsCountryAllowed(country string) (utils.Region, bool) func (rr *RegionReciever) IsProvinceAllowed(country string, province string) (utils.Region, utils.Region, bool) { cData, cok := rr.IsCountryAllowed(country) - pData, pok := rr.AllRegions[country].Regions[province] - return cData, utils.Region{Name: pData.Name, Code: pData.Code, Type: pData.Type}, cok && pok + if cok { + pData, pok := rr.AllRegions[country].Regions[province] + return cData, utils.Region{Name: pData.Name, Code: pData.Code, Type: pData.Type}, cok && pok + } + return utils.Region{}, utils.Region{}, false } func (rr *RegionReciever) IsCityAllowed(country, province, city string) (utils.Region, utils.Region, utils.Region, bool) { countryData, pData, cpOk := rr.IsProvinceAllowed(country, province) - cData, cok := rr.AllRegions[country].Regions[province].Regions[city] - return countryData, pData, utils.Region{Name: cData.Name, Code: cData.Code, Type: cData.Type}, cok && cpOk + if cpOk { + cData, cok := rr.AllRegions[country].Regions[province].Regions[city] + return countryData, pData, utils.Region{Name: cData.Name, Code: cData.Code, Type: cData.Type}, cok && cpOk + } + return utils.Region{}, utils.Region{}, utils.Region{}, false } diff --git a/api/utils/types.go b/api/utils/types.go index 066dd4441..f681cf768 100644 --- a/api/utils/types.go +++ b/api/utils/types.go @@ -8,9 +8,9 @@ type RegionsList struct { } type DistributorData struct { - Name string `json:"name"` - Include map[string]RegionsList `json:"include"` - Exclude map[string]RegionsList `json:"exclude"` + Name string `json:"name"` + Include map[string]bool `json:"include"` + Exclude map[string]bool `json:"exclude"` } type Region struct { From 309a37f686e086f3f85a74ac42320275dc0c785f Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Thu, 23 Oct 2025 22:17:45 +0530 Subject: [PATCH 07/11] completed add permissions api --- api/config/constants.go | 5 ++ api/controllers/permissions.go | 1 - api/main.go | 123 +++++++++++++++++++++++++++------ api/services/distributors.go | 30 ++++++++ api/services/permission.go | 56 +++++++++++++++ api/utils/types.go | 13 ++++ 6 files changed, 205 insertions(+), 23 deletions(-) delete mode 100644 api/controllers/permissions.go diff --git a/api/config/constants.go b/api/config/constants.go index 019aaadc1..a0b95c55c 100644 --- a/api/config/constants.go +++ b/api/config/constants.go @@ -6,4 +6,9 @@ const ( CITY CitiesFilePath = "../cities.csv" + + ADMIN string = "ADMIN" + DISTRIBUTOR_PREFIX string = "D00" + SUBDISTRIBUTOR1_PREFIX string = "SD01" + SUBDISTRIBUTOR2_PREFIX string = "SD02" ) diff --git a/api/controllers/permissions.go b/api/controllers/permissions.go deleted file mode 100644 index 2d3293679..000000000 --- a/api/controllers/permissions.go +++ /dev/null @@ -1 +0,0 @@ -package controllers diff --git a/api/main.go b/api/main.go index 337cc9fc0..c996863e3 100644 --- a/api/main.go +++ b/api/main.go @@ -1,41 +1,120 @@ package main import ( + "distributor-permissions/config" service "distributor-permissions/services" "distributor-permissions/utils" + "encoding/json" "fmt" "log" "net/http" + "strings" ) +var DR service.DistributorReceiver +var RR service.RegionReciever +var PR service.PermissionsReceiver + +func AddDistributorData(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + return + } + payload := utils.RequestPayload{} + encode := json.NewDecoder(r.Body) + err := encode.Decode(&payload) + if err != nil { + log.Printf("Error in loading payload %s\n", err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + fmt.Println("\n\n") + fmt.Println("payload =======>", payload) + + if strings.TrimSpace(payload.Distributor) == "" || strings.TrimSpace(payload.SubDistributor) == "" { + http.Error(w, "Bad Request", http.StatusBadRequest) + return + } + + switch strings.Split(payload.Distributor, "-")[0] { + case config.ADMIN: + fmt.Println("The adder is ADMIN") + if _, ok := PR.DistributorR.Distributors[payload.SubDistributor]; !ok { + PR.DistributorR.NewDistributor(payload.SubDistributor, payload.Distributor) + } + fmt.Println("distributors====>", PR.DistributorR.Distributors) + goto distributor + case config.DISTRIBUTOR_PREFIX: + if _, ok := PR.DistributorR.Distributors[payload.SubDistributor]; !ok { + err := PR.DistributorR.AddSubDistributor(payload.Distributor, payload.SubDistributor) + if err != nil { + log.Printf("Error in adding sub distributor %s\n", err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + } + fmt.Println("distributors====>", PR.DistributorR.Distributors) + goto subDist + case config.SUBDISTRIBUTOR1_PREFIX: + if _, ok := PR.DistributorR.Distributors[payload.Distributor]; ok { + err := PR.DistributorR.AddSubDistributor(payload.Distributor, payload.SubDistributor) + if err != nil { + log.Printf("Error in adding sub distributor2 %s\n", err.Error()) + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + } + fmt.Println("distributors====>", PR.DistributorR.Distributors) + goto subDist + case config.SUBDISTRIBUTOR2_PREFIX: + http.Error(w, "2nd SubDistributor cannot add data", http.StatusBadRequest) + return + default: + http.Error(w, "Incorrect distributor data", http.StatusBadRequest) + return + + } + +distributor: + { + data, err := PR.UpdateDistributorPermissions(payload.SubDistributor, payload.Include, payload.Exclude) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + fmt.Fprintf(w, "%+v", data) + return + } +subDist: + { + data, err := PR.UpdateSubDistributorPermissions(payload.Distributor, payload.SubDistributor, payload.Include, payload.Exclude) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + fmt.Fprintf(w, "%+v", data) + return + } + +} + func main() { - rr := service.RegionReciever{} - err := rr.LoadAllRegions() + + err := RR.LoadAllRegions() if err != nil { log.Println("Error loading regions=>", err) return } - pr := &service.PermissionsReceiver{} - pr.DistributorPermissions = make(map[string]utils.DistributorData) - pr.RegionR = &rr - include := []string{"AN-IN", "AP-IN"} - exclude := []string{} - data, err := pr.UpdateDistributorPermissions("DISTRIBUTOR2", include, exclude) - fmt.Printf("case1=> %+v", data) - - // file, err := os.Create("RegionsList.txt") - // if err != nil { - // log.Println("Error creating file=>", err) - // return - // } - // marshal, err := json.Marshal(rr.AllRegions) - // if err != nil { - // log.Println("Error in byte=>", err) - // return - // } - // file.Write(marshal) - // file.Close() + DR.Initilize() + + PR.DistributorPermissions = make(map[string]utils.DistributorData) + PR.RegionR = &RR + PR.DistributorR = &DR + + http.HandleFunc("/api/v1/permissions", AddDistributorData) log.Println("Server listening to port 3001") http.ListenAndServe(":3001", nil) } diff --git a/api/services/distributors.go b/api/services/distributors.go index 6d43c3366..5084ae315 100644 --- a/api/services/distributors.go +++ b/api/services/distributors.go @@ -1 +1,31 @@ package service + +import ( + "distributor-permissions/utils" + "errors" + "fmt" +) + +type DistributorReceiver struct { + Distributors map[string]utils.Distributor +} + +func (dr *DistributorReceiver) Initilize() { + dr.Distributors = make(map[string]utils.Distributor) +} + +func (dr *DistributorReceiver) NewDistributor(name string, parentName string) { + dr.Distributors[name] = utils.Distributor{Name: name, ParentDistributor: parentName, Sub: make(map[string]bool)} +} + +func (dr *DistributorReceiver) AddSubDistributor(dName string, subDName string) error { + fmt.Println("in AddSubDistributor", dr.Distributors) + if _, ok := dr.Distributors[dName]; ok { + dr.NewDistributor(subDName, dName) + dr.Distributors[dName].Sub[subDName] = true + fmt.Println("new distributors =>", dr.Distributors) + return nil + } + + return errors.New("distributor Not Found") +} diff --git a/api/services/permission.go b/api/services/permission.go index 566ad8f2d..941c0f8d6 100644 --- a/api/services/permission.go +++ b/api/services/permission.go @@ -1,6 +1,7 @@ package service import ( + "distributor-permissions/config" "distributor-permissions/utils" "log" "strings" @@ -9,6 +10,7 @@ import ( type PermissionsReceiver struct { DistributorPermissions map[string]utils.DistributorData RegionR *RegionReciever + DistributorR *DistributorReceiver } func (pr *PermissionsReceiver) UpdateDistributorPermissions(distributor string, include, exclude []string) (utils.DistributorData, error) { @@ -212,3 +214,57 @@ func (pr *PermissionsReceiver) HasRegionPermission(distributor, regionCode strin } return false } + +func (pr *PermissionsReceiver) UpdateSubDistributorPermissions(distributor, subDistributor string, include, exclude []string) (utils.DistributorData, error) { + //add subDistributor if not exists + if _, ok := pr.DistributorPermissions[subDistributor]; !ok { + pr.DistributorPermissions[subDistributor] = utils.DistributorData{Name: subDistributor, Include: make(map[string]bool), Exclude: make(map[string]bool)} + } + + //check if the distributor is subDistributor1 + if strings.HasPrefix(distributor, config.SUBDISTRIBUTOR1_PREFIX) { + //find the parent of subDistributor1 + parent := pr.DistributorR.Distributors[distributor].ParentDistributor + + for _, v := range include { + pr.updateSubDistributor2Permission(parent, distributor, subDistributor, v, true) + } + + for _, v := range exclude { + pr.updateSubDistributor2Permission(parent, distributor, subDistributor, v, false) + } + } else if strings.HasPrefix(distributor, config.DISTRIBUTOR_PREFIX) { + for _, v := range include { + pr.updateSubDistributor1Permission(distributor, subDistributor, v, true) + } + + for _, v := range exclude { + pr.updateSubDistributor1Permission(distributor, subDistributor, v, false) + } + } + return pr.DistributorPermissions[subDistributor], nil +} + +func (pr *PermissionsReceiver) updateSubDistributor2Permission(parent, subDistributor1, subDistributor2, region string, include bool) { + //check if subDistributor has the permission to include the region + subPermission := pr.HasRegionPermission(subDistributor1, region) + //check if the parentDistributor has the permission to include the region + parentPermission := pr.HasRegionPermission(parent, region) + + //if both are allowed, update the subDistributor2 list + if subPermission && parentPermission { + pr.updatePermissions(region, subDistributor2, include) + } else { + log.Printf("Region %s Excluded in parent distributors of %s\n", region, subDistributor2) + } +} + +func (pr *PermissionsReceiver) updateSubDistributor1Permission(distributor, subDistributor, region string, include bool) { + //check if distributor has the permission to include the region + allowed := pr.HasRegionPermission(distributor, region) + if allowed { + pr.updatePermissions(region, subDistributor, include) + } else { + log.Printf("Region %s Excluded in parent distributors of %s\n", region, subDistributor) + } +} diff --git a/api/utils/types.go b/api/utils/types.go index f681cf768..1269cf81b 100644 --- a/api/utils/types.go +++ b/api/utils/types.go @@ -18,3 +18,16 @@ type Region struct { Type int Code string } + +type Distributor struct { + Name string + ParentDistributor string + Sub map[string]bool +} + +type RequestPayload struct { + Distributor string `json:"distributor"` + SubDistributor string `json:"subDistributor"` + Include []string `json:"include"` + Exclude []string `json:"exclude"` +} From 44d20f495309dade6bda49153f9e29b448fafed0 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Thu, 23 Oct 2025 22:37:46 +0530 Subject: [PATCH 08/11] added checking region api --- api/main.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/api/main.go b/api/main.go index c996863e3..e6030d7e2 100644 --- a/api/main.go +++ b/api/main.go @@ -100,6 +100,28 @@ subDist: } +func HasRegionPermission(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + return + } + distributor := r.URL.Query().Get("distributor") + region := r.URL.Query().Get("region") + if strings.TrimSpace(distributor) == "" || strings.TrimSpace(region) == "" { + http.Error(w, "Bad Request", http.StatusBadRequest) + return + } + data := PR.HasRegionPermission(distributor, region) + message := "" + if data { + message = "Distributor has " + region + " permission" + } else { + message = "Distributor doesn't have " + region + " permission" + } + + fmt.Fprintf(w, "Allowed: %v\n Message: %s", data, message) +} + func main() { err := RR.LoadAllRegions() @@ -115,6 +137,8 @@ func main() { PR.DistributorR = &DR http.HandleFunc("/api/v1/permissions", AddDistributorData) + http.HandleFunc("/api/v1/isRegionAllowed", HasRegionPermission) + log.Println("Server listening to port 3001") http.ListenAndServe(":3001", nil) } From 6aa9e4a79a7903d554c83e248c43ac97b902353d Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:20:54 +0530 Subject: [PATCH 09/11] added distributor api --- api/main.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/api/main.go b/api/main.go index e6030d7e2..4874b221d 100644 --- a/api/main.go +++ b/api/main.go @@ -122,6 +122,22 @@ func HasRegionPermission(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Allowed: %v\n Message: %s", data, message) } +func GetDistributorData(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + return + } + distributor := r.URL.Query().Get("distributor") + data, ok := PR.DistributorPermissions[distributor] + message := "" + if ok { + message = "Distributor " + distributor + " record found" + } else { + message = "Distributor " + distributor + " record not found" + } + fmt.Fprintf(w, "Data: %+v\n Message: %s", data, message) +} + func main() { err := RR.LoadAllRegions() @@ -136,8 +152,9 @@ func main() { PR.RegionR = &RR PR.DistributorR = &DR - http.HandleFunc("/api/v1/permissions", AddDistributorData) + http.HandleFunc("/api/v1/addPermissions", AddDistributorData) http.HandleFunc("/api/v1/isRegionAllowed", HasRegionPermission) + http.HandleFunc("/api/v1/permissions", GetDistributorData) log.Println("Server listening to port 3001") http.ListenAndServe(":3001", nil) From 46d5360ce6d66be0e6f1b061652c873a0c47a853 Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:28:50 +0530 Subject: [PATCH 10/11] clean up --- api/main.go | 6 ------ api/services/distributors.go | 3 --- 2 files changed, 9 deletions(-) diff --git a/api/main.go b/api/main.go index 4874b221d..41c118fff 100644 --- a/api/main.go +++ b/api/main.go @@ -28,8 +28,6 @@ func AddDistributorData(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusBadRequest) return } - fmt.Println("\n\n") - fmt.Println("payload =======>", payload) if strings.TrimSpace(payload.Distributor) == "" || strings.TrimSpace(payload.SubDistributor) == "" { http.Error(w, "Bad Request", http.StatusBadRequest) @@ -38,11 +36,9 @@ func AddDistributorData(w http.ResponseWriter, r *http.Request) { switch strings.Split(payload.Distributor, "-")[0] { case config.ADMIN: - fmt.Println("The adder is ADMIN") if _, ok := PR.DistributorR.Distributors[payload.SubDistributor]; !ok { PR.DistributorR.NewDistributor(payload.SubDistributor, payload.Distributor) } - fmt.Println("distributors====>", PR.DistributorR.Distributors) goto distributor case config.DISTRIBUTOR_PREFIX: if _, ok := PR.DistributorR.Distributors[payload.SubDistributor]; !ok { @@ -53,7 +49,6 @@ func AddDistributorData(w http.ResponseWriter, r *http.Request) { return } } - fmt.Println("distributors====>", PR.DistributorR.Distributors) goto subDist case config.SUBDISTRIBUTOR1_PREFIX: if _, ok := PR.DistributorR.Distributors[payload.Distributor]; ok { @@ -64,7 +59,6 @@ func AddDistributorData(w http.ResponseWriter, r *http.Request) { return } } - fmt.Println("distributors====>", PR.DistributorR.Distributors) goto subDist case config.SUBDISTRIBUTOR2_PREFIX: http.Error(w, "2nd SubDistributor cannot add data", http.StatusBadRequest) diff --git a/api/services/distributors.go b/api/services/distributors.go index 5084ae315..c80807435 100644 --- a/api/services/distributors.go +++ b/api/services/distributors.go @@ -3,7 +3,6 @@ package service import ( "distributor-permissions/utils" "errors" - "fmt" ) type DistributorReceiver struct { @@ -19,11 +18,9 @@ func (dr *DistributorReceiver) NewDistributor(name string, parentName string) { } func (dr *DistributorReceiver) AddSubDistributor(dName string, subDName string) error { - fmt.Println("in AddSubDistributor", dr.Distributors) if _, ok := dr.Distributors[dName]; ok { dr.NewDistributor(subDName, dName) dr.Distributors[dName].Sub[subDName] = true - fmt.Println("new distributors =>", dr.Distributors) return nil } From 9ce3fa774a8ddee2713e553492c866cb7fa90f0e Mon Sep 17 00:00:00 2001 From: apoorvan-repo <238725065+apoorvan-repo@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:46:59 +0530 Subject: [PATCH 11/11] added curl details --- README.md | 91 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index f1c342f65..0d6414603 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,54 @@ # Real Image Challenge 2016 -In the cinema business, a feature film is usually provided to a regional distributor based on a contract for exhibition in a particular geographical territory. - -Each authorization is specified by a combination of included and excluded regions. For example, a distributor might be authorzied in the following manner: -``` -Permissions for DISTRIBUTOR1 -INCLUDE: INDIA -INCLUDE: UNITEDSTATES -EXCLUDE: KARNATAKA-INDIA -EXCLUDE: CHENNAI-TAMILNADU-INDIA -``` -This allows `DISTRIBUTOR1` to distribute in any city inside the United States and India, *except* cities in the state of Karnataka (in India) and the city of Chennai (in Tamil Nadu, India). - -At this point, asking your program if `DISTRIBUTOR1` has permission to distribute in `CHICAGO-ILLINOIS-UNITEDSTATES` should get `YES` as the answer, and asking if distribution can happen in `CHENNAI-TAMILNADU-INDIA` should of course be `NO`. Asking if distribution is possible in `BANGALORE-KARNATAKA-INDIA` should also be `NO`, because the whole state of Karnataka has been excluded. - -Sometimes, a distributor might split the work of distribution amount smaller sub-distiributors inside their authorized geographies. For instance, `DISTRIBUTOR1` might assign the following permissions to `DISTRIBUTOR2`: - -``` -Permissions for DISTRIBUTOR2 < DISTRIBUTOR1 -INCLUDE: INDIA -EXCLUDE: TAMILNADU-INDIA -``` -Now, `DISTRIBUTOR2` can distribute the movie anywhere in `INDIA`, except inside `TAMILNADU-INDIA` and `KARNATAKA-INDIA` - `DISTRIBUTOR2`'s permissions are always a subset of `DISTRIBUTOR1`'s permissions. It's impossible/invalid for `DISTRIBUTOR2` to have `INCLUDE: CHINA`, for example, because `DISTRIBUTOR1` isn't authorized to do that in the first place. - -If `DISTRIBUTOR2` authorizes `DISTRIBUTOR3` to handle just the city of Hubli, Karnataka, India, for example: -``` -Permissions for DISTRIBUTOR3 < DISTRIBUTOR2 < DISTRIBUTOR1 -INCLUDE: HUBLI-KARNATAKA-INDIA -``` -Again, `DISTRIBUTOR2` cannot authorize `DISTRIBUTOR3` with a region that they themselves do not have access to. - -We've provided a CSV with the list of all countries, states and cities in the world that we know of - please use the data mentioned there for this program. *The codes you see there may be different from what you see here, so please always use the codes in the CSV*. This Readme is only an example. - -Write a program in any language you want (If you're here from Gophercon, use Go :D) that does this. Feel free to make your own input and output format / command line tool / GUI / Webservice / whatever you want. Feel free to hold the dataset in whatever structure you want, but try not to use external databases - as far as possible stick to your langauage without bringing in MySQL/Postgres/MongoDB/Redis/Etc. - -To submit a solution, fork this repo and send a Pull Request on Github. - -For any questions or clarifications, raise an issue on this repo and we'll answer your questions as fast as we can. - - +Run application: +go run main.go + + +Prefix to be used while adding distributors: +ADMIN = "ADMIN" +DISTRIBUTOR_PREFIX = "D00" +SUBDISTRIBUTOR1_PREFIX = "SD01" +SUBDISTRIBUTOR2_PREFIX = "SD02" + + +1) API to add Distributors and Permissions: + +curl --location --request POST 'http://localhost:3001/api/v1/addPermissions' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "distributor":"ADMIN", + "subDistributor":"D00-01", + "include":["IN","BR-AL"], + "exclude":["MH-IN"] + +} +' + +curl --location --request POST 'http://localhost:3001/api/v1/addPermissions' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "distributor":"D00-01", + "subDistributor":"SD01-01", + "include":["MH-IN","KA-IN"], + "exclude":["AL"] + +} +' + +curl --location --request POST 'http://localhost:3001/api/v1/addPermissions' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "distributor":"SD01-01", + "subDistributor":"SD02-01", + "include":["KA-IN"], + "exclude":["ANEKL-KA-IN"] + +} +' + +2) Check if distributor has permission to the region: +curl --location --request GET 'http://localhost:3001/api/v1/isRegionAllowed?distributor=SD02-01®ion=MH-IN' + + +3) Get distributor permission data +curl --location --request GET 'http://localhost:3001/api/v1/permissions?distributor=SD02-01' \ No newline at end of file