package blog import ( "bytes" "context" "log" "net/http" "strings" "time" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" ) type Blog struct { ID string `json:"id" bson:"_id"` Author string `json:"author" bson:"author"` Favicon string `json:"favicon" bson:"favicon"` Title string `json:"title" bson:"title"` RawBlog string `json:"blog" bson:"blog"` HTMLBlog string `json:"-" bson:"-"` StaticPage bool `json:"staticPage" bson:"staticPage"` Draft bool `json:"draft" bson:"draft"` CreateTime int64 `json:"createTime" bson:"createTime"` UpdateTime int64 `json:"updateTime" bson:"updateTime"` } func (b *Backend) GetBlog(ctx context.Context, ID string, allowDraft bool) (Blog, error) { filter := bson.M{"_id": ID} if !allowDraft { filter["draft"] = false } res := b.blogCol.FindOne(ctx, filter) if res.Err() != nil { return Blog{}, res.Err() } var out Blog err := res.Decode(&out) return out, err } func (b *Backend) postBlogReq(w http.ResponseWriter, r *http.Request) { usr := b.verifyEditorCookie(r) if usr == nil { redirect(w, r, "/login") return } if usr.Perm["blog"] != "admin" && usr.Perm["blog"] != "writer" { w.Write([]byte("
Sorry, but you aren't authorized to do this action.
")) return } err := r.ParseForm() if err != nil { w.Write([]byte("Error decoding form
")) return } newBlog := Blog{ ID: r.FormValue("id"), Title: r.FormValue("title"), RawBlog: r.FormValue("blog"), StaticPage: r.FormValue("staticPage") == "on", Draft: r.FormValue("draft") == "on", UpdateTime: time.Now().Unix(), } if newBlog.Title == "" || newBlog.RawBlog == "" { w.Write([]byte("Title and blog contents are required
")) return } if newBlog.ID == "" { newBlog.ID = strings.ToLower(strings.ReplaceAll(newBlog.Title, " ", "-")) newBlog.CreateTime = newBlog.UpdateTime newBlog.Author = usr.Username _, err = b.blogCol.InsertOne(r.Context(), newBlog) if mongo.IsDuplicateKeyError(err) { w.Write([]byte("Title already exists
")) return } else if err != nil { log.Println("error inserting document") w.Write([]byte("Server error inserting document
")) return } b.blogSuccessFullPageReplace(r.Context(), w, newBlog) return } res := b.blogCol.FindOne(r.Context(), bson.M{"_id": newBlog.ID}) if res.Err() == mongo.ErrNoDocuments { w.Write([]byte("Error finding old document
")) return } else if res.Err() != nil { log.Println("error getting old blog for update:", res.Err()) w.Write([]byte("Server error!
")) return } var oldBlog Blog err = res.Decode(&oldBlog) if err != nil { log.Println("error decoding old blog for update:", res.Err()) w.Write([]byte("Server error!
")) return } newBlog.CreateTime = oldBlog.CreateTime if oldBlog.Title != newBlog.Title { res = b.blogCol.FindOne(r.Context(), bson.M{"_id": strings.ToLower(strings.ReplaceAll(newBlog.Title, " ", "-"))}) if res.Err() == nil { w.Write([]byte("Title already exists
")) return } else if res.Err() != mongo.ErrNoDocuments { log.Println("error checking for title existance:", res.Err()) w.Write([]byte("Server error!
")) return } res = b.blogCol.FindOneAndDelete(r.Context(), bson.M{"_id": oldBlog.ID}) if res.Err() != nil { log.Println("error deleting old blog:", res.Err()) w.Write([]byte("Server error!
")) return } newBlog.ID = strings.ToLower(strings.ReplaceAll(newBlog.Title, " ", "-")) _, err = b.blogCol.InsertOne(r.Context(), newBlog) if err != nil { log.Println("error inserting document") w.Write([]byte("Server error inserting document
")) return } b.blogSuccessFullPageReplace(r.Context(), w, newBlog) return } _, err = b.blogCol.UpdateByID(r.Context(), newBlog.ID, bson.M{ "updateTime": newBlog.UpdateTime, "blog": newBlog.RawBlog, "staticPage": newBlog.StaticPage, "draft": newBlog.Draft, }) if err != nil { log.Println("error updating blog:", err) w.Write([]byte("Server error inserting document
")) } else { w.Write([]byte("Successfully updated
")) } } func (b *Backend) blogSuccessFullPageReplace(ctx context.Context, w http.ResponseWriter, blog Blog) { form, err := b.BlogEditForm(blog) if err != nil { log.Println("error with blogForm template:", err) w.Write([]byte("Success, but error reloading page
")) return } out, err := b.BlogEditPage(ctx, blog.ID, form) if err != nil { log.Println("error with getting blog list:", err) w.Write([]byte("Success, but error reloading page
")) return } w.Header().Set("Hx-Retarget", "#editPage") w.Write([]byte(out)) } func (b *Backend) BlogEditForm(blog Blog) (string, error) { form := new(bytes.Buffer) err := b.tmpl.ExecuteTemplate(form, "blogForm", blogFormStruct{ Blog: blog, Result: "Success!!
", }) return form.String(), err } func (b *Backend) blogFormReq(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Hx-Request") != "true" { redirect(w, r, "/editor") return } blogID := r.URL.Query().Get("blog") var blog Blog if blogID != "" { var err error blog, err = b.GetBlog(r.Context(), blogID, true) if err != nil { log.Println("error getting blog:", err) w.Write([]byte("Server error!
")) return } } form, err := b.BlogEditForm(blog) if err != nil { log.Println("error using blogForm template:", err) w.Write([]byte("Server error!
")) return } w.Write([]byte(form)) } func (b *Backend) BlogEditPage(ctx context.Context, selectedID, editor string) (string, error) { blogs, err := b.FullBlogList(ctx) if err != nil { return "", err } out := new(bytes.Buffer) err = b.tmpl.ExecuteTemplate(out, "blogPage", blogPageStruct{ Selected: selectedID, Editor: editor, Blogs: blogs, }) return out.String(), err } func (b *Backend) blogPageReq(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Hx-Request") != "true" { redirect(w, r, "/editor") return } form, err := b.BlogEditForm(Blog{}) if err != nil { log.Println("error using blogForm template:", err) w.Write([]byte("Server error!
")) return } page, err := b.BlogEditPage(r.Context(), "", form) if err != nil { log.Println("error using blogPage template:", err) w.Write([]byte("Server error!
")) return } w.Write([]byte(page)) }