github.com/bosssauce/ponzu@v0.11.1-0.20200102001432-9bc41b703131/examples/deleteable/content/song.go (about) 1 package content 2 3 import ( 4 "fmt" 5 "log" 6 7 "net/http" 8 9 "github.com/ponzu-cms/ponzu/management/editor" 10 "github.com/ponzu-cms/ponzu/system/admin/user" 11 "github.com/ponzu-cms/ponzu/system/api" 12 "github.com/ponzu-cms/ponzu/system/item" 13 ) 14 15 type Song struct { 16 item.Item 17 18 Title string `json:"title"` 19 Artist string `json:"artist"` 20 Rating int `json:"rating"` 21 Opinion string `json:"opinion"` 22 SpotifyURL string `json:"spotify_url"` 23 } 24 25 // MarshalEditor writes a buffer of html to edit a Song within the CMS 26 // and implements editor.Editable 27 func (s *Song) MarshalEditor() ([]byte, error) { 28 view, err := editor.Form(s, 29 // Take note that the first argument to these Input-like functions 30 // is the string version of each Song field, and must follow 31 // this pattern for auto-decoding and auto-encoding reasons: 32 editor.Field{ 33 View: editor.Input("Title", s, map[string]string{ 34 "label": "Title", 35 "type": "text", 36 "placeholder": "Enter the Title here", 37 }), 38 }, 39 editor.Field{ 40 View: editor.Input("Artist", s, map[string]string{ 41 "label": "Artist", 42 "type": "text", 43 "placeholder": "Enter the Artist here", 44 }), 45 }, 46 editor.Field{ 47 View: editor.Input("Rating", s, map[string]string{ 48 "label": "Rating", 49 "type": "text", 50 "placeholder": "Enter the Rating here", 51 }), 52 }, 53 editor.Field{ 54 View: editor.Richtext("Opinion", s, map[string]string{ 55 "label": "Opinion", 56 "placeholder": "Enter the Opinion here", 57 }), 58 }, 59 editor.Field{ 60 View: editor.Input("SpotifyURL", s, map[string]string{ 61 "label": "SpotifyURL", 62 "type": "text", 63 "placeholder": "Enter the SpotifyURL here", 64 }), 65 }, 66 ) 67 68 if err != nil { 69 return nil, fmt.Errorf("Failed to render Song editor view: %s", err.Error()) 70 } 71 72 return view, nil 73 } 74 75 func init() { 76 item.Types["Song"] = func() interface{} { return new(Song) } 77 } 78 79 // String defines the display name of a Song in the CMS list-view 80 func (s *Song) String() string { return s.Title } 81 82 // BeforeAPIDelete is only called if the Song type implements api.Deleteable 83 // It is called before Delete, and returning an error will cancel the request 84 // causing the system to reject the data sent in the POST 85 func (s *Song) BeforeAPIDelete(res http.ResponseWriter, req *http.Request) error { 86 // do initial user authentication here on the request, checking for a 87 // token or cookie, or that certain form fields are set and valid 88 89 // for example, this will check if the request was made by a CMS admin user: 90 if !user.IsValid(req) { 91 return api.ErrNoAuth 92 } 93 94 // you could then to data validation on the request post form, or do it in 95 // the Delete method, which is called after BeforeAPIDelete 96 97 return nil 98 } 99 100 // Delete is called after BeforeAPIDelete and implements api.Deleteable. All 101 // other delete-based hooks are only called if this is implemented. 102 func (s *Song) Delete(res http.ResponseWriter, req *http.Request) error { 103 // See BeforeAPIDelete above, how we have checked the request for some 104 // form of auth. This could be done here instead, but if it is done once 105 // above, it means the request is valid here too. 106 return nil 107 } 108 109 // AfterAPIDelete is called after Delete, and is useful for logging or triggering 110 // notifications, etc. after the data is deleted frm the database, etc. 111 func (s *Song) AfterAPIDelete(res http.ResponseWriter, req *http.Request) error { 112 addr := req.RemoteAddr 113 log.Println("Song deleted by:", addr, "id:", req.URL.Query().Get("id")) 114 115 return nil 116 }