package main import ( "crypto/md5" "encoding/base64" "net/http" "sophuwu.site/myweb/template" "strings" "time" ) // AnimInfo is a struct that holds information about an animation. type AnimInfo struct { ID string `storm:"id"` Title string Date string `storm:"index"` Desc string Imgs []string Vids []string } // HasReqFields checks if all required fields have a non-empty value. func (a *AnimInfo) HasReqFields() bool { return a.Title != "" && a.Desc != "" && (len(a.Imgs)+len(a.Vids) > 0) && a.Date != "" && a.ID != "" } // GenAnimID generates an ID for an animation. It will generate a different ID // each time it is called, even if the input is the same. This allows for // multiple animations with the same title to be stored without conflict. 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 } // GetAnim retrieves AnimInfo from the database with the given ID. // If the ID is not found, an error is returned. func GetAnim(id string) (AnimInfo, error) { var a AnimInfo err := DB.One("ID", id, &a) return a, err } // AnimDelete deletes an animation from the database with the given ID. func AnimDelete(id string) error { return DB.DeleteStruct(&AnimInfo{ID: id}) } // GetAnims retrieves all animations from the database. The animations are // sorted by date, with the most recent first in []AnimInfo. 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 } // AnimHandler is a http.HandlerFunc that serves the animations page. // It retrieves all animations from the database and displays them. func AnimHandler(w http.ResponseWriter, r *http.Request) { anims, err := GetAnims() CheckHttpErr(err, w, r, 500) d, err := GetPageData("anims") 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) } // AnimManageList is a http.HandlerFunc that serves the animation manager list. // It retrieves all animations from the database and displays them as a list. // With each animation, there is a link to edit the details of that animation. 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 } // AnimManager is a http.HandlerFunc that serves the animation manager. It // allows the user to edit an existing animation or create a new one. // If the ID is "new", a new animation is created. Otherwise, the animation // with the given ID is retrieved from the database and displayed for editing. 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) }