diff --git a/dist.yaml b/dist.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/distributer/dist.go b/distributer/dist.go new file mode 100644 index 000000000..a3aade062 --- /dev/null +++ b/distributer/dist.go @@ -0,0 +1,67 @@ +package distributer + +import ( + "Qubecinema/challenge/utils" + "fmt" + "strings" +) + +type Distributor struct { + Name string + Parent string + Permissions map[string]bool +} + +var DistMap = make(map[string]Distributor) + +func AddDistributor(Name, Parent string, Include, Exclude []string) error { + if _, exists := DistMap[Name]; exists { + return fmt.Errorf("distributor %s already exists", Name) + } + newDist := Distributor{ + Name: Name, + Parent: Parent, + Permissions: make(map[string]bool), + } + if Parent != "" { + parentDist, exists := DistMap[Parent] + if !exists { + return fmt.Errorf("parent distributor %s not found", Parent) + } + for _, region := range Include { + if !parentDist.Permissions[region] { + return fmt.Errorf("parent distributor %s does not have access to %s", Parent, region) + } + } + } + for _, region := range Include { + newDist.Permissions[region] = true + for area := range utils.AreaMap { + if strings.HasSuffix(area, region) { + newDist.Permissions[area] = true + } + } + } + for _, region := range Exclude { + for area := range newDist.Permissions { + if strings.HasSuffix(area, region) { + delete(newDist.Permissions, area) + } + } + } + DistMap[Name] = newDist + return nil +} + +func CheckPermission(distributorName, region string) (bool, error) { + dist, exists := DistMap[distributorName] + if !exists { + return false, fmt.Errorf("distributor %s not found", distributorName) + } + + if allowed, found := dist.Permissions[region]; found { + return allowed, nil + } + + return false, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 000000000..29008e195 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module Qubecinema/challenge + +go 1.22.2 + +require github.com/fatih/color v1.18.0 + +require ( + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + golang.org/x/sys v0.25.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 000000000..33148a44b --- /dev/null +++ b/go.sum @@ -0,0 +1,11 @@ +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go new file mode 100644 index 000000000..b429edc2e --- /dev/null +++ b/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "Qubecinema/challenge/distributer" + "Qubecinema/challenge/utils" + "bufio" + "fmt" + "os" + "strings" + + "github.com/fatih/color" +) + +func init() { + err := utils.LoadCSV("cities.csv") + if err != nil { + fmt.Printf("Error loading csv %v", err) + return + } +} + +func main() { + reader := bufio.NewReader(os.Stdin) + + color.HiGreen("...............Distributor System...............") + + for { + color.HiCyan("\n1. Add Distributor") + color.HiCyan("2. Check Permission") + color.HiCyan("3. Exit") + color.HiYellow("Enter your choice: ") + + input, err := reader.ReadString('\n') + if err != nil { + fmt.Println("❌ Error reading input:", err) + continue + } + + input = strings.TrimSpace(input) + + switch input { + case "1": + fmt.Print("Enter Distributor Name: ") + name, _ := reader.ReadString('\n') + name = strings.TrimSpace(name) + fmt.Print("Enter Parent Distributor (leave empty if none): ") + parent, _ := reader.ReadString('\n') + parent = strings.TrimSpace(parent) + + fmt.Print("Enter regions to INCLUDE (comma-separated, e.g., IN,US, KA-IN): ") + includeInput, _ := reader.ReadString('\n') + include := strings.Split(strings.TrimSpace(includeInput), ",") + + fmt.Print("Enter regions to EXCLUDE (comma-separated, e.g., KA-IN,CENAI-TN-INDIA): ") + excludeInput, _ := reader.ReadString('\n') + exclude := strings.Split(strings.TrimSpace(excludeInput), ",") + err := distributer.AddDistributor(name, parent, include, exclude) + if err != nil { + color.HiRed("Ditributer Not Added %v", err) + } + case "2": + fmt.Print("Enter Distributor Name: ") + name, _ := reader.ReadString('\n') + name = strings.TrimSpace(name) + fmt.Print("Enter regions to CHECK (KA-IN): ") + includeInput, _ := reader.ReadString('\n') + includeInput = strings.TrimSpace(includeInput) + perm, err := distributer.CheckPermission(name, includeInput) + if err != nil { + color.HiRed("Distributer does not exist") + } else { + color.HiGreen("IS ALLOWED: %t", perm) + } + case "3": + color.HiRed("Exiting...") + return + + default: + color.HiRed("❌ Invalid choice, please try again.") + } + } +} diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 000000000..dcff921ae --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,38 @@ +package utils + +import ( + "encoding/csv" + "fmt" + "os" +) + +var AreaMap = make(map[string]bool) + +func LoadCSV(filename string) error { + file, err := os.Open(filename) + if err != nil { + return err + } + defer file.Close() + + reader := csv.NewReader(file) + records, err := reader.ReadAll() + if err != nil { + return err + } + + for i, record := range records { + if i == 0 { + continue + } + cityCode := record[0] + provinceCode := record[1] + countryCode := record[2] + + AreaMap[countryCode] = true + AreaMap[fmt.Sprintf("%s-%s", provinceCode, countryCode)] = true + AreaMap[fmt.Sprintf("%s-%s-%s", cityCode, provinceCode, countryCode)] = true + } + + return nil +}