diff --git a/distributor.go b/distributor.go new file mode 100644 index 000000000..70381bd3b --- /dev/null +++ b/distributor.go @@ -0,0 +1,93 @@ +package main + +import "strings" + +// distributor struct +type Distributor struct { + Name string + Includes []string + Excludes []string + SubDistributors map[string]*Distributor +} + +// stores all thedistributors +var distributors = make(map[string]*Distributor) + +// add a main distributor +func AddDistributor(name string, includes, excludes []string) { + distributors[name] = &Distributor{ + Name: name, + Includes: includes, + Excludes: excludes, + SubDistributors: make(map[string]*Distributor), + } +} + +// add a sub-distributor with parent validation +func AddSubDistributor(parentName, subName string, includes, excludes []string) string { + parent, exists := distributors[parentName] + if !exists { + return "ERROR: Parent distributor not found" + } + + // ensure sub-distributor does not override parent exclusions + for _, incl := range includes { + if isExcludedByParent(parent, incl) { + return "ERROR: Sub-distributor cannot include " + incl + " as it is excluded by parent." + } + } + + // create and register the sub-distributor + subDistributor := &Distributor{ + Name: subName, + Includes: includes, + Excludes: excludes, + SubDistributors: make(map[string]*Distributor), + } + + parent.SubDistributors[subName] = subDistributor + distributors[subName] = subDistributor + + return "Sub-distributor " + subName + " added successfully." +} + +// check if a parent or ancestor excluded a region +func isExcludedByParent(distributor *Distributor, region string) bool { + // Direct exclusion check + for _, excl := range distributor.Excludes { + if strings.Contains(region, excl) { + return true + } + } + + // recursively check if an ancestor excluded it + for _, parent := range distributors { + if parent.SubDistributors[distributor.Name] != nil { + if isExcludedByParent(parent, region) { + return true + } + } + } + + return false +} + +// check if a distributor is authorized to distribute in a location +func CanDistribute(distributorName, location string) string { + dist, exists := distributors[distributorName] + if !exists { + return "Distributor not found" + } + + if isExcludedByParent(dist, location) { + return "NO" + } + + for _, incl := range dist.Includes { + if strings.Contains(location, incl) { + return "YES" + } + } + + return "NO" +} diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..99b50fb7c --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module distributor_permission_checking + +go 1.24.1 diff --git a/location.go b/location.go new file mode 100644 index 000000000..733c2875a --- /dev/null +++ b/location.go @@ -0,0 +1,39 @@ +package main + +import ( + "encoding/csv" + "fmt" + "os" +) + +// stores locations +var locationMap = make(map[string]bool) + +// read and store locations from CSV +func ReadCSV(filename string) { + file, err := os.Open(filename) + if err != nil { + fmt.Println("Error opening file:", err) + return + } + defer file.Close() + + reader := csv.NewReader(file) + records, err := reader.ReadAll() + if err != nil { + fmt.Println("Error reading CSV:", err) + return + } + + // process each row, skipping the header + for i, row := range records { + if i == 0 || len(row) < 6 { + continue + } + + fullLocation := row[3] + "-" + row[4] + "-" + row[5] // City-State-Country + locationMap[fullLocation] = true + } + + fmt.Println("Total locations loaded:", len(locationMap)) +} diff --git a/main.go b/main.go new file mode 100644 index 000000000..837c0646f --- /dev/null +++ b/main.go @@ -0,0 +1,25 @@ +package main + +import "fmt" + +func main() { + ReadCSV("cities.csv") + + // define main distributor + AddDistributor("DISTRIBUTOR1", + []string{"INDIA", "UNITED STATES"}, + []string{"KARNATAKA-INDIA", "CHENNAI-TAMILNADU-INDIA"}, + ) + + // adding sub-distributors + fmt.Println(AddSubDistributor("DISTRIBUTOR1", "DISTRIBUTOR2", + []string{"INDIA"}, []string{"TAMILNADU-INDIA"})) + + fmt.Println(AddSubDistributor("DISTRIBUTOR2", "DISTRIBUTOR3", + []string{"HUBLI-KARNATAKA-INDIA"}, []string{})) // must fail + + // permission test checks + fmt.Println("Can DISTRIBUTOR2 distribute in MUMBAI-MAHARASHTRA-INDIA?", CanDistribute("DISTRIBUTOR2", "MUMBAI-MAHARASHTRA-INDIA")) + fmt.Println("Can DISTRIBUTOR2 distribute in CHENNAI-TAMILNADU-INDIA?", CanDistribute("DISTRIBUTOR2", "CHENNAI-TAMILNADU-INDIA")) + fmt.Println("Can DISTRIBUTOR3 distribute in HUBLI-KARNATAKA-INDIA?", CanDistribute("DISTRIBUTOR3", "HUBLI-KARNATAKA-INDIA")) +}