Skip to content

Solution real image-2016 challange Feat/distribution qube #188

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 4 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
27 changes: 27 additions & 0 deletions HowToRun.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
Find the Below Example Commands For Each of the Following :

User Flow

Choose an option:
1. Add new permission
2. Get Distributor With Name
3. Check Distributor Permission
4. Exit

Addding single distributor:

1. slect option one after initial promt (1)
2. Add distributor name and click enter(distributor1)
3. Add permissions as many as you want and if you want to exit enter EXIT(EXIT)
4. then you can check the distributor by selecting option 2 (2)
5. enter the distributor name and it will fetch all the details
6. checking individual region permissions select option (3)
7. Enter Distributor Name
8. enter the permissons with format (NAME : CITY-PROVINCE_COUNTRY)exqample (distributor1)


For Adding PArent Child Distributor:

All the things follow same flow
only while adding names : Child < Parent
this is the only change
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module challange2016

go 1.23.3
18 changes: 18 additions & 0 deletions internal/models/cahceinitialisor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package models

type DistributionMaps struct {
CityMap map[string]*Location
ProvinceMap map[string]*Location
CountryMap map[string]*Location
Distributor map[string]*Distributor
}

// factory function
func NewDistributionMaps() *DistributionMaps {
return &DistributionMaps{
CityMap: make(map[string]*Location),
ProvinceMap: make(map[string]*Location),
CountryMap: make(map[string]*Location),
Distributor: make(map[string]*Distributor),
}
}
22 changes: 22 additions & 0 deletions internal/models/distributor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package models

type Distributor struct {
Name string
Include []Location
Exclude []Location
ParentDistributor *string
}

type Location struct {
City string
CityCode string
Province string
ProvinceCode string
Country string
CountryCode string
}

type CheckPermission struct {
DistributorName *string
Loc *Location
}
9 changes: 9 additions & 0 deletions internal/service/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package service

import "challange2016/internal/models"

type Service interface {
AddDistributor(reqBody *models.Distributor) (*models.Distributor, error)
GetDistributorByName(distributorName *string) (*models.Distributor, error)
CheckDistributorPermission(distributorName *string, reqBody models.CheckPermission) bool
}
155 changes: 155 additions & 0 deletions internal/service/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
package service

import (
"challange2016/internal/models"
"challange2016/internal/store"
"errors"
"strings"
)

type service struct {
store store.Store
}

func New(store store.Store) *service {
return &service{
store: store,
}
}

func (s *service) AddDistributor(reqBody *models.Distributor) (*models.Distributor, error) {
reqBody.Name = strings.ToUpper(reqBody.Name)

// check whether distributor already exist or not
distributor := s.store.GetDistributorByName(reqBody.Name)
if distributor != nil {
return nil, errors.New("distributor already exist")
}
// initilise include fields
reqBody.Include = s.AutoInitialiseFields(reqBody.Include)
// initialise exclude fields
reqBody.Exclude = s.AutoInitialiseFields(reqBody.Exclude)
// if parentDistributor exist, assign exclude fields also
if reqBody.ParentDistributor != nil {
isAllowed := s.checkParentDistributorPermissions(reqBody)
if !isAllowed {
return nil, errors.New("Parent Distributor doesn't have permission to distribute these location")
}
upperCaseName := strings.ToUpper(*reqBody.ParentDistributor)
reqBody.ParentDistributor = &upperCaseName
}
// store layer call
response := s.store.AddDistributor(reqBody)

return response, nil
}

func (s *service) checkParentDistributorPermissions(distributor *models.Distributor) bool {
parentDistributor := s.store.GetDistributorByName(strings.ToUpper(*distributor.ParentDistributor))
if parentDistributor == nil {
return false
}
for _, loc := range distributor.Include {
isIncludeAllowed := checkPermission(parentDistributor.Include, loc)
isExcludeAllowed := checkPermission(parentDistributor.Exclude, loc)

if isExcludeAllowed || !isIncludeAllowed {
return false
}
}

return true
}

