| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "html/template" |
| 5 | "net/http" |
| 6 | "strings" |
| 7 | |
| 8 | "github.com/stevedylandev/andromeda/pkg/auth" |
| 9 | "github.com/stevedylandev/andromeda/pkg/web" |
| 10 | ) |
| 11 | |
| 12 | func (a *App) loginGetHandler(w http.ResponseWriter, r *http.Request) { |
| 13 | web.Render(a.Templates, w, "login.html", loginPageData{Error: r.URL.Query().Get("error")}, a.Log) |
| 14 | } |
| 15 | |
| 16 | func (a *App) loginPostHandler(w http.ResponseWriter, r *http.Request) { |
| 17 | if err := r.ParseForm(); err != nil { |
| 18 | web.RedirectWithError(w, r, "/login", "Invalid request") |
| 19 | return |
| 20 | } |
| 21 | if !auth.SecureEqual(r.FormValue("password"), a.Password) { |
| 22 | web.RedirectWithError(w, r, "/login", "Invalid password") |
| 23 | return |
| 24 | } |
| 25 | token, err := a.Sessions.Create() |
| 26 | if err != nil { |
| 27 | a.Log.Error("create session failed", "err", err) |
| 28 | web.RedirectWithError(w, r, "/login", "Server error") |
| 29 | return |
| 30 | } |
| 31 | http.SetCookie(w, a.Sessions.SessionCookie(token)) |
| 32 | http.Redirect(w, r, "/", http.StatusSeeOther) |
| 33 | } |
| 34 | |
| 35 | func (a *App) logoutHandler(w http.ResponseWriter, r *http.Request) { |
| 36 | if c, err := r.Cookie(a.Sessions.CookieName); err == nil && c.Value != "" { |
| 37 | a.Sessions.Delete(c.Value) |
| 38 | } |
| 39 | http.SetCookie(w, a.Sessions.ClearCookie()) |
| 40 | http.Redirect(w, r, "/login", http.StatusSeeOther) |
| 41 | } |
| 42 | |
| 43 | func (a *App) indexHandler(w http.ResponseWriter, r *http.Request) { |
| 44 | notes, err := listNotes(a.DB) |
| 45 | if err != nil { |
| 46 | a.Log.Error("list notes failed", "err", err) |
| 47 | http.Error(w, "internal server error", http.StatusInternalServerError) |
| 48 | return |
| 49 | } |
| 50 | web.Render(a.Templates, w, "index.html", indexPageData{Notes: notes}, a.Log) |
| 51 | } |
| 52 | |
| 53 | func (a *App) newNoteGetHandler(w http.ResponseWriter, r *http.Request) { |
| 54 | web.Render(a.Templates, w, "new.html", newPageData{Error: r.URL.Query().Get("error")}, a.Log) |
| 55 | } |
| 56 | |
| 57 | func (a *App) createNoteHandler(w http.ResponseWriter, r *http.Request) { |
| 58 | if err := r.ParseForm(); err != nil { |
| 59 | web.RedirectWithError(w, r, "/notes/new", "Invalid request") |
| 60 | return |
| 61 | } |
| 62 | title := strings.TrimSpace(r.FormValue("title")) |
| 63 | content := r.FormValue("content") |
| 64 | if title == "" { |
| 65 | web.RedirectWithError(w, r, "/notes/new", "Title is required") |
| 66 | return |
| 67 | } |
| 68 | note, err := createNote(a.DB, title, content) |
| 69 | if err != nil { |
| 70 | a.Log.Error("create note failed", "err", err) |
| 71 | web.RedirectWithError(w, r, "/notes/new", "Failed to create note") |
| 72 | return |
| 73 | } |
| 74 | http.Redirect(w, r, "/notes/"+note.ShortID, http.StatusSeeOther) |
| 75 | } |
| 76 | |
| 77 | func (a *App) viewNoteHandler(w http.ResponseWriter, r *http.Request) { |
| 78 | shortID := r.PathValue("short_id") |
| 79 | note, err := getNoteByShortID(a.DB, shortID) |
| 80 | if err != nil { |
| 81 | a.Log.Error("get note failed", "err", err) |
| 82 | http.Error(w, "internal server error", http.StatusInternalServerError) |
| 83 | return |
| 84 | } |
| 85 | if note == nil { |
| 86 | http.Error(w, "Note not found", http.StatusNotFound) |
| 87 | return |
| 88 | } |
| 89 | rendered, err := renderMarkdown(note.Content) |
| 90 | if err != nil { |
| 91 | a.Log.Error("render markdown failed", "err", err) |
| 92 | http.Error(w, "internal server error", http.StatusInternalServerError) |
| 93 | return |
| 94 | } |
| 95 | web.Render(a.Templates, w, "view.html", viewPageData{Note: *note, Rendered: template.HTML(rendered)}, a.Log) |
| 96 | } |
| 97 | |
| 98 | func (a *App) editNoteGetHandler(w http.ResponseWriter, r *http.Request) { |
| 99 | shortID := r.PathValue("short_id") |
| 100 | note, err := getNoteByShortID(a.DB, shortID) |
| 101 | if err != nil { |
| 102 | a.Log.Error("get note failed", "err", err) |
| 103 | http.Error(w, "internal server error", http.StatusInternalServerError) |
| 104 | return |
| 105 | } |
| 106 | if note == nil { |
| 107 | http.Error(w, "Note not found", http.StatusNotFound) |
| 108 | return |
| 109 | } |
| 110 | web.Render(a.Templates, w, "edit.html", editPageData{Note: *note, Error: r.URL.Query().Get("error")}, a.Log) |
| 111 | } |
| 112 | |
| 113 | func (a *App) updateNoteHandler(w http.ResponseWriter, r *http.Request) { |
| 114 | shortID := r.PathValue("short_id") |
| 115 | if err := r.ParseForm(); err != nil { |
| 116 | web.RedirectWithError(w, r, "/notes/"+shortID+"/edit", "Invalid request") |
| 117 | return |
| 118 | } |
| 119 | title := strings.TrimSpace(r.FormValue("title")) |
| 120 | content := r.FormValue("content") |
| 121 | if title == "" { |
| 122 | web.RedirectWithError(w, r, "/notes/"+shortID+"/edit", "Title is required") |
| 123 | return |
| 124 | } |
| 125 | note, err := updateNoteByShortID(a.DB, shortID, title, content) |
| 126 | if err != nil { |
| 127 | a.Log.Error("update note failed", "err", err) |
| 128 | web.RedirectWithError(w, r, "/notes/"+shortID+"/edit", "Failed to update note") |
| 129 | return |
| 130 | } |
| 131 | if note == nil { |
| 132 | http.Error(w, "Note not found", http.StatusNotFound) |
| 133 | return |
| 134 | } |
| 135 | http.Redirect(w, r, "/notes/"+shortID, http.StatusSeeOther) |
| 136 | } |
| 137 | |
| 138 | func (a *App) deleteNoteHandler(w http.ResponseWriter, r *http.Request) { |
| 139 | shortID := r.PathValue("short_id") |
| 140 | if _, err := deleteNoteByShortID(a.DB, shortID); err != nil { |
| 141 | a.Log.Error("delete note failed", "err", err) |
| 142 | } |
| 143 | http.Redirect(w, r, "/", http.StatusSeeOther) |
| 144 | } |