package trantor import ( html_tmpl "html/template" txt_tmpl "text/template" log "github.com/cihub/seelog" "encoding/json" "errors" "fmt" "io" "net/http" "net/url" "path" "strings" "time" "gitlab.com/trantor/trantor/lib/database" ) var tmpl_funcs = map[string]interface{}{ "strings_join": stringsJoin, "download_url": downloadUrl, "size2mb": size2mb, "mul": mul, } type Status struct { BaseURL string FullURL string IsOnion bool Title string Search string User string Role string Notif []Notification Updated string Home bool About bool News bool Upload bool Stats bool Help bool Dasboard bool } func GetStatus(h handler) Status { var s Status host := h.r.Host s.BaseURL = "https://" + host if strings.HasSuffix(host, ".onion") || strings.Contains(host, "localhost") { s.BaseURL = "http://" + host } s.FullURL = s.BaseURL + h.r.RequestURI s.IsOnion = strings.HasSuffix(host, ".onion") s.Title = "Imperial Library of Trantor" s.User = h.sess.User s.Role = h.sess.Role s.Notif = h.sess.GetNotif() s.Updated = time.Now().UTC().Format("2006-01-02T15:04:05Z") h.sess.Save(h.w, h.r) return s } type TemplateExecutor interface { ExecuteTemplate(io.Writer, string, interface{}) error } type Template struct { html TemplateExecutor opds TemplateExecutor } func InitTemplate(assetsPath string) *Template { var err error var t Template templatePath := path.Join(assetsPath, "templates") t.html, err = html_tmpl.New("html").Funcs(tmpl_funcs).ParseGlob(path.Join(templatePath, "*.html")) if err != nil { log.Critical("Error loading html templates: ", err) } t.opds, err = txt_tmpl.New("opds").Funcs(tmpl_funcs).ParseGlob(path.Join(templatePath, "*.opds")) if err != nil { log.Critical("Error loading opds templates: ", err) } return &t } func stringsJoin(strs []string, sep string) string { return strings.Join(strs, sep) } func bookFileName(book database.Book) string { var authorsStr string switch len(book.Authors) { case 0: authorsStr = "" case 1: authorsStr = book.Authors[0] + " - " default: authorsStr = book.Authors[0] + ", ... - " } return url.PathEscape(fmt.Sprintf("%s%s.epub", authorsStr, book.Title)) } func downloadUrl(book database.Book) string { return fmt.Sprintf("/download/%s/%s", book.ID, bookFileName(book)) } func size2mb(size int) float32 { return float32(size) / (1024.0 * 1024.0) } func mul(a, b int) int { return a * b } type DevTemplateExecutor struct { assetsPath string tpe string } func InitDevTemplate(assetsPath string) *Template { return &Template{ html: DevTemplateExecutor{assetsPath, "html"}, opds: DevTemplateExecutor{assetsPath, "txt"}, } } func (e DevTemplateExecutor) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { templatePath := path.Join(e.assetsPath, "templates") file := path.Join(templatePath, name) var t TemplateExecutor switch e.tpe { case "html": included_files := []string{file} for _, f := range []string{"header.html", "footer.html", "book_list.html"} { included_files = append(included_files, path.Join(templatePath, f)) } t = html_tmpl.Must(html_tmpl.New("html").Funcs(tmpl_funcs).ParseFiles(included_files...)) case "txt": t = txt_tmpl.Must(txt_tmpl.New("txt").Funcs(tmpl_funcs).ParseFiles(file)) } return t.ExecuteTemplate(wr, name, data) } func loadJson(w http.ResponseWriter, tmpl string, data interface{}) error { var res []byte var err error switch tmpl { case "index": res, err = indexJson(data) case "book": res, err = bookJson(data) case "news": res, err = newsJson(data) case "search": res, err = searchJson(data) case "list": res, err = listJson(data) } if err != nil { return err } _, err = w.Write(res) return err } func indexJson(data interface{}) ([]byte, error) { index, ok := data.(indexData) if !ok { return nil, errors.New("Data is not valid") } books := make([]map[string]interface{}, len(index.Books)) for i, book := range index.Books { books[i] = bookJsonRaw(book) } news := newsJsonRaw(index.News) return json.Marshal(map[string]interface{}{ "title": index.S.Title, "url": index.S.BaseURL, "count": index.Count, "news": news, "tags": index.Tags, "last_added": books, }) } func bookJson(data interface{}) ([]byte, error) { book, ok := data.(bookData) if !ok { return nil, errors.New("Data is not valid") } return json.Marshal(bookJsonRaw(book.Book)) } func newsJson(data interface{}) ([]byte, error) { news, ok := data.(newsData) if !ok { return nil, errors.New("Data is not valid") } return json.Marshal(newsJsonRaw(news.News)) } func newsJsonRaw(news []newsEntry) []map[string]string { list := make([]map[string]string, len(news)) for i, n := range news { list[i] = map[string]string{ "date": n.Date, "text": n.Text, } } return list } func searchJson(data interface{}) ([]byte, error) { search, ok := data.(searchData) if !ok { return nil, errors.New("Data is not valid") } books := make([]map[string]interface{}, len(search.Books)) for i, book := range search.Books { books[i] = bookJsonRaw(book) } return json.Marshal(map[string]interface{}{ "found": search.Found, "page": search.Page - 1, "items": search.ItemsPage, "books": books, }) } func listJson(data interface{}) ([]byte, error) { list, ok := data.(listData) if !ok { return nil, errors.New("Data is not valid") } books := make([]map[string]interface{}, len(list.List.Books)) for i, book := range list.List.Books { books[i] = bookJsonRaw(book) } return json.Marshal(map[string]interface{}{ "ID": list.List.ListID, "title": list.List.Title, "description": list.List.Description, "user ": list.List.User.Username, "books": books, }) } func bookJsonRaw(book database.Book) map[string]interface{} { cover := "" coverSmall := "" if book.Cover { cover = "/cover/" + book.ID + "/big/" + book.Title + ".jpg" coverSmall = "/cover/" + book.ID + "/small/" + book.Title + ".jpg" } return map[string]interface{}{ "id": book.ID, "title": book.Title, "authors": book.Authors, "contributor": book.Contributor, "publisher": book.Publisher, "description": book.Description, "tags": book.Tags, "date": book.Date, "lang": book.Lang, "isbn": book.Isbn, "size": book.FileSize, "sha256": book.FileHash, "cover": cover, "cover_small": coverSmall, "download": "/download/" + book.ID + "/" + book.Title + ".epub", "read": "/read/" + book.ID, } }