func (s *service) GetDistributorByName(distributorName *string) (*models.Distributor, error) {
if distributorName == nil || *distributorName == "" {
return nil, errors.New("empty distributor name value")
}

*distributorName = strings.ToUpper(*distributorName)

distributor := s.store.GetDistributorByName(*distributorName)
if distributor == nil {
return nil, errors.New("entity not found")
}

return distributor, nil
}

func (s *service) CheckDistributorPermission(distributorName *string, reqBody models.CheckPermission) bool {
switch {
case reqBody.DistributorName == nil:
return false
case reqBody.Loc == nil:
return false
case reqBody.Loc.City == "" || reqBody.Loc.Province == "" || reqBody.Loc.Country == "":
return false

}

if distributorName == nil || *distributorName == "" {
return false
}

*distributorName = strings.ToUpper(*distributorName)

distributor := s.store.GetDistributorByName(*distributorName)
if distributor == nil {
return false
}
isIncludeLoc := checkPermission(distributor.Include, *reqBody.Loc)
if !isIncludeLoc {
// return false - as it does have have permission to distribute

return false
}

// check for exclude permission
for {
isExcludeLoc := checkPermission(distributor.Exclude, *reqBody.Loc)
if isExcludeLoc {

return false
}

// check for exlude permission
if distributor.ParentDistributor != nil {
distributor = s.store.GetDistributorByName(strings.ToUpper(*distributor.ParentDistributor))
} else {
break
}
}

return true
}

func checkPermission(distributorLoc []models.Location, loc models.Location) bool {
for _, dLoc := range distributorLoc {
if strings.EqualFold(dLoc.Country, loc.Country) {
if strings.EqualFold(dLoc.Province, loc.Province) || strings.EqualFold(dLoc.Province, "ALL") {
if strings.EqualFold(dLoc.City, loc.City) || strings.EqualFold(dLoc.City, "ALL") {
return true
}
}
}
}

return false
}

func (s *service) AutoInitialiseFields(loc []models.Location) []models.Location {
for i := range loc {

if loc[i].City != "" {
loc[i] = *s.store.GetLocationDetailsByCity(loc[i].City)
} else if loc[i].Province != "" {

loc[i] = *s.store.GetLocationDetailsByProvince(loc[i].Province)
} else if loc[i].Country != "" {

loc[i] = *s.store.GetLocationDetailsByCountry(loc[i].Country)
}
}

return loc
}
11 changes: 11 additions & 0 deletions internal/store/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package store

import "challange2016/internal/models"

type Store interface {
AddDistributor(obj *models.Distributor) *models.Distributor
GetDistributorByName(distributorName string) *models.Distributor
GetLocationDetailsByCity(cityName string) *models.Location
GetLocationDetailsByProvince(province string) *models.Location
GetLocationDetailsByCountry(countryName string) *models.Location
}
67 changes: 67 additions & 0 deletions internal/store/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package store

import (
"challange2016/internal/models"
"strings"
)

type store struct {
dMap *models.DistributionMaps
}

func NewStore(dMap *models.DistributionMaps) *store {
return &store{
dMap: dMap,
}
}

func (s *store) AddDistributor(obj *models.Distributor) *models.Distributor {
// storing a distributor in a map
s.dMap.Distributor[obj.Name] = obj

// get call

return s.GetDistributorByName(obj.Name)
}

func (s *store) GetDistributorByName(distributorName string) *models.Distributor {
distributorName = strings.ToUpper(distributorName)

distributor, ok := s.dMap.Distributor[distributorName]
if !ok {
return nil
}

return distributor
}

func (s *store) GetLocationDetailsByCity(cityName string) *models.Location {
cityName = strings.ToUpper(cityName)

loc, ok := s.dMap.CityMap[cityName]
if !ok {
return nil
}

return loc
}

func (s *store) GetLocationDetailsByProvince(province string) *models.Location {
province = strings.ToUpper(province)
loc, ok := s.dMap.ProvinceMap[province]
if !ok {
return nil
}
return loc
}

func (s *store) GetLocationDetailsByCountry(countryName string) *models.Location {
countryName = strings.ToUpper(countryName)

loc, ok := s.dMap.CountryMap[countryName]
if !ok {
return nil
}

return loc
}
Loading