sophuwu.site > myweb
added handler for animations
added managment handlers for anims and blogs
sophuwu sophie@skisiel.com
Wed, 11 Dec 2024 19:57:37 +0100
commit

ecc9b487c08e9d7aff62711da93d3ac6b6421b0b

parent

894a3330e701ec43a09b96721b19c237dc9bd329

A animations.go

@@ -0,0 +1,169 @@

+package main + +import ( + "crypto/md5" + "encoding/base64" + "encoding/json" + "net/http" + "sophuwu.site/myweb/template" + "strings" + "time" +) + +type AnimInfo struct { + ID string `storm:"id"` + Title string + Date string `storm:"index"` + Desc string + Imgs []string + Vids []string +} + +func (a *AnimInfo) HasReqFields() bool { + return a.Title != "" && a.Desc != "" && (len(a.Imgs)+len(a.Vids) > 0) && a.Date != "" && a.ID != "" +} + +func GenAnimID(a AnimInfo) AnimInfo { + md := md5.New() + md.Write([]byte(time.Now().String() + a.Title)) + a.ID = base64.URLEncoding.EncodeToString(md.Sum(nil)) + if a.Date == "" { + a.Date = time.Now().Format("2006-01-02") + } + return a +} + +func GetAnim(id string) (AnimInfo, error) { + var a AnimInfo + err := DB.One("ID", id, &a) + return a, err +} + +func AnimSaveJson(js string) error { + var a AnimInfo + err := json.Unmarshal([]byte(js), &a) + if err != nil { + return err + } + return DB.Save(&a) +} + +func AnimDelete(id string) error { + return DB.DeleteStruct(&AnimInfo{ID: id}) +} + +func GetAnims() ([]AnimInfo, error) { + var anims []AnimInfo + err := DB.All(&anims) + if err != nil { + return nil, err + } + for i := 0; i < len(anims); i++ { + for j := i + 1; j < len(anims); j++ { + if anims[i].Date < anims[j].Date { + anims[i], anims[j] = anims[j], anims[i] + } + } + } + return anims, nil +} + +func AnimHandler(w http.ResponseWriter, r *http.Request) { + anims, err := GetAnims() + CheckHttpErr(err, w, r, 500) + var d template.HTMLDataMap + err = DB.Get("pages", "anims", &d) + if CheckHttpErr(err, w, r, 500) { + return + } + d.Set("Anims", anims) + d.Set("NoAnims", len(anims)) + err = template.Use(w, r, "anims", d) + CheckHttpErr(err, w, r, 500) +} + +func AnimManageList(w http.ResponseWriter, r *http.Request) { + anims, err := GetAnims() + if CheckHttpErr(err, w, r, 500) { + return + } + opts := make([]UrlOpt, len(anims)+1) + opts[0] = UrlOpt{Name: "Add new animation", URL: "/manage/animation/?id=new"} + for i, a := range anims { + opts[i+1] = UrlOpt{Name: a.Title, URL: "/manage/animation/?id=" + a.ID} + } + d := template.Data("Manage animations", "List of animations") + d.Set("Options", opts) + err = template.Use(w, r, "manage", d) + CheckHttpErr(err, w, r, 500) + return +} + +func AnimManager(w http.ResponseWriter, r *http.Request) { + if "/manage/animation/" != r.URL.Path { + HttpErr(w, r, 404) + return + } + if r.Method == "GET" { + id := r.URL.Query().Get("id") + if id == "" { + AnimManageList(w, r) + return + } + var a AnimInfo + var err error + if id == "new" { + a.ID = "new" + } else { + a, err = GetAnim(id) + } + if CheckHttpErr(err, w, r, 404) { + return + } + data := template.Data("Edit animation", id) + data.Set("AnimUrl", "/manage/animation/") + data.Set("Anim", a) + err = template.Use(w, r, "edit", data) + CheckHttpErr(err, w, r, 500) + return + } + if r.Method == "POST" { + err := r.ParseForm() + if CheckHttpErr(err, w, r, 500) { + return + } + g := func(s string) string { + s = r.Form.Get(s) + return strings.TrimSpace(s) + } + gg := func(s string) []string { + var ss []string + for _, s = range strings.Split(g(s), "\n") { + s = strings.TrimSpace(s) + if s != "" { + ss = append(ss, s) + } + } + return ss + } + var a AnimInfo + a.ID = g("id") + a.Title = g("title") + a.Date = g("date") + a.Desc = g("desc") + a.Imgs = gg("imgs") + a.Vids = gg("vids") + if a.ID == "new" { + a = GenAnimID(a) + } + if !a.HasReqFields() { + HttpErr(w, r, 400) + return + } + err = DB.Save(&a) + if CheckHttpErr(err, w, r, 400) { + return + } + } + http.Redirect(w, r, "/animations/", http.StatusFound) +}
M blogs.goblogs.go

@@ -61,7 +61,13 @@ err = DB.One("ID", id, &meta)

