diff options
-rw-r--r-- | content/post.go (renamed from post.go) | 50 | ||||
-rw-r--r-- | content/types.go | 7 | ||||
-rw-r--r-- | management/editor/editor.go (renamed from editor/editor.go) | 10 | ||||
-rw-r--r-- | management/editor/elements.go (renamed from editor/element.go) | 2 | ||||
-rw-r--r-- | management/manager/manager.go | 46 | ||||
-rw-r--r-- | server.go | 78 | ||||
-rw-r--r-- | system/admin.go | 2 | ||||
-rw-r--r-- | system/db/item.go | 8 | ||||
-rw-r--r-- | system/db/query.go | 21 |
9 files changed, 181 insertions, 43 deletions
diff --git a/post.go b/content/post.go index 3ae0b92..65ea88f 100644 --- a/post.go +++ b/content/post.go @@ -1,15 +1,15 @@ -package main +package content import ( - "bytes" "fmt" - "net/http" - "github.com/nilslice/cms/editor" + "github.com/nilslice/cms/management/editor" + "github.com/nilslice/cms/system/db" ) // Post is the generic content struct type Post struct { + db.Item editor editor.Editor Title []byte `json:"title"` @@ -18,23 +18,18 @@ type Post struct { Timestamp []byte `json:"timestamp"` } -// Editor partially implements editor.Editable -func (p *Post) Editor() *editor.Editor { - return &p.editor +func init() { + Types["Post"] = Post{} } -// NewViewBuffer partially implements editor.Editable -func (p *Post) NewViewBuffer() { - p.editor.ViewBuf = &bytes.Buffer{} -} +// ContentID partially implements editor.Editable +func (p Post) ContentID() int { return p.ID } -// Render partially implements editor.Editable -func (p *Post) Render() []byte { - return p.editor.ViewBuf.Bytes() -} +// Editor partially implements editor.Editable +func (p Post) Editor() *editor.Editor { return &p.editor } -// EditView writes a buffer of html to edit a Post -func (p Post) EditView() ([]byte, error) { +// MarshalEditor writes a buffer of html to edit a Post and partially implements editor.Editable +func (p Post) MarshalEditor() ([]byte, error) { view, err := editor.New(&p, editor.Field{ View: editor.Input("Title", &p, map[string]string{ @@ -70,24 +65,3 @@ func (p Post) EditView() ([]byte, error) { return view, nil } - -func (p Post) ServeHTTP(res http.ResponseWriter, req *http.Request) { - res.Header().Set("Content-type", "text/html") - resp, err := p.EditView() - if err != nil { - fmt.Println(err) - } - res.Write(resp) -} - -func main() { - p := Post{ - Content: []byte("<h3>H</h3>ello. My name is <em>Steve</em>."), - Title: []byte("Profound introduction"), - Author: []byte("Steve Manuel"), - Timestamp: []byte("2016-09-16"), - } - - http.ListenAndServe(":8080", p) - -} diff --git a/content/types.go b/content/types.go new file mode 100644 index 0000000..778f742 --- /dev/null +++ b/content/types.go @@ -0,0 +1,7 @@ +package content + +import "github.com/nilslice/cms/management/editor" + +// Types is a map used to reference a type name to its actual Editable type +// mainly for lookups in /admin route based utilities +var Types = make(map[string]editor.Editable) diff --git a/editor/editor.go b/management/editor/editor.go index 11dc064..24b514e 100644 --- a/editor/editor.go +++ b/management/editor/editor.go @@ -6,9 +6,9 @@ import "bytes" // Editable ensures data is editable type Editable interface { + ContentID() int Editor() *Editor - NewViewBuffer() - Render() []byte + MarshalEditor() ([]byte, error) } // Editor is a view containing fields to manage content @@ -25,15 +25,15 @@ type Field struct { // New takes editable content and any number of Field funcs to describe the edit // page for any content struct added by a user func New(post Editable, fields ...Field) ([]byte, error) { - post.NewViewBuffer() - editor := post.Editor() + editor.ViewBuf = &bytes.Buffer{} + for _, f := range fields { addFieldToEditorView(editor, f) } - return post.Render(), nil + return editor.ViewBuf.Bytes(), nil } func addFieldToEditorView(e *Editor, f Field) { diff --git a/editor/element.go b/management/editor/elements.go index 519ce5d..59d74f0 100644 --- a/editor/element.go +++ b/management/editor/elements.go @@ -60,6 +60,7 @@ func domElementSelfClose(e *element, wrapInLabel bool) []byte { for attr, value := range e.Attrs { e.viewBuf.Write([]byte(attr + `="` + string(value) + `"`)) } + e.viewBuf.Write([]byte(` name="` + e.Name + `"`)) e.viewBuf.Write([]byte(` />`)) return e.viewBuf.Bytes() @@ -75,6 +76,7 @@ func domElement(e *element, wrapInLabel bool) []byte { for attr, value := range e.Attrs { e.viewBuf.Write([]byte(attr + `="` + string(value) + `"`)) } + e.viewBuf.Write([]byte(` name="` + e.Name + `"`)) e.viewBuf.Write([]byte(` >`)) e.viewBuf.Write([]byte(e.data)) diff --git a/management/manager/manager.go b/management/manager/manager.go new file mode 100644 index 0000000..83ed63a --- /dev/null +++ b/management/manager/manager.go @@ -0,0 +1,46 @@ +package manager + +import ( + "bytes" + "fmt" + "html/template" + "reflect" + + "github.com/nilslice/cms/management/editor" +) + +var html = ` +<div class="manager"> + <form method="post" action="/admin/edit?type={{.Kind}}&contentId={{.ID}}"> + {{.Editor}} + <input type="submit" value="Save"/> + </form> +</div> +` + +type form struct { + ID int + Kind string + Editor template.HTML +} + +// Manage ... +func Manage(e editor.Editable) ([]byte, error) { + v, err := e.MarshalEditor() + if err != nil { + return nil, fmt.Errorf("Couldn't marshal editor for content %T. %s", e, err.Error()) + } + + f := form{ + ID: e.ContentID(), + Kind: reflect.TypeOf(e).Name(), + Editor: template.HTML(v), + } + + // execute html template into buffer for func return val + buf := &bytes.Buffer{} + tmpl := template.Must(template.New("manager").Parse(html)) + tmpl.Execute(buf, f) + + return buf.Bytes(), nil +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..d7605f6 --- /dev/null +++ b/server.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "net/http" + + "github.com/nilslice/cms/content" + "github.com/nilslice/cms/management/manager" +) + +const ( + // ErrTypeNotRegistered means content type isn't registered (not found in content.Types map) + ErrTypeNotRegistered = `Error: +There is no type registered for %[1]s + +Add this to the file which defines %[1]s{} in the 'content' package: +--------------------------------+ + +func init() { + Types["%[1]s"] = %[1]s{} +} + +--------------------------------+ +` +) + +func main() { + // p := content.Post{ + // Title: []byte("Profound introduction"), + // Content: []byte("<h3>H</h3>ello. My name is <em>Steve</em>."), + // Author: []byte("Steve Manuel"), + // Timestamp: []byte("2016-09-16"), + // } + // p.ID = 1 + + http.HandleFunc("/admin/edit", func(res http.ResponseWriter, req *http.Request) { + switch req.Method { + case http.MethodGet: + err := req.ParseForm() + if err != nil { + res.WriteHeader(http.StatusBadRequest) + return + } + + t := req.FormValue("type") + contentType, ok := content.Types[t] + if !ok { + fmt.Fprintf(res, ErrTypeNotRegistered, t) + return + } + view, err := manager.Manage(contentType) + if err != nil { + res.WriteHeader(http.StatusInternalServerError) + return + } + res.Header().Set("Content-Type", "text/html") + res.Write(view) + + case http.MethodPost: + err := req.ParseForm() + if err != nil { + res.WriteHeader(http.StatusBadRequest) + return + } + + id := req.FormValue("contentId") + if id == "0" { + res.Write([]byte("This would create a new post")) + return + } + + res.Write([]byte("Updated post " + id)) + } + }) + + http.ListenAndServe(":8080", nil) + +} diff --git a/system/admin.go b/system/admin.go new file mode 100644 index 0000000..7fa156a --- /dev/null +++ b/system/admin.go @@ -0,0 +1,2 @@ +// Package system exposes all interfaces to admin and api components +package system diff --git a/system/db/item.go b/system/db/item.go new file mode 100644 index 0000000..23e8553 --- /dev/null +++ b/system/db/item.go @@ -0,0 +1,8 @@ +// Package db ... +package db + +// Item should only be embedded into content type structs. +// Helper for DB-related actions +type Item struct { + ID int `json:"_id"` +} diff --git a/system/db/query.go b/system/db/query.go new file mode 100644 index 0000000..c9cf37c --- /dev/null +++ b/system/db/query.go @@ -0,0 +1,21 @@ +package db + +// Set inserts or updates values in the database. +// The `key` argument is a string made up of namespace:id (string:int) +func Set(key string) error { + + return nil +} + +// Get retrives one item from the database. Non-existent values will return an empty []byte +// The `key` argument is a string made up of namespace:id (string:int) +func Get(key string) []byte { + + return nil +} + +// GetAll retrives all items from the database within the provided namespace +func GetAll(namespace string) [][]byte { + + return nil +} |