github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/menus/menus.go (about) 1 package menus 2 3 import ( 4 "fmt" 5 6 "github.com/gocaveman/caveman/webutil" 7 ) 8 9 var ErrNotFound = webutil.ErrNotFound 10 var ErrAlreadyExists = fmt.Errorf("already exists") 11 12 type Store interface { 13 ReadMenuItem(id string) (*MenuItem, error) 14 CreateMenuItem(mi *MenuItem) error 15 UpdateMenuItem(mi *MenuItem) error 16 DeleteMenuItem(id string) error 17 // FIXME: Do we need a recursive delete? If not, do we allow 18 // deletes for ones that have children? We could just block that 19 // action and provide a separate naked function to do a recurive delete. 20 FindChildren(id string) ([]string, error) 21 } 22 23 type MenuItemReader interface { 24 ReadMenuItem(id string) (*MenuItem, error) 25 FindChildren(id string) ([]string, error) 26 } 27 28 type MenuItem struct { 29 MenuID string `json:"menu_id" yaml:"menu_id" db:"menu_id"` 30 ParentMenuID string `json:"parent_menu_id" yaml:"parent_menu_id" db:"parent_menu_id"` 31 Sequence float64 `json:"sequence" yaml:"sequence" db:"sequence"` 32 Title string `json:"title" yaml:"title" db:"title"` 33 Meta webutil.SimpleStringDataMap `json:"meta" yaml:"meta" db:"meta"` 34 Enabled bool `json:"enabled" yaml:"enabled" db:"enabled"` 35 } 36 37 type MenuItemList []MenuItem 38 39 // TODO: We could probably add some builder pattern stuff here so you can do things 40 // like WithChildren() or other things that would make statically providing some menus 41 // in a package to the registry easier to do. 42 43 func (a MenuItemList) Len() int { return len(a) } 44 func (a MenuItemList) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 45 func (a MenuItemList) Less(i, j int) bool { 46 if a[i].Sequence == a[j].Sequence { 47 return a[i].MenuID < a[j].MenuID 48 } 49 return a[i].Sequence < a[j].Sequence 50 } 51 52 // TODO: MenuScopeHandler to provide MenuScope in context, 53 // and then register it in the handlerregistry and autowire. 54 55 // MenuScope provides display facilities for use in templates. 56 type MenuScope struct { 57 MenuItemReader `autowire:""` 58 } 59 60 func (ms *MenuScope) Display(id string) (DisplayMenuItem, error) { 61 return BuildDisplayMenuItem(ms.MenuItemReader, id) 62 } 63 64 type DisplayMenuItem struct { 65 MenuItem 66 Children []DisplayMenuItem `json:"children,omitempty" yaml:"children,omitempty"` 67 Additional map[string]interface{} `json:"additional,omitempty" yaml:"additional,omitempty"` 68 } 69 70 func BuildDisplayMenuItem(r MenuItemReader, id string) (ret DisplayMenuItem, err error) { 71 72 var mi *MenuItem 73 mi, err = r.ReadMenuItem(id) 74 if err != nil { 75 return 76 } 77 ret.MenuItem = *mi 78 79 var childIDs []string 80 childIDs, err = r.FindChildren(id) 81 if err != nil { 82 return 83 } 84 85 for _, childID := range childIDs { 86 var child DisplayMenuItem 87 child, err = BuildDisplayMenuItem(r, childID) 88 if err != nil { 89 return 90 } 91 ret.Children = append(ret.Children, child) 92 } 93 94 return 95 }