return } -func SortBlogsDate(blogs []BlogMeta) []BlogMeta { +func GetBlogs() ([]BlogMeta, error) { + var blogs []BlogMeta + // err := DB.All(&blogs) + err := DB.AllByIndex("Date", &blogs) + if err != nil { + return nil, err + } for i := 0; i < len(blogs); i++ { for j := i + 1; j < len(blogs); j++ { if blogs[i].Date < blogs[j].Date {

@@ -69,17 +75,6 @@ blogs[i], blogs[j] = blogs[j], blogs[i]

} } } - return blogs -} - -func GetBlogs() ([]BlogMeta, error) { - var blogs []BlogMeta - // err := DB.All(&blogs) - err := DB.AllByIndex("Date", &blogs) - if err != nil { - return nil, err - } - blogs = SortBlogsDate(blogs) return blogs, err }

@@ -90,7 +85,11 @@ blogs, err := GetBlogs()

if CheckHttpErr(err, w, r, 500) { return } - d := template.Data("Sophie's Blogs", "I sometimes write blogs about random things that I find interesting. Here you can read all my posts about various things I found interesting at some point.") + var d template.HTMLDataMap + err = DB.Get("pages", "blogs", &d) + if CheckHttpErr(err, w, r, 500) { + return + } d["blogs"] = []BlogMeta(blogs) d.Set("NoBlogs", len(blogs))

@@ -108,3 +107,100 @@ data.SetHTML(content.Content)

err = template.Use(w, r, "blog", data) CheckHttpErr(err, w, r, 500) } + +func BlogManageList(w http.ResponseWriter, r *http.Request) { + blogs, err := GetBlogs() + if CheckHttpErr(err, w, r, 500) { + return + } + opts := make([]UrlOpt, len(blogs)+1) + opts[0] = UrlOpt{Name: "Add new blog", URL: "/manage/blog/?id=new"} + for i, b := range blogs { + opts[i+1] = UrlOpt{Name: b.Title, URL: "/manage/blog/?id=" + b.ID} + } + d := template.Data("Manage blogs", "List of blogs") + d.Set("Options", opts) + err = template.Use(w, r, "manage", d) + CheckHttpErr(err, w, r, 500) + return +} + +func BlogManager(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/manage/blog/" { + HttpErr(w, r, 404) + return + } + if r.Method == "GET" { + id := r.URL.Query().Get("id") + if id == "" { + BlogManageList(w, r) + return + } + if id == "new" { + var data = template.Data("New blog", "Create a new blog") + data.Set("BlogUrl", "/manage/blog/") + data.Set("BlogID", "new") + data.Set("BlogDesc", "") + data.Set("BlogContent", "") + err := template.Use(w, r, "edit", data) + CheckHttpErr(err, w, r, 500) + return + } + meta, content, err := GetBlog(id) + if CheckHttpErr(err, w, r, 404) { + return + } + data := template.Data("Edit blog "+meta.Title, "Make changes to the content or description") + data.Set("BlogUrl", "/manage/blog/") + data.Set("BlogID", meta.ID) + data.Set("BlogDesc", meta.Desc) + data.Set("BlogContent", content.Content) + err = template.Use(w, r, "edit", data) + CheckHttpErr(err, w, r, 500) + return + } + if r.Method == "POST" { + err := r.ParseForm() + if CheckHttpErr(err, w, r, 500) { + return + } + id := r.Form.Get("id") + title := r.Form.Get("title") + desc := r.Form.Get("desc") + body := r.Form.Get("content") + date := r.Form.Get("date") + if id == "" || desc == "" || body == "" || (id == "new" && title == "") { + HttpErr(w, r, 400) + return + } + if date == "" { + date = time.Now().Format("2006-01-02") + } + if id == "new" { + err = SaveBlog(title, desc, body, date) + CheckHttpErr(err, w, r, 500) + http.Redirect(w, r, "/manage/blog/", 302) + return + } + meta, content, err := GetBlog(id) + if CheckHttpErr(err, w, r, 500) { + return + } + if meta.Desc != desc { + meta.Desc = desc + err = DB.Update(&meta) + if CheckHttpErr(err, w, r, 500) { + return + } + } + if content.Content != body { + content.Content = body + err = DB.Update(&content) + if CheckHttpErr(err, w, r, 500) { + return + } + } + http.Redirect(w, r, "/manage/blog/", 302) + return + } +}
M db.godb.go

@@ -79,15 +79,17 @@ }

HttpErr(w, r, 405) } +type UrlOpt struct{ Name, URL string } + func ManagerHandler(w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/manage/" { data := template.Data("Manage", config.URL) - data["Options"] = []struct{ Name, URL string }{ + data["Options"] = []UrlOpt{ {"Edit index", "/manage/edit/"}, {"Upload media", "/manage/media/"}, {"Delete media", "/manage/delete/media/"}, - {"Post blog", "/manage/blog/"}, - {"Add Animation", "/manage/animation/"}, + {"Manage blogs", "/manage/blog/"}, + {"Manage Animations", "/manage/animation/"}, {"Backup", "/manage/backup/"}, } err := template.Use(w, r, "manage", data)

@@ -104,6 +106,14 @@ return

} if strings.HasPrefix(r.URL.Path, "/manage/delete/media/") { DeleteMedia(w, r) + return + } + if r.URL.Path == "/manage/animation/" { + AnimManager(w, r) + return + } + if r.URL.Path == "/manage/blog/" { + BlogManager(w, r) return } HttpErr(w, r, 404)
M main.gomain.go

@@ -98,6 +98,7 @@ http.HandleFunc("/", HttpIndex)

http.HandleFunc("/blog/", BlogHandler) HttpFS("/static/", config.StaticPath) http.HandleFunc("/media/", MediaHandler) + http.HandleFunc("/animations/", AnimHandler) http.Handle("/manage/", Authenticate(ManagerHandler)) server := http.Server{Addr: config.ListenAddr, Handler: nil}
M webhome/static/style_main.csswebhome/static/style_main.css

@@ -216,4 +216,27 @@ margin: 0.25em 0;

} article { margin: 1lh 0; -}+} +.animation { + max-height: 20rem; + max-width: 95%; + border-radius: 15px; + padding: 5px; +} +.anim-row { + margin: 0; + padding: 0; +} +.anim-media { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + flex-wrap: wrap; + margin: 0; + padding: 0; +} +h3 { + margin: 0.5lh 0 0.25lh; + font-size: 1.25rem; +}
A webhome/templates/anims.html

@@ -0,0 +1,35 @@

+{{ define "anims" }} +<html lang="en"> +{{ template "head" . }} +<body> +{{ template "nav" . }} +<main> + <h2>Animations</h2> + <p> + {{ .Description }} + </p> + <p> + Showing {{ .NoAnims }} animations. + </p> + <hr> + + {{- range .Anims -}} + <section class="anim-row" id="{{ .ID }}"> + <h3>{{ .Title }}</h3> + <span class="date">{{ .Date }}</span> + <p>{{ .Desc }}</p> + <div class="anim-media"> + {{ range .Vids }} + <video src="/media/{{ . }}" class="animation" loading="lazy" autoplay="" loop="" muted=""></video> + {{ end }} + {{ range .Imgs }} + <img src="/media/{{ . }}" class="animation" loading="lazy"> + {{ end }} + </div> + </section> + <hr> + {{ end }} +</main> +</body> +</html> +{{ end }}
M webhome/templates/edit.htmlwebhome/templates/edit.html

@@ -15,11 +15,83 @@ <input type="file" name="file1" id="file1">

<input type="submit"> </form> {{ else }} + {{ if .AnimUrl }} + <form action="{{ .AnimUrl }}" method="post" style="width: 100%;"> + <table> + <tr> + <td>ID:</td> + <td><input type="text" name="id" value="{{ .Anim.ID }}" readonly></td> + </tr> + <tr> + <td>Title:</td> + <td><input type="text" name="title" value="{{ .Anim.Title }}"></td> + </tr> + <tr> + <td>Date:</td> + <td><input type="text" name="date" value="{{ .Anim.Date }}"></td> + </tr> + <tr> + <td>Description:</td> + <td><textarea name="desc" rows="5" cols="50">{{ .Anim.Desc }}</textarea></td> + </tr> + <tr> + <td>Video:</td> + <td><textarea name="vids" rows="5" cols="50">{{ range .Anim.Vids }}{{ . }}{{ end }}</textarea></td> + </tr> + <tr> + <td>Image:</td> + <td><textarea name="imgs" rows="5" cols="50">{{ range .Anim.Imgs }}{{ . }}{{ end }}</textarea></td> + </tr> + <tr> + <td></td> + <td><input type="submit" value="Save"></td> + </tr> + </table> + </form> + {{ else }} + {{ if .BlogUrl }} + <div class="splits"> + <form action="{{ .BlogUrl }}" method="post" style="width: 100%;"> + <table> + <tr> + <td>ID:</td> + <td><input type="text" name="id" value="{{ .BlogID }}" readonly></td> + </tr> + {{ if eq .BlogID "new" }} + <tr> + <td>Title:</td> + <td><input type="text" name="title" ></td> + </tr> + <tr> + <td>Date:</td> + <td><input type="text" name="date" ></td> + </tr> + {{ end }} + <tr> + <td>Description:</td> + <td><textarea name="desc" rows="5" cols="50">{{ .BlogDesc }}</textarea></td> + </tr> + <tr> + <td>Content:</td> + <td><textarea name="content" id="blog-text" rows="30" cols="100">{{ .BlogContent }}</textarea></td> + </tr> + <tr> + <td> + </td> + <td><input type="submit" value="Save"></td> + </tr> + </table> + </form> + <article id="blog-view"></article> + </div> + {{ else }} <form action="/manage/edit/save" method="post" style="width: 100%;"> <textarea name="data" rows="30" cols="100" style="width: 100%;">{{ .Data }}</textarea> <br> <input type="submit" value="Save"> </form> + {{ end }} + {{ end }} {{ end }} </main> </body>
M webhome/templates/filelist.htmlwebhome/templates/filelist.html

@@ -20,6 +20,7 @@ <td>{{- .Size -}}</td>

</tr> {{ end }} </table> + </main> </body> </html>