package bouquins import ( "database/sql" "encoding/json" "html/template" "log" "net/http" "strconv" "strings" ) const ( TPL_BOOKS = "book.html" TPL_AUTHORS = "author.html" TPL_SERIES = "series.html" TPL_INDEX = "index.html" PARAM_LIST = "list" PARAM_ORDER = "order" PARAM_SORT = "sort" LIST_AUTHORS = "authors" LIST_SERIES = "series" LIST_BOOKS = "books" URL_INDEX = "/" URL_BOOKS = "/books/" URL_AUTHORS = "/authors/" URL_SERIES = "/series/" URL_JS = "/js/" URL_CSS = "/css/" URL_FONTS = "/fonts/" ) type Bouquins struct { *template.Template *sql.DB } /* * A book series. */ type Series struct { Id int64 `json:"id,omitempty"` Name string `json:"name,omitempty"` } /* * A book. Generic data. */ type Book struct { Id int64 `json:"id,omitempty"` Title string `json:"title,omitempty"` SeriesIndex float64 `json:"series_idx,omitempty"` Series *Series `json:"series,omitempty"` } /* * An author. */ type Author struct { Id int64 `json:"id,omitempty"` Name string `json:"name,omitempty"` } /* * Author and number of books. */ type AuthorAdv struct { Author Count int `json:"count,omitempty"` } /* * Downloadable book data. */ type BookData struct { Size int64 `json:"size,omitempty"` Format string `json:"format,omitempty"` Name string `json:"name,omitempty"` } /* * A book. Advanced data: authors, tags. */ type BookAdv struct { Book Authors []*Author `json:"authors,omitempty"` Tags []string `json:"tags,omitempty"` } type AuthorFull struct { Author Books []*BookAdv `json:"books,omitempty"` } type BookFull struct { BookAdv Data []*BookData `json:"data,omitempty"` Timestamp int64 `json:"timestamp,omitempty"` Pubdate int64 `json:"pubdate,omitempty"` Isbn string `json:"isbn,omitempty"` Lccn string `json:"lccn,omitempty"` Path string `json:"path,omitempty"` Uuid string `json:"uuid,omitempty"` Has_cover bool `json:"has_cover,omitempty"` Lang string `json:"lang,omitempty"` Publisher string `json:"publisher,omitempty"` } type SeriesAdv struct { Series Count int64 `json:"count,omitempty"` Authors []*Author `json:"authors,omitempty"` } type SeriesFull struct { SeriesAdv Books []*Book `json:"books,omitempty"` } type BouquinsModel struct { Title string `json:"title,omitempty"` } // Constructor BouquinsModel func NewBouquinsModel(title string) *BouquinsModel { return &BouquinsModel{ title, } } type IndexModel struct { BouquinsModel BooksCount int64 `json:"count"` Books []*BookAdv `json:"books,omitempty"` Series []*SeriesAdv `json:"series,omitempty"` Authors []*AuthorAdv `json:"authors,omitempty"` } // Constructor IndexModel func NewIndexModel(title string, count int64) *IndexModel { return &IndexModel{ *NewBouquinsModel(title), count, nil, nil, nil, } } type BookModel struct { BouquinsModel *BookFull } func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) { err := app.Template.ExecuteTemplate(res, tpl, model) if err != nil { log.Print(err) } } // ROUTES // func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) { count, err := app.BookCount() if err != nil { log.Print(err) } model := NewIndexModel("", count) order, sort := req.URL.Query().Get(PARAM_ORDER), req.URL.Query().Get(PARAM_SORT) switch req.URL.Query().Get(PARAM_LIST) { case LIST_AUTHORS: model.Authors, err = app.AuthorsAdv(0, 0, sort, order) case LIST_SERIES: model.Series, err = app.SeriesAdv(0, 0, sort, order) case LIST_BOOKS: fallthrough default: model.Books, err = app.BooksAdv(0, 0, sort, order) } if err != nil { log.Print(err) } if req.Header.Get("Accept") == "application/json" { res.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(res) err := enc.Encode(model) if err != nil { log.Println(err) http.Error(res, err.Error(), 500) } } else { app.render(res, TPL_INDEX, model) } } func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) { if !strings.HasPrefix(req.URL.Path, URL_BOOKS) { // FIXME 404 log.Fatalln("Invalid URL") } id, err := strconv.Atoi(req.URL.Path[len(URL_BOOKS):]) if err != nil { // FIXME 404 log.Fatalln(err) } book, err := app.BookFull(int64(id)) if err != nil { // FIXME 500 log.Fatalln(err) } model := &BookModel{ *NewBouquinsModel(book.Title), book, } app.render(res, TPL_BOOKS, model) } func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) { app.render(res, TPL_AUTHORS, nil) } func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) { app.render(res, TPL_SERIES, nil) }