2016-05-02 21:36:49 -04:00
|
|
|
package trantor
|
2012-08-15 11:51:25 +02:00
|
|
|
|
2014-08-30 03:56:36 -05:00
|
|
|
import (
|
2016-05-03 01:03:23 -04:00
|
|
|
html_tmpl "html/template"
|
2014-08-30 03:56:36 -05:00
|
|
|
txt_tmpl "text/template"
|
2013-08-31 00:38:32 +02:00
|
|
|
|
2018-04-09 09:47:44 +00:00
|
|
|
log "github.com/cihub/seelog"
|
|
|
|
|
2014-08-30 03:56:36 -05:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2020-12-10 12:44:36 +00:00
|
|
|
"fmt"
|
2020-12-03 12:58:37 +00:00
|
|
|
"io"
|
2014-08-30 03:56:36 -05:00
|
|
|
"net/http"
|
2020-12-10 12:44:36 +00:00
|
|
|
"net/url"
|
2016-05-03 01:03:23 -04:00
|
|
|
"path"
|
2018-04-09 19:14:11 +00:00
|
|
|
"strings"
|
2015-01-17 02:19:14 -06:00
|
|
|
"time"
|
2014-08-30 13:17:50 -05:00
|
|
|
|
2016-05-02 21:36:49 -04:00
|
|
|
"gitlab.com/trantor/trantor/lib/database"
|
2014-08-30 03:56:36 -05:00
|
|
|
)
|
2014-08-30 01:25:16 -05:00
|
|
|
|
2020-12-10 12:44:36 +00:00
|
|
|
var tmpl_funcs = map[string]interface{}{
|
|
|
|
"strings_join": stringsJoin,
|
|
|
|
"download_url": downloadUrl,
|
2021-02-09 17:32:13 +00:00
|
|
|
"size2mb": size2mb,
|
2017-06-08 00:44:35 +00:00
|
|
|
"mul": mul,
|
2020-12-10 12:44:36 +00:00
|
|
|
}
|
|
|
|
|
2012-08-18 02:06:43 +02:00
|
|
|
type Status struct {
|
2014-02-19 11:59:16 +01:00
|
|
|
BaseURL string
|
|
|
|
FullURL string
|
2020-03-23 19:13:58 +00:00
|
|
|
IsOnion bool
|
2016-01-28 18:13:26 -05:00
|
|
|
Title string
|
2014-02-19 11:59:16 +01:00
|
|
|
Search string
|
|
|
|
User string
|
2016-10-16 20:05:45 -04:00
|
|
|
Role string
|
2014-02-19 11:59:16 +01:00
|
|
|
Notif []Notification
|
2015-01-17 02:19:14 -06:00
|
|
|
Updated string
|
2014-02-19 11:59:16 +01:00
|
|
|
Home bool
|
|
|
|
About bool
|
|
|
|
News bool
|
|
|
|
Upload bool
|
|
|
|
Stats bool
|
|
|
|
Help bool
|
|
|
|
Dasboard bool
|
2012-08-18 02:06:43 +02:00
|
|
|
}
|
|
|
|
|
2013-09-23 16:27:31 +02:00
|
|
|
func GetStatus(h handler) Status {
|
2012-08-19 02:29:34 +02:00
|
|
|
var s Status
|
2020-02-20 23:52:51 +00:00
|
|
|
host := h.r.Host
|
|
|
|
s.BaseURL = "https://" + host
|
|
|
|
if strings.HasSuffix(host, ".onion") || strings.Contains(host, "localhost") {
|
|
|
|
s.BaseURL = "http://" + host
|
|
|
|
}
|
2013-09-23 16:27:31 +02:00
|
|
|
s.FullURL = s.BaseURL + h.r.RequestURI
|
2020-03-23 19:13:58 +00:00
|
|
|
s.IsOnion = strings.HasSuffix(host, ".onion")
|
2016-01-28 18:13:26 -05:00
|
|
|
s.Title = "Imperial Library of Trantor"
|
2013-09-23 16:27:31 +02:00
|
|
|
s.User = h.sess.User
|
2016-10-16 20:05:45 -04:00
|
|
|
s.Role = h.sess.Role
|
2013-09-23 16:27:31 +02:00
|
|
|
s.Notif = h.sess.GetNotif()
|
2015-01-17 02:19:14 -06:00
|
|
|
s.Updated = time.Now().UTC().Format("2006-01-02T15:04:05Z")
|
2013-09-23 16:27:31 +02:00
|
|
|
h.sess.Save(h.w, h.r)
|
2012-08-19 02:29:34 +02:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2020-12-03 12:58:37 +00:00
|
|
|
type TemplateExecutor interface {
|
|
|
|
ExecuteTemplate(io.Writer, string, interface{}) error
|
|
|
|
}
|
|
|
|
|
2016-05-03 01:03:23 -04:00
|
|
|
type Template struct {
|
2020-12-03 12:58:37 +00:00
|
|
|
html TemplateExecutor
|
|
|
|
opds TemplateExecutor
|
2016-05-03 01:03:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func InitTemplate(assetsPath string) *Template {
|
2018-04-09 09:47:44 +00:00
|
|
|
var err error
|
2016-05-03 01:03:23 -04:00
|
|
|
var t Template
|
|
|
|
templatePath := path.Join(assetsPath, "templates")
|
|
|
|
|
2020-12-10 12:44:36 +00:00
|
|
|
t.html, err = html_tmpl.New("html").Funcs(tmpl_funcs).ParseGlob(path.Join(templatePath, "*.html"))
|
2018-04-09 09:47:44 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Critical("Error loading html templates: ", err)
|
|
|
|
}
|
|
|
|
|
2020-12-10 12:44:36 +00:00
|
|
|
t.opds, err = txt_tmpl.New("opds").Funcs(tmpl_funcs).ParseGlob(path.Join(templatePath, "*.opds"))
|
2018-04-09 09:47:44 +00:00
|
|
|
if err != nil {
|
|
|
|
log.Critical("Error loading opds templates: ", err)
|
|
|
|
}
|
2016-05-03 01:03:23 -04:00
|
|
|
|
|
|
|
return &t
|
|
|
|
}
|
|
|
|
|
2021-05-01 11:36:07 +00:00
|
|
|
func stringsJoin(strs []string, sep string) string {
|
|
|
|
return strings.Join(strs, sep)
|
2020-12-10 12:44:36 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 17:50:51 +00:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2020-12-10 12:44:36 +00:00
|
|
|
func downloadUrl(book database.Book) string {
|
2021-02-09 17:50:51 +00:00
|
|
|
return fmt.Sprintf("/download/%s/%s", book.ID, bookFileName(book))
|
2020-12-10 12:44:36 +00:00
|
|
|
}
|
|
|
|
|
2021-02-09 17:32:13 +00:00
|
|
|
func size2mb(size int) float32 {
|
|
|
|
return float32(size) / (1024.0 * 1024.0)
|
|
|
|
}
|
|
|
|
|
2017-06-08 00:44:35 +00:00
|
|
|
func mul(a, b int) int {
|
|
|
|
return a * b
|
|
|
|
}
|
|
|
|
|
2020-12-03 12:58:37 +00:00
|
|
|
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))
|
|
|
|
}
|
2020-12-10 12:44:36 +00:00
|
|
|
t = html_tmpl.Must(html_tmpl.New("html").Funcs(tmpl_funcs).ParseFiles(included_files...))
|
2020-12-03 12:58:37 +00:00
|
|
|
case "txt":
|
2020-12-10 12:44:36 +00:00
|
|
|
t = txt_tmpl.Must(txt_tmpl.New("txt").Funcs(tmpl_funcs).ParseFiles(file))
|
2020-12-03 12:58:37 +00:00
|
|
|
}
|
|
|
|
return t.ExecuteTemplate(wr, name, data)
|
|
|
|
}
|
|
|
|
|
2014-08-30 03:56:36 -05:00
|
|
|
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)
|
2018-04-09 09:47:44 +00:00
|
|
|
case "list":
|
|
|
|
res, err = listJson(data)
|
2014-08-30 03:56:36 -05:00
|
|
|
}
|
|
|
|
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{}{
|
2016-01-28 18:13:26 -05:00
|
|
|
"title": index.S.Title,
|
2014-08-30 03:56:36 -05:00
|
|
|
"url": index.S.BaseURL,
|
|
|
|
"count": index.Count,
|
|
|
|
"news": news,
|
|
|
|
"tags": index.Tags,
|
2014-08-30 15:02:51 -05:00
|
|
|
"last_added": books,
|
2014-08-30 03:56:36 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2014-08-30 18:22:48 -05:00
|
|
|
return json.Marshal(map[string]interface{}{
|
|
|
|
"found": search.Found,
|
|
|
|
"page": search.Page - 1,
|
|
|
|
"items": search.ItemsPage,
|
|
|
|
"books": books,
|
|
|
|
})
|
2014-08-30 03:56:36 -05:00
|
|
|
}
|
|
|
|
|
2018-04-09 09:47:44 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-08-30 03:56:36 -05:00
|
|
|
func bookJsonRaw(book database.Book) map[string]interface{} {
|
|
|
|
cover := ""
|
|
|
|
coverSmall := ""
|
|
|
|
if book.Cover {
|
2016-07-30 07:59:30 -04:00
|
|
|
cover = "/cover/" + book.ID + "/big/" + book.Title + ".jpg"
|
|
|
|
coverSmall = "/cover/" + book.ID + "/small/" + book.Title + ".jpg"
|
2014-08-30 03:56:36 -05:00
|
|
|
}
|
|
|
|
return map[string]interface{}{
|
2016-07-30 07:59:30 -04:00
|
|
|
"id": book.ID,
|
2014-08-30 03:56:36 -05:00
|
|
|
"title": book.Title,
|
2016-07-30 07:36:58 -04:00
|
|
|
"authors": book.Authors,
|
2014-08-30 03:56:36 -05:00
|
|
|
"contributor": book.Contributor,
|
|
|
|
"publisher": book.Publisher,
|
|
|
|
"description": book.Description,
|
2016-07-30 07:36:58 -04:00
|
|
|
"tags": book.Tags,
|
2014-08-30 03:56:36 -05:00
|
|
|
"date": book.Date,
|
|
|
|
"lang": book.Lang,
|
|
|
|
"isbn": book.Isbn,
|
|
|
|
"size": book.FileSize,
|
2020-06-24 11:07:04 +00:00
|
|
|
"sha256": book.FileHash,
|
2014-08-30 03:56:36 -05:00
|
|
|
"cover": cover,
|
|
|
|
"cover_small": coverSmall,
|
2016-07-30 07:59:30 -04:00
|
|
|
"download": "/download/" + book.ID + "/" + book.Title + ".epub",
|
|
|
|
"read": "/read/" + book.ID,
|
2014-08-30 03:56:36 -05:00
|
|
|
}
|
|
|
|
}
|