Skip to content

QubeCinema Assignment #197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module qc_assignment

go 1.22.2
100 changes: 100 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package main

import (
"bufio"
"fmt"
"log"
"os"
"qc_assignment/models"
"qc_assignment/services"
"strconv"
"strings"
)

func main() {
err := services.LoadCSVIntoStruct("cities.csv")
if err != nil {
log.Println("error loading csv file")
}

for {
reader := bufio.NewReader(os.Stdin)
fmt.Println("Enter the operation you want to perform:")
fmt.Println("1 - Create new Distributor")
fmt.Println("2 - Create Sub-Distributor")
var optionStr string
optionStr, _ = reader.ReadString('\n')
optionStr = strings.TrimSpace(optionStr)
option, _ := strconv.Atoi(optionStr)

if option == 1 {
fmt.Println("Enter the name of the distributor: ")
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
if services.IsExistsDistributor(name) {
fmt.Println("Error: Distributor already exists. Please try again.")
continue
}
fmt.Println("Enter the permissions in the form <ACTION> <CITY>-<STATE>-<COUNTRY> \nOR <ACTION> <STATE>-<COUNTRY> \nOR <ACTION> <COUNTRY>.\nEnter 'DONE' to stop:")
var permissions []models.Permission
for {
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line)
if line == "DONE" {
break
}
lineSplit := strings.Split(line, " ")
permissions = append(permissions, models.Permission{
Action: lineSplit[0],
Area: lineSplit[1],
})
}
distributor := models.CreateNewEmptyDistributor()
services.CreateDistributor(name, distributor)
distributor.AddPermissions(permissions)
fmt.Printf("Distributor %s created.\n", name)
} else if option == 2 {
// Check if the primary distributor exists
fmt.Println("Enter the name of the primary distributor: ")
primaryDistributorName, _ := reader.ReadString('\n')
primaryDistributorName = strings.TrimSpace(primaryDistributorName)
if !services.IsExistsDistributor(primaryDistributorName) {
fmt.Println("Error: Primary Distributor does not exist. Please try again.")
continue
}
// Create secondary distributor
fmt.Println("Enter the name of the Secondary Distributor: ")
secondaryDistributorName, _ := reader.ReadString('\n')
secondaryDistributorName = strings.TrimSpace(secondaryDistributorName)
if services.IsExistsDistributor(secondaryDistributorName) {
fmt.Println("Error: Distributor already exists. Please try again.")
continue
}
fmt.Println("Enter the permissions in the form <ACTION> <CITY>-<STATE>-<COUNTRY> \nOR <ACTION> <STATE>-<COUNTRY> \nOR <ACTION> <COUNTRY>.\nEnter 'DONE' to stop:")
var permissions []models.Permission
for {
line, _ := reader.ReadString('\n')
line = strings.TrimSpace(line)
if line == "DONE" {
break
}
lineSplit := strings.Split(line, " ")
permissions = append(permissions, models.Permission{
Action: lineSplit[0],
Area: lineSplit[1],
})
}
parentDistributor := services.GetDistributor(primaryDistributorName)
check := services.CheckDistributor(parentDistributor, permissions)
if !check {
fmt.Println("Error: Parent distributor can't create distributor with these permissions. Please try again.")
continue
}
secondaryDistributor := models.CreateNewEmptyDistributor()
secondaryDistributor.AddPermissions(permissions)
fmt.Printf("Distributor %s created.\n", secondaryDistributorName)
} else {
fmt.Println("Invalid option entered. Please try again.")
}
}
}
4 changes: 4 additions & 0 deletions models/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package models

const INCLUDE = "INCLUDE"
const EXCLUDE = "EXCLUDE"
72 changes: 72 additions & 0 deletions models/distributor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package models

import (
"errors"
"strings"
)

type Distributor struct {
Name string
ParentName *Distributor
Included map[string]struct{}
Excluded map[string]struct{}
}

func CreateNewEmptyDistributor() *Distributor {
return &Distributor{
Name: "",
ParentName: &Distributor{},
Included: map[string]struct{}{},
Excluded: map[string]struct{}{},
}
}

type Permission struct {
Action string
Area string
}

// The area string will be of the form country, state-country, or city-state-country

func (d *Distributor) AddPermissions(permissions []Permission) error {
for _, permission := range permissions {
action := permission.Action
area := permission.Area
areas := strings.Split(area, "-")
if action == INCLUDE {
for _, i := range areas {
d.Included[i] = struct{}{}
}
} else if action == EXCLUDE {
for _, i := range areas {
d.Excluded[i] = struct{}{}
delete(d.Included, i)
}
} else {
return errors.New("invalid action")
}
}
return nil
}

func (d *Distributor) IsIncluded(area string) bool {
areas := strings.Split(area, "-")
for _, i := range areas {
_, exists := d.Included[i]
if exists {
return true
}
}
return false
}

func (d *Distributor) IsExcluded(area string) bool {
areas := strings.Split(area, "-")
for _, i := range areas {
_, exists := d.Excluded[i]
if !exists {
return false
}
}
return true
}
19 changes: 19 additions & 0 deletions models/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package models

type Node struct {
Name string
Child map[string]*Node
}

func UpsertNode(parent *Node, name string) *Node {
childNode, exists := parent.Child[name]
if exists {
return childNode
}
childNode = &Node{
Name: name,
Child: map[string]*Node{},
}
parent.Child[name] = childNode
return childNode
}
45 changes: 45 additions & 0 deletions services/distributor.service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package services

import "qc_assignment/models"

var distributors map[string]*models.Distributor

func init() { // Initialize map to store all the distributors
distributors = make(map[string]*models.Distributor)
}

func CreateDistributor(name string, d *models.Distributor) {
distributors[name] = d
}

func CheckDistributor(parent *models.Distributor, permissions []models.Permission) bool { // Check if a sub-distributor can be created with the parent distributor.
for _, permission := range permissions {
action := permission.Action
area := permission.Area

if action == models.INCLUDE {
if !parent.IsIncluded(area) {
return false
}
}
if action == models.EXCLUDE {
if parent.IsExcluded(area) {
return false
}
}
}
return true
}

func IsExistsDistributor(name string) bool {
_, exists := distributors[name]
return exists
}

func GetDistributor(name string) *models.Distributor {
d, exists := distributors[name]
if exists {
return d
}
return nil
}
33 changes: 33 additions & 0 deletions services/file_loader.service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package services

import (
"bufio"
"os"
"qc_assignment/models"
"strings"
)

func LoadCSVIntoStruct(path string) error {
f, err := os.Open(path)
if err != nil {
return nil
}
defer f.Close()

scanner := bufio.NewScanner(f)
// Skipping the first line
scanner.Scan()
root := &models.Node{
Name: "countries",
Child: map[string]*models.Node{},
}
for scanner.Scan() {
line := scanner.Text()
splitLine := strings.Split(line, ",")
country, state, city := splitLine[3], splitLine[4], splitLine[5]
countryNode := models.UpsertNode(root, country)
stateNode := models.UpsertNode(countryNode, state)
models.UpsertNode(stateNode, city)
}
return nil
}