// NotepadCreatePOST handles the note creation form submission func NotepadCreatePOST(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // Validate with required fields if validate, missingField := view.Validate(r, []string{"note"}); !validate { sess.AddFlash(view.Flash{"Field missing: " + missingField, view.FlashError}) sess.Save(r, w) NotepadCreateGET(w, r) return } // Get form values content := r.FormValue("note") userID := fmt.Sprintf("%s", sess.Values["id"]) // Get database result err := model.NoteCreate(content, userID) // Will only error if there is a problem with the query if err != nil { log.Println(err) sess.AddFlash(view.Flash{"An error occurred on the server. Please try again later.", view.FlashError}) sess.Save(r, w) } else { sess.AddFlash(view.Flash{"Note added!", view.FlashSuccess}) sess.Save(r, w) http.Redirect(w, r, "/notepad", http.StatusFound) return } // Display the same page NotepadCreateGET(w, r) }
// NotepadUpdateGET displays the note update page func NotepadUpdateGET(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // Get the note id var params httprouter.Params params = context.Get(r, "params").(httprouter.Params) noteID := params.ByName("id") userID := fmt.Sprintf("%s", sess.Values["id"]) // Get the note note, err := model.NoteByID(userID, noteID) if err != nil { // If the note doesn't exist log.Println(err) sess.AddFlash(view.Flash{"An error occurred on the server. Please try again later.", view.FlashError}) sess.Save(r, w) http.Redirect(w, r, "/notepad", http.StatusFound) return } // Display the view v := view.New(r) v.Name = "notepad/update" v.Vars["token"] = csrfbanana.Token(w, r, sess) v.Vars["note"] = note.Content v.Render(w) }
// New returns a new view func New(req *http.Request) *View { v := &View{} v.Vars = make(map[string]interface{}) v.Vars["AuthLevel"] = "anon" v.BaseURI = viewInfo.BaseURI v.Extension = viewInfo.Extension v.Folder = viewInfo.Folder v.Name = viewInfo.Name // Make sure BaseURI is available in the templates v.Vars["BaseURI"] = v.BaseURI // This is required for the view to access the request v.request = req // Get session sess := session.Instance(v.request) // Set the AuthLevel to auth if the user is logged in if sess.Values["id"] != nil { v.Vars["AuthLevel"] = "auth" } return v }
// NotepadDeleteGET handles the note deletion func NotepadDeleteGET(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) userID := fmt.Sprintf("%s", sess.Values["id"]) var params httprouter.Params params = context.Get(r, "params").(httprouter.Params) noteID := params.ByName("id") // Get database result err := model.NoteDelete(userID, noteID) // Will only error if there is a problem with the query if err != nil { log.Println(err) sess.AddFlash(view.Flash{"An error occurred on the server. Please try again later.", view.FlashError}) sess.Save(r, w) } else { sess.AddFlash(view.Flash{"Note deleted!", view.FlashSuccess}) sess.Save(r, w) } http.Redirect(w, r, "/notepad", http.StatusFound) return }
// NotepadCreateGET displays the note creation page func NotepadCreateGET(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // Display the view v := view.New(r) v.Name = "notepad/create" v.Vars["token"] = csrfbanana.Token(w, r, sess) v.Render(w) }
// RegisterGET displays the register page func RegisterGET(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // Display the view v := view.New(r) v.Name = "register/register" v.Vars["token"] = csrfbanana.Token(w, r, sess) // Refill any form fields view.Repopulate([]string{"first_name", "last_name", "email"}, r.Form, v.Vars) v.Render(w) }
// LogoutGET clears the session and logs the user out func LogoutGET(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // If user is authenticated if sess.Values["id"] != nil { session.Empty(sess) sess.AddFlash(view.Flash{"Goodbye!", view.FlashNotice}) sess.Save(r, w) } http.Redirect(w, r, "/", http.StatusFound) }
// DisallowAuth does not allow authenticated users to access the page func DisallowAuth(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // If user is authenticated, don't allow them to access the page if sess.Values["id"] != nil { http.Redirect(w, r, "/", http.StatusFound) return } h.ServeHTTP(w, r) }) }
// SendFlashes allows retrieval of flash messages for using with Ajax func (v *View) SendFlashes(w http.ResponseWriter) { // Get session sess := session.Instance(v.request) flashes := peekFlashes(w, v.request) sess.Save(v.request, w) js, err := json.Marshal(flashes) if err != nil { http.Error(w, "JSON Error: "+err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.Write(js) }
// IndexGET displays the home page func IndexGET(w http.ResponseWriter, r *http.Request) { // Get session session := session.Instance(r) if session.Values["id"] != nil { // Display the view v := view.New(r) v.Name = "index/auth" v.Vars["first_name"] = session.Values["first_name"] v.Render(w) } else { // Display the view v := view.New(r) v.Name = "index/anon" v.Render(w) return } }
// NotepadReadGET displays the notes in the notepad func NotepadReadGET(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) userID := fmt.Sprintf("%s", sess.Values["id"]) notes, err := model.NotesByUserID(userID) if err != nil { log.Println(err) notes = []model.Note{} } // Display the view v := view.New(r) v.Name = "notepad/read" v.Vars["first_name"] = sess.Values["first_name"] v.Vars["notes"] = notes v.Render(w) }
func peekFlashes(w http.ResponseWriter, r *http.Request) []Flash { // Get session sess := session.Instance(r) var v []Flash // Get the flashes for the template if flashes := sess.Flashes(); len(flashes) > 0 { v = make([]Flash, len(flashes)) for i, f := range flashes { switch f.(type) { case Flash: v[i] = f.(Flash) default: v[i] = Flash{f.(string), "alert-box"} } } } return v }
// Render renders a template to the writer func (v *View) Render(w http.ResponseWriter) { // Get the template collection from cache mutex.RLock() tc, ok := templateCollection[v.Name] mutex.RUnlock() // Get the plugin collection mutexPlugins.RLock() pc := pluginCollection mutexPlugins.RUnlock() // If the template collection is not cached or caching is disabled if !ok || !viewInfo.Caching { // List of template names var templateList []string templateList = append(templateList, rootTemplate) templateList = append(templateList, v.Name) templateList = append(templateList, childTemplates...) // Loop through each template and test the full path for i, name := range templateList { // Get the absolute path of the root template path, err := filepath.Abs(v.Folder + string(os.PathSeparator) + name + "." + v.Extension) if err != nil { http.Error(w, "Template Path Error: "+err.Error(), http.StatusInternalServerError) return } templateList[i] = path } // Determine if there is an error in the template syntax templates, err := template.New(v.Name).Funcs(pc).ParseFiles(templateList...) if err != nil { http.Error(w, "Template Parse Error: "+err.Error(), http.StatusInternalServerError) return } // Cache the template collection mutex.Lock() templateCollection[v.Name] = templates mutex.Unlock() // Save the template collection tc = templates } // Get session sess := session.Instance(v.request) // Get the flashes for the template if flashes := sess.Flashes(); len(flashes) > 0 { v.Vars["flashes"] = make([]Flash, len(flashes)) for i, f := range flashes { switch f.(type) { case Flash: v.Vars["flashes"].([]Flash)[i] = f.(Flash) default: v.Vars["flashes"].([]Flash)[i] = Flash{f.(string), "alert-box"} } } sess.Save(v.request, w) } // Display the content to the screen err := tc.Funcs(pc).ExecuteTemplate(w, rootTemplate+"."+v.Extension, v.Vars) if err != nil { http.Error(w, "Template File Error: "+err.Error(), http.StatusInternalServerError) } }
// RegisterPOST handles the registration form submission func RegisterPOST(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // Prevent brute force login attempts by not hitting MySQL and pretending like it was invalid :-) if sess.Values["register_attempt"] != nil && sess.Values["register_attempt"].(int) >= 5 { log.Println("Brute force register prevented") http.Redirect(w, r, "/register", http.StatusFound) return } // Validate with required fields if validate, missingField := view.Validate(r, []string{"first_name", "last_name", "email", "password"}); !validate { sess.AddFlash(view.Flash{"Field missing: " + missingField, view.FlashError}) sess.Save(r, w) RegisterGET(w, r) return } // Validate with Google reCAPTCHA if !recaptcha.Verified(r) { sess.AddFlash(view.Flash{"reCAPTCHA invalid!", view.FlashError}) sess.Save(r, w) RegisterGET(w, r) return } // Get form values firstName := r.FormValue("first_name") lastName := r.FormValue("last_name") email := r.FormValue("email") password, errp := passhash.HashString(r.FormValue("password")) // If password hashing failed if errp != nil { log.Println(errp) sess.AddFlash(view.Flash{"An error occurred on the server. Please try again later.", view.FlashError}) sess.Save(r, w) http.Redirect(w, r, "/register", http.StatusFound) return } // Get database result _, err := model.UserByEmail(email) if err == model.ErrNoResult { // If success (no user exists with that email) ex := model.UserCreate(firstName, lastName, email, password) // Will only error if there is a problem with the query if ex != nil { log.Println(ex) sess.AddFlash(view.Flash{"An error occurred on the server. Please try again later.", view.FlashError}) sess.Save(r, w) } else { sess.AddFlash(view.Flash{"Account created successfully for: " + email, view.FlashSuccess}) sess.Save(r, w) http.Redirect(w, r, "/login", http.StatusFound) return } } else if err != nil { // Catch all other errors log.Println(err) sess.AddFlash(view.Flash{"An error occurred on the server. Please try again later.", view.FlashError}) sess.Save(r, w) } else { // Else the user already exists sess.AddFlash(view.Flash{"Account already exists for: " + email, view.FlashError}) sess.Save(r, w) } // Display the page RegisterGET(w, r) }
// LoginPOST handles the login form submission func LoginPOST(w http.ResponseWriter, r *http.Request) { // Get session sess := session.Instance(r) // Prevent brute force login attempts by not hitting MySQL and pretending like it was invalid :-) if sess.Values[sessLoginAttempt] != nil && sess.Values[sessLoginAttempt].(int) >= 5 { log.Println("Brute force login prevented") sess.AddFlash(view.Flash{"Sorry, no brute force :-)", view.FlashNotice}) sess.Save(r, w) LoginGET(w, r) return } // Validate with required fields if validate, missingField := view.Validate(r, []string{"email", "password"}); !validate { sess.AddFlash(view.Flash{"Field missing: " + missingField, view.FlashError}) sess.Save(r, w) LoginGET(w, r) return } // Form values email := r.FormValue("email") password := r.FormValue("password") // Get database result result, err := model.UserByEmail(email) // Determine if user exists if err == model.ErrNoResult { loginAttempt(sess) sess.AddFlash(view.Flash{"Password is incorrect - Attempt: " + fmt.Sprintf("%v", sess.Values[sessLoginAttempt]), view.FlashWarning}) sess.Save(r, w) } else if err != nil { // Display error message log.Println(err) sess.AddFlash(view.Flash{"There was an error. Please try again later.", view.FlashError}) sess.Save(r, w) } else if passhash.MatchString(result.Password, password) { if result.StatusID != 1 { // User inactive and display inactive message sess.AddFlash(view.Flash{"Account is inactive so login is disabled.", view.FlashNotice}) sess.Save(r, w) } else { // Login successfully session.Empty(sess) sess.AddFlash(view.Flash{"Login successful!", view.FlashSuccess}) sess.Values["id"] = result.UserID() sess.Values["email"] = email sess.Values["first_name"] = result.FirstName sess.Save(r, w) http.Redirect(w, r, "/", http.StatusFound) return } } else { loginAttempt(sess) sess.AddFlash(view.Flash{"Password is incorrect - Attempt: " + fmt.Sprintf("%v", sess.Values[sessLoginAttempt]), view.FlashWarning}) sess.Save(r, w) } // Show the login page again LoginGET(w, r) }