diff --git a/auth/main.go b/auth/main.go index 0203e58..4ccc41a 100644 --- a/auth/main.go +++ b/auth/main.go @@ -27,7 +27,7 @@ func SetupAuthboss() { Ab.LayoutDataMaker = layoutData - b, err := ioutil.ReadFile(filepath.Join("templates", "base.html.tpl")) + b, err := ioutil.ReadFile(filepath.Join("templates", "base.html")) if err != nil { panic(err) } diff --git a/config/dev.yaml b/config/dev.yaml new file mode 100644 index 0000000..e69de29 diff --git a/config/prod.yaml b/config/prod.yaml new file mode 100644 index 0000000..e69de29 diff --git a/controller/controller.go b/controller/controller.go new file mode 100644 index 0000000..fcfc0d7 --- /dev/null +++ b/controller/controller.go @@ -0,0 +1,178 @@ +package controller + +import ( + "html/template" + "net/http" + "errors" + "github.com/gorilla/mux" + "github.com/toasterson/mozaik/router" + "mime/multipart" + "fmt" + "github.com/dannyvankooten/grender" +) + +var ( + globTplCache = map[string]*template.Template{} + grend *grender.Grender +) + +type Controller struct { + postFormParsed bool + isInitialized bool + Routes []router.Route + Data map[interface{}]interface{} + Name string + TplName string + TplExt string + W http.ResponseWriter + R *http.Request +} + +type ControllerInterface interface { + Init() //method = Initializes the Controller + Prepare(w http.ResponseWriter, r *http.Request) //method = SetUp All Local Variables needed for the Functions + Get() error //method = GET processing + Post() error //method = POST processing + Delete() error //method = DELETE processing + Put() error //method = PUT handling + Head() error //method = HEAD processing + Patch() error //method = PATCH treatment + Options() error //method = OPTIONS processing + Finish() //method = Used to clear Temporary Variables and Cleanup + GetRoutes() []router.Route //Get the Routes of the Controller +} + +type Handler struct { + ControllerInterface +} + +func (this *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + this.Prepare(w, r) + defer this.Finish() + var err error = nil + switch r.Method { + case http.MethodGet: + err = this.Get() + case http.MethodPost: + err = this.Post() + case http.MethodPatch: + err = this.Patch() + case http.MethodPut: + err = this.Put() + case http.MethodHead: + err = this.Head() + case http.MethodDelete: + err = this.Delete() + case http.MethodOptions: + err = this.Options() + default: + err = errors.New("No Method") + } + //TODO Better Handling Should an error Occur Maybe Custom error Class? + if err != nil { + fmt.Println(err) + http.Error(w, err.Error(), http.StatusMethodNotAllowed) + } +} + +func MakeHandler(controllerInterface ControllerInterface) *Handler{ + return &Handler{controllerInterface} +} + +func SetUpRouting(mux_router *mux.Router, controllers []ControllerInterface){ + for _, controller := range controllers { + controller.Init() + for _, route := range controller.GetRoutes() { + mux_router.Handle(route.Path, MakeHandler(controller)).Methods(route.Method) + } + } +} + +func (this *Controller) GetRoutes() []router.Route{ + return this.Routes +} + +func (this *Controller) Prepare(w http.ResponseWriter, r *http.Request){ + this.W = w + this.R = r +} + +func (this *Controller) Finish(){ + this.W = nil + this.R = nil +} + +func (this *Controller) Init() {} + +func (this *Controller) SuperInit() { + if !this.isInitialized { + this.postFormParsed = false + this.Data = make(map[interface{}]interface{}) + this.TplName = "" + this.TplExt = "html" + this.isInitialized = true + } +} + +func (this *Controller) Get() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Post() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Delete() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Put() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Head() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Patch() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Options() error { + return errors.New("Not Allowed") +} + +func (this *Controller) Render() error { + return grend.HTML(this.W, http.StatusOK, this.TplName+"."+this.TplExt, this.Data) +} + +func (this *Controller) ParseForm(maxMem int64) error { + return this.R.ParseMultipartForm(maxMem) +} + +func (this *Controller) PostFormValue(key string) string{ + return this.R.PostFormValue(key) +} + +func (this *Controller) FormFile(key string) (multipart.File, *multipart.FileHeader, error){ + return this.R.FormFile(key) +} + +//Initialize Global Server stuff +func Init(tplGlob string, debug bool, partialGlob string, funcs template.FuncMap) { + grend = grender.New(grender.Options{ + Debug: debug, // If true, templates will be recompiled before each render call + TemplatesGlob: tplGlob, // Glob to your template files + PartialsGlob: partialGlob, // Glob to your patials or global templates + Funcs: funcs, // Your template FuncMap + Charset: "UTF-8", // Charset to use for Content-Type header values + }) +} + +func Forbidden(w http.ResponseWriter, r *http.Request) { + grend.HTML(w, http.StatusForbidden, "forbidden.html", nil) +} + +func NotFound(w http.ResponseWriter, r *http.Request) { + grend.HTML(w, http.StatusNotFound, "notfound.html", nil) +} diff --git a/mozaik.go b/mozaik.go index 8a78d6d..b289c4e 100644 --- a/mozaik.go +++ b/mozaik.go @@ -4,16 +4,14 @@ import ( "net/http" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" - "io" "os" "log" "github.com/toasterson/mozaik/auth" "github.com/gorilla/schema" "encoding/base64" "github.com/gorilla/mux" + "github.com/toasterson/mozaik/controller" "github.com/justinas/alice" - "fmt" - "html/template" ) var schemaDec = schema.NewDecoder() @@ -21,6 +19,12 @@ var pages = map[string]Page{ "testing": {"Testing", []byte("Testing")}, } +var ( + mainCont = MainController{} + newPageCont = NewPageController{} + pageDetailCont = PageDetailController{} +) + type Pages map[string]Page type Page struct { @@ -28,26 +32,6 @@ type Page struct { Body []byte } -func loadPage(title string) (Page, error) { - return pages[title], nil -} - -func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) { - t, _ := template.ParseFiles(tmpl + ".html") - t.Execute(w, p) -} - -func viewHandler(w http.ResponseWriter, r *http.Request) { - title := r.URL.Path[len("/view/"):] - p, err := loadPage(title) - if err != nil { - http.NotFound(w, r) - return - } - renderTemplate(w, "templates/view", &p) -} - - func main() { // Initialize Sessions and Cookies // Typically gorilla securecookie and sessions packages require @@ -74,27 +58,26 @@ func main() { auth.SetSessionStore(sessions.NewCookieStore(sessionStoreKey)) // Initialize ab. - auth.SetupAuthboss() + //auth.SetupAuthboss() + + //Load Templates to cache + controller.Init("./templates/*.html", true, "", nil) // Set up our router schemaDec.IgnoreUnknownKeys(true) - router := mux.NewRouter() - - // Routes - gets := router.Methods("GET").Subrouter() - - router.PathPrefix("/auth").Handler(auth.Ab.NewRouter()) - - gets.HandleFunc("/view/{title}", viewHandler) + //Routes + mux_router := mux.NewRouter() - router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotFound) - io.WriteString(w, "Not found") + controller.SetUpRouting(mux_router, []controller.ControllerInterface{ + &mainCont, + &newPageCont, + &pageDetailCont, }) + mux_router.NotFoundHandler = http.HandlerFunc(controller.NotFound) // Set up our middleware chain - stack := alice.New(auth.Logger, auth.Nosurfing, auth.Ab.ExpireMiddleware).Then(router) + stack := alice.New(auth.Logger).Then(mux_router) // Start the server port := os.Getenv("PORT") @@ -109,16 +92,4 @@ func index(w http.ResponseWriter, r *http.Request) { data := layoutData(w, r).MergeKV("posts", blogs) mustRender(w, r, "index", data) } -*/ - -func badRequest(w http.ResponseWriter, err error) bool { - if err == nil { - return false - } - - w.Header().Set("Content-Type", "text/plain") - w.WriteHeader(http.StatusBadRequest) - fmt.Fprintln(w, "Bad request:", err) - - return true -} \ No newline at end of file +*/ \ No newline at end of file diff --git a/router/routes.go b/router/routes.go new file mode 100644 index 0000000..88037c2 --- /dev/null +++ b/router/routes.go @@ -0,0 +1,8 @@ +package router + +type Route struct { + Method string + Path string +} + + diff --git a/templates/base.html.tpl b/templates/base.html similarity index 96% rename from templates/base.html.tpl rename to templates/base.html index b414cb5..5edc6a6 100644 --- a/templates/base.html.tpl +++ b/templates/base.html @@ -39,6 +39,9 @@ +
+ {{template "content" .}} +
{{with .flash_success}}
{{.}}
{{end}} diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..ad55605 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,12 @@ +{{/* extends "base.html" */}} + +{{define "content"}} +{{$loggedin := .loggedin}} + {{if $loggedin}} +
+
+ New Post +
+
+ {{end}} +{{end}} \ No newline at end of file diff --git a/templates/index.html.tpl b/templates/index.html.tpl deleted file mode 100644 index 489967a..0000000 --- a/templates/index.html.tpl +++ /dev/null @@ -1,37 +0,0 @@ -{{define "pagetitle"}}Blogs - Index{{end}} - -{{$loggedin := .loggedin}} -{{if $loggedin}} -
-
- New Post -
-
-{{end}} - -
-
- {{range .posts}} -
-
-
-
{{.Title}}
-
- {{if $loggedin}} - Edit - Delete - {{end}} -
-
-
-
{{.Content}}
- -
- {{end}} -
-
\ No newline at end of file diff --git a/templates/view.html b/templates/notfound.html similarity index 51% rename from templates/view.html rename to templates/notfound.html index fc053f9..722bdb0 100644 --- a/templates/view.html +++ b/templates/notfound.html @@ -2,10 +2,9 @@ - Title + 404 Not Found -

{{.Title}}

-
{{printf "%s" .Body}}
+

404 Not Found

\ No newline at end of file diff --git a/templates/page_form.html b/templates/page_form.html new file mode 100644 index 0000000..fa6c560 --- /dev/null +++ b/templates/page_form.html @@ -0,0 +1,15 @@ +{{/* extends "base.html" */}} + +{{define "content"}} +
+ + + +
+{{end}} \ No newline at end of file diff --git a/templates/page_view.html b/templates/page_view.html new file mode 100644 index 0000000..b692b37 --- /dev/null +++ b/templates/page_view.html @@ -0,0 +1,7 @@ +{{/* extends "base.html" */}} + +{{define "content"}} +{{$page := index . "page"}} +

{{$page.Title}}

+
{{printf "%s" $page.Body}}
+{{end}} \ No newline at end of file diff --git a/util.go b/util.go deleted file mode 100644 index 06ab7d0..0000000 --- a/util.go +++ /dev/null @@ -1 +0,0 @@ -package main diff --git a/util/util.go b/util/util.go new file mode 100644 index 0000000..0af8917 --- /dev/null +++ b/util/util.go @@ -0,0 +1,24 @@ +package util + +import ( + "net/http" + "fmt" +) + +func Must(err error){ + if err != nil { + panic(err) + } +} + +func HTTPBadRequest(w http.ResponseWriter, err error) bool { + if err == nil { + return false + } + + w.Header().Set("Content-Type", "text/plain") + w.WriteHeader(http.StatusBadRequest) + fmt.Fprintln(w, "Bad request:", err) + + return true +} diff --git a/views.go b/views.go index 06ab7d0..5c2d7ec 100644 --- a/views.go +++ b/views.go @@ -1 +1,78 @@ package main + +import ( + "github.com/toasterson/mozaik/router" + "github.com/toasterson/mozaik/controller" + "net/http" + "github.com/gorilla/mux" + "fmt" + "errors" +) + +type MainController struct { + controller.Controller +} + +func (c *MainController) Get() error { + return c.Render() +} + +func (c *MainController) Init() { + c.SuperInit() + c.TplName = "index" + c.Routes = []router.Route{ + {http.MethodGet, "/"}, + } +} + +//TODO See if we can make one ListController with different Parameters instead of one per Object +type PageDetailController struct { + controller.Controller +} + +func (c *PageDetailController) Init() { + c.SuperInit() + c.TplName = "page_view" + c.Routes = []router.Route{ + {http.MethodGet, "/pages/{title}"}, + } +} + +func (c *PageDetailController) Get() error { + vars := mux.Vars(c.R) + title := vars["title"] + //TODO Load from DB Here + var ok bool + c.Data["page"], ok = pages[title] + if !ok { + return errors.New("Does Not Exist yet Maybe create it?") + } + return c.Render() +} + +type NewPageController struct { + controller.Controller +} + +func (c *NewPageController) Init() { + c.SuperInit() + c.TplName = "page_form" + c.Routes = []router.Route{ + {http.MethodGet, "/pages/new"}, + {http.MethodPost, "/pages/new"}, + } +} + +func (c *NewPageController) Get() error { + return c.Render() +} + +func (c *NewPageController) Post() error{ + title := c.PostFormValue("title") + p := Page{title, []byte(c.PostFormValue("body"))} + //TODO Database Saving Here + pages[title] = p + fmt.Println(pages) + http.Redirect(c.W, c.R, title, http.StatusSeeOther) + return nil +}