Code style (go vet, go lint)
This commit is contained in:
parent
0362051918
commit
2943d217a7
@ -16,93 +16,89 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TPL_BOOKS = "book.html"
|
tplBooks = "book.html"
|
||||||
TPL_AUTHORS = "author.html"
|
tplAuthors = "author.html"
|
||||||
TPL_SERIES = "series.html"
|
tplSeries = "series.html"
|
||||||
TPL_INDEX = "index.html"
|
tplIndex = "index.html"
|
||||||
TPL_SEARCH = "search.html"
|
tplSearch = "search.html"
|
||||||
TPL_ABOUT = "about.html"
|
tplAbout = "about.html"
|
||||||
|
|
||||||
PARAM_LIST = "list"
|
pList = "list"
|
||||||
PARAM_ORDER = "order"
|
pOrder = "order"
|
||||||
PARAM_SORT = "sort"
|
pSort = "sort"
|
||||||
PARAM_PAGE = "page"
|
pPage = "page"
|
||||||
PARAM_PERPAGE = "perpage"
|
pPerPage = "perpage"
|
||||||
PARAM_TERM = "term"
|
pTerm = "term"
|
||||||
|
|
||||||
LIST_AUTHORS = "authors"
|
// URLIndex url of index page
|
||||||
LIST_SERIES = "series"
|
URLIndex = "/"
|
||||||
LIST_BOOKS = "books"
|
// URLBooks url of books page
|
||||||
|
URLBooks = "/books/"
|
||||||
URL_INDEX = "/"
|
// URLAuthors url of authors page
|
||||||
URL_BOOKS = "/books/"
|
URLAuthors = "/authors/"
|
||||||
URL_AUTHORS = "/authors/"
|
// URLSeries url of series page
|
||||||
URL_SERIES = "/series/"
|
URLSeries = "/series/"
|
||||||
URL_SEARCH = "/search/"
|
// URLSearch url of search page
|
||||||
URL_ABOUT = "/about/"
|
URLSearch = "/search/"
|
||||||
URL_JS = "/js/"
|
// URLAbout url of about page
|
||||||
URL_CSS = "/css/"
|
URLAbout = "/about/"
|
||||||
URL_FONTS = "/fonts/"
|
// URLJs url of js assets
|
||||||
URL_CALIBRE = "/calibre/"
|
URLJs = "/js/"
|
||||||
|
// URLCss url of css assets
|
||||||
|
URLCss = "/css/"
|
||||||
|
// URLFonts url of fonts assets
|
||||||
|
URLFonts = "/fonts/"
|
||||||
|
// URLCalibre url of calibre resources (covers, ebooks files)
|
||||||
|
URLCalibre = "/calibre/"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Bouquins contains application common resources: templates, database
|
||||||
type Bouquins struct {
|
type Bouquins struct {
|
||||||
*template.Template
|
Tpl *template.Template
|
||||||
*sql.DB
|
DB *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Series is a book series.
|
||||||
* A book series.
|
|
||||||
*/
|
|
||||||
type Series struct {
|
type Series struct {
|
||||||
Id int64 `json:"id,omitempty"`
|
ID int64 `json:"id,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Book contains basic data on book
|
||||||
* A book. Generic data.
|
|
||||||
*/
|
|
||||||
type Book struct {
|
type Book struct {
|
||||||
Id int64 `json:"id,omitempty"`
|
ID int64 `json:"id,omitempty"`
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
SeriesIndex float64 `json:"series_idx,omitempty"`
|
SeriesIndex float64 `json:"series_idx,omitempty"`
|
||||||
Series *Series `json:"series,omitempty"`
|
Series *Series `json:"series,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Author contains basic data on author
|
||||||
* An author.
|
|
||||||
*/
|
|
||||||
type Author struct {
|
type Author struct {
|
||||||
Id int64 `json:"id,omitempty"`
|
ID int64 `json:"id,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// AuthorAdv extends Author with number of books
|
||||||
* Author and number of books.
|
|
||||||
*/
|
|
||||||
type AuthorAdv struct {
|
type AuthorAdv struct {
|
||||||
Author
|
Author
|
||||||
Count int `json:"count,omitempty"`
|
Count int `json:"count,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// BookData contains data for dowloadable book
|
||||||
* Downloadable book data.
|
|
||||||
*/
|
|
||||||
type BookData struct {
|
type BookData struct {
|
||||||
Size int64 `json:"size,omitempty"`
|
Size int64 `json:"size,omitempty"`
|
||||||
Format string `json:"format,omitempty"`
|
Format string `json:"format,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// BookAdv extends Book with authors and tags
|
||||||
* A book. Advanced data: authors, tags.
|
|
||||||
*/
|
|
||||||
type BookAdv struct {
|
type BookAdv struct {
|
||||||
Book
|
Book
|
||||||
Authors []*Author `json:"authors,omitempty"`
|
Authors []*Author `json:"authors,omitempty"`
|
||||||
Tags []string `json:"tags,omitempty"`
|
Tags []string `json:"tags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorFull extends Author with books, series and co-authors
|
||||||
type AuthorFull struct {
|
type AuthorFull struct {
|
||||||
Author
|
Author
|
||||||
Books []*Book `json:"books,omitempty"`
|
Books []*Book `json:"books,omitempty"`
|
||||||
@ -110,6 +106,7 @@ type AuthorFull struct {
|
|||||||
CoAuthors []*Author `json:"coauthors,omitempty"`
|
CoAuthors []*Author `json:"coauthors,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BookFull extends BookAdv with all available data
|
||||||
type BookFull struct {
|
type BookFull struct {
|
||||||
BookAdv
|
BookAdv
|
||||||
Data []*BookData `json:"data,omitempty"`
|
Data []*BookData `json:"data,omitempty"`
|
||||||
@ -118,98 +115,111 @@ type BookFull struct {
|
|||||||
Isbn string `json:"isbn,omitempty"`
|
Isbn string `json:"isbn,omitempty"`
|
||||||
Lccn string `json:"lccn,omitempty"`
|
Lccn string `json:"lccn,omitempty"`
|
||||||
Path string `json:"path,omitempty"`
|
Path string `json:"path,omitempty"`
|
||||||
Uuid string `json:"uuid,omitempty"`
|
UUID string `json:"uuid,omitempty"`
|
||||||
Has_cover bool `json:"has_cover,omitempty"`
|
HasCover bool `json:"has_cover,omitempty"`
|
||||||
Lang string `json:"lang,omitempty"`
|
Lang string `json:"lang,omitempty"`
|
||||||
Publisher string `json:"publisher,omitempty"`
|
Publisher string `json:"publisher,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeriesAdv extends Series with count of books and authors
|
||||||
type SeriesAdv struct {
|
type SeriesAdv struct {
|
||||||
Series
|
Series
|
||||||
Count int64 `json:"count,omitempty"`
|
Count int64 `json:"count,omitempty"`
|
||||||
Authors []*Author `json:"authors,omitempty"`
|
Authors []*Author `json:"authors,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeriesFull extends SeriesAdv with related books
|
||||||
type SeriesFull struct {
|
type SeriesFull struct {
|
||||||
SeriesAdv
|
SeriesAdv
|
||||||
Books []*Book `json:"books,omitempty"`
|
Books []*Book `json:"books,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BouquinsModel struct {
|
// Model is basic page model
|
||||||
|
type Model struct {
|
||||||
Title string
|
Title string
|
||||||
Page string
|
Page string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor BouquinsModel
|
// NewModel constuctor for Model
|
||||||
func NewBouquinsModel(title, page string) *BouquinsModel {
|
func NewModel(title, page string) *Model {
|
||||||
return &BouquinsModel{title, page}
|
return &Model{title, page}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexModel is the model for index page
|
||||||
type IndexModel struct {
|
type IndexModel struct {
|
||||||
BouquinsModel
|
Model
|
||||||
BooksCount int64 `json:"count"`
|
BooksCount int64 `json:"count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructor IndexModel
|
// NewIndexModel constructor IndexModel
|
||||||
func NewIndexModel(title string, count int64) *IndexModel {
|
func NewIndexModel(title string, count int64) *IndexModel {
|
||||||
return &IndexModel{*NewBouquinsModel(title, "index"), count}
|
return &IndexModel{*NewModel(title, "index"), count}
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchModel struct {
|
// NewSearchModel constuctor for search page
|
||||||
BouquinsModel
|
func NewSearchModel() *Model {
|
||||||
}
|
return NewModel("Recherche", "search")
|
||||||
|
|
||||||
func NewSearchModel() *SearchModel {
|
|
||||||
return &SearchModel{*NewBouquinsModel("Recherche", "search")}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResultsModel is a generic model for list pages
|
||||||
type ResultsModel struct {
|
type ResultsModel struct {
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
More bool `json:"more"`
|
More bool `json:"more"`
|
||||||
CountResults int `json:"count,omitempty"`
|
CountResults int `json:"count,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BooksResultsModel is the model for list of books
|
||||||
type BooksResultsModel struct {
|
type BooksResultsModel struct {
|
||||||
ResultsModel
|
ResultsModel
|
||||||
Results []*BookAdv `json:"results,omitempty"`
|
Results []*BookAdv `json:"results,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewBooksResultsModel constuctor for BooksResultsModel
|
||||||
func NewBooksResultsModel(books []*BookAdv, more bool, count int) *BooksResultsModel {
|
func NewBooksResultsModel(books []*BookAdv, more bool, count int) *BooksResultsModel {
|
||||||
return &BooksResultsModel{ResultsModel{"books", more, count}, books}
|
return &BooksResultsModel{ResultsModel{"books", more, count}, books}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorsResultsModel is the model for list of authors
|
||||||
type AuthorsResultsModel struct {
|
type AuthorsResultsModel struct {
|
||||||
ResultsModel
|
ResultsModel
|
||||||
Results []*AuthorAdv `json:"results,omitempty"`
|
Results []*AuthorAdv `json:"results,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewAuthorsResultsModel constuctor for AuthorsResultsModel
|
||||||
func NewAuthorsResultsModel(authors []*AuthorAdv, more bool, count int) *AuthorsResultsModel {
|
func NewAuthorsResultsModel(authors []*AuthorAdv, more bool, count int) *AuthorsResultsModel {
|
||||||
return &AuthorsResultsModel{ResultsModel{"authors", more, count}, authors}
|
return &AuthorsResultsModel{ResultsModel{"authors", more, count}, authors}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeriesResultsModel is the model for list of series
|
||||||
type SeriesResultsModel struct {
|
type SeriesResultsModel struct {
|
||||||
ResultsModel
|
ResultsModel
|
||||||
Results []*SeriesAdv `json:"results,omitempty"`
|
Results []*SeriesAdv `json:"results,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewSeriesResultsModel constuctor for SeriesResultsModel
|
||||||
func NewSeriesResultsModel(series []*SeriesAdv, more bool, count int) *SeriesResultsModel {
|
func NewSeriesResultsModel(series []*SeriesAdv, more bool, count int) *SeriesResultsModel {
|
||||||
return &SeriesResultsModel{ResultsModel{"series", more, count}, series}
|
return &SeriesResultsModel{ResultsModel{"series", more, count}, series}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BookModel is the model for single book page
|
||||||
type BookModel struct {
|
type BookModel struct {
|
||||||
BouquinsModel
|
Model
|
||||||
*BookFull
|
*BookFull
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeriesModel is the model for single series page
|
||||||
type SeriesModel struct {
|
type SeriesModel struct {
|
||||||
BouquinsModel
|
Model
|
||||||
*SeriesFull
|
*SeriesFull
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorModel is the model for single author page
|
||||||
type AuthorModel struct {
|
type AuthorModel struct {
|
||||||
BouquinsModel
|
Model
|
||||||
*AuthorFull
|
*AuthorFull
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReqParams contains request parameters for searches and lists
|
||||||
type ReqParams struct {
|
type ReqParams struct {
|
||||||
Limit int
|
Limit int
|
||||||
Offset int
|
Offset int
|
||||||
@ -219,7 +229,7 @@ type ReqParams struct {
|
|||||||
AllWords bool
|
AllWords bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// add functions to templates
|
// TemplatesFunc adds functions to templates
|
||||||
func TemplatesFunc() *template.Template {
|
func TemplatesFunc() *template.Template {
|
||||||
return template.New("").Funcs(template.FuncMap{
|
return template.New("").Funcs(template.FuncMap{
|
||||||
"humanSize": func(sz int64) string {
|
"humanSize": func(sz int64) string {
|
||||||
@ -237,18 +247,18 @@ func TemplatesFunc() *template.Template {
|
|||||||
|
|
||||||
// output page with template
|
// output page with template
|
||||||
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) error {
|
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) error {
|
||||||
return app.Template.ExecuteTemplate(res, tpl, model)
|
return app.Tpl.ExecuteTemplate(res, tpl, model)
|
||||||
}
|
}
|
||||||
|
|
||||||
// output as JSON
|
// output as JSON
|
||||||
func writeJson(res http.ResponseWriter, model interface{}) error {
|
func writeJSON(res http.ResponseWriter, model interface{}) error {
|
||||||
res.Header().Set("Content-Type", "application/json")
|
res.Header().Set("Content-Type", "application/json")
|
||||||
enc := json.NewEncoder(res)
|
enc := json.NewEncoder(res)
|
||||||
return enc.Encode(model)
|
return enc.Encode(model)
|
||||||
}
|
}
|
||||||
|
|
||||||
// test if JSON requested
|
// test if JSON requested
|
||||||
func isJson(req *http.Request) bool {
|
func isJSON(req *http.Request) bool {
|
||||||
return req.Header.Get("Accept") == "application/json"
|
return req.Header.Get("Accept") == "application/json"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +278,7 @@ func paramInt(name string, req *http.Request) int {
|
|||||||
|
|
||||||
// get order parameter
|
// get order parameter
|
||||||
func paramOrder(req *http.Request) string {
|
func paramOrder(req *http.Request) string {
|
||||||
val := req.URL.Query().Get(PARAM_ORDER)
|
val := req.URL.Query().Get(pOrder)
|
||||||
if val == "desc" || val == "asc" {
|
if val == "desc" || val == "asc" {
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
@ -277,23 +287,23 @@ func paramOrder(req *http.Request) string {
|
|||||||
|
|
||||||
// get common request parameters
|
// get common request parameters
|
||||||
func params(req *http.Request) *ReqParams {
|
func params(req *http.Request) *ReqParams {
|
||||||
page, perpage := paramInt(PARAM_PAGE, req), paramInt(PARAM_PERPAGE, req)
|
page, perpage := paramInt(pPage, req), paramInt(pPerPage, req)
|
||||||
limit := perpage
|
limit := perpage
|
||||||
if perpage == 0 {
|
if perpage == 0 {
|
||||||
limit = DEF_LIM
|
limit = defaultLimit
|
||||||
}
|
}
|
||||||
offset := perpage * (page - 1)
|
offset := perpage * (page - 1)
|
||||||
if offset < 0 {
|
if offset < 0 {
|
||||||
offset = 0
|
offset = 0
|
||||||
}
|
}
|
||||||
sort := req.URL.Query().Get(PARAM_SORT)
|
sort := req.URL.Query().Get(pSort)
|
||||||
order := paramOrder(req)
|
order := paramOrder(req)
|
||||||
terms := req.URL.Query()[PARAM_TERM]
|
terms := req.URL.Query()[pTerm]
|
||||||
return &ReqParams{limit, offset, sort, order, terms, false}
|
return &ReqParams{limit, offset, sort, order, terms, false}
|
||||||
}
|
}
|
||||||
|
|
||||||
// single element or list elements page
|
// single element or list elements page
|
||||||
func listOrId(res http.ResponseWriter, req *http.Request, url string,
|
func listOrID(res http.ResponseWriter, req *http.Request, url string,
|
||||||
listFunc func(res http.ResponseWriter, req *http.Request) error,
|
listFunc func(res http.ResponseWriter, req *http.Request) error,
|
||||||
idFunc func(idParam string, res http.ResponseWriter, req *http.Request) error) error {
|
idFunc func(idParam string, res http.ResponseWriter, req *http.Request) error) error {
|
||||||
if !strings.HasPrefix(req.URL.Path, url) {
|
if !strings.HasPrefix(req.URL.Path, url) {
|
||||||
@ -308,40 +318,40 @@ func listOrId(res http.ResponseWriter, req *http.Request, url string,
|
|||||||
|
|
||||||
// LIST ELEMENTS PAGES //
|
// LIST ELEMENTS PAGES //
|
||||||
|
|
||||||
func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) booksListPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
if isJson(req) {
|
if isJSON(req) {
|
||||||
books, count, more, err := app.BooksAdv(params(req))
|
books, count, more, err := app.BooksAdv(params(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return writeJson(res, NewBooksResultsModel(books, more, count))
|
return writeJSON(res, NewBooksResultsModel(books, more, count))
|
||||||
}
|
}
|
||||||
return errors.New("Invalid mime")
|
return errors.New("Invalid mime")
|
||||||
}
|
}
|
||||||
func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) authorsListPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
if isJson(req) {
|
if isJSON(req) {
|
||||||
authors, count, more, err := app.AuthorsAdv(params(req))
|
authors, count, more, err := app.AuthorsAdv(params(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return writeJson(res, NewAuthorsResultsModel(authors, more, count))
|
return writeJSON(res, NewAuthorsResultsModel(authors, more, count))
|
||||||
}
|
}
|
||||||
return errors.New("Invalid mime")
|
return errors.New("Invalid mime")
|
||||||
}
|
}
|
||||||
func (app *Bouquins) SeriesListPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) seriesListPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
if isJson(req) {
|
if isJSON(req) {
|
||||||
series, count, more, err := app.SeriesAdv(params(req))
|
series, count, more, err := app.SeriesAdv(params(req))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return writeJson(res, NewSeriesResultsModel(series, more, count))
|
return writeJSON(res, NewSeriesResultsModel(series, more, count))
|
||||||
}
|
}
|
||||||
return errors.New("Invalid mime")
|
return errors.New("Invalid mime")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SINGLE ELEMENT PAGES //
|
// SINGLE ELEMENT PAGES //
|
||||||
|
|
||||||
func (app *Bouquins) BookPage(idParam string, res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) bookPage(idParam string, res http.ResponseWriter, req *http.Request) error {
|
||||||
id, err := strconv.Atoi(idParam)
|
id, err := strconv.Atoi(idParam)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -350,9 +360,9 @@ func (app *Bouquins) BookPage(idParam string, res http.ResponseWriter, req *http
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return app.render(res, TPL_BOOKS, &BookModel{*NewBouquinsModel(book.Title, "book"), book})
|
return app.render(res, tplBooks, &BookModel{*NewModel(book.Title, "book"), book})
|
||||||
}
|
}
|
||||||
func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) authorPage(idParam string, res http.ResponseWriter, req *http.Request) error {
|
||||||
id, err := strconv.Atoi(idParam)
|
id, err := strconv.Atoi(idParam)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -361,9 +371,9 @@ func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *ht
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return app.render(res, TPL_AUTHORS, &AuthorModel{*NewBouquinsModel(author.Name, "author"), author})
|
return app.render(res, tplAuthors, &AuthorModel{*NewModel(author.Name, "author"), author})
|
||||||
}
|
}
|
||||||
func (app *Bouquins) SeriePage(idParam string, res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) seriePage(idParam string, res http.ResponseWriter, req *http.Request) error {
|
||||||
id, err := strconv.Atoi(idParam)
|
id, err := strconv.Atoi(idParam)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -372,34 +382,45 @@ func (app *Bouquins) SeriePage(idParam string, res http.ResponseWriter, req *htt
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return app.render(res, TPL_SERIES, &SeriesModel{*NewBouquinsModel(series.Name, "series"), series})
|
return app.render(res, tplSeries, &SeriesModel{*NewModel(series.Name, "series"), series})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ROUTES //
|
// ROUTES //
|
||||||
|
|
||||||
|
// BooksPage displays a single books or a returns a list of books
|
||||||
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
return listOrId(res, req, URL_BOOKS, app.BooksListPage, app.BookPage)
|
return listOrID(res, req, URLBooks, app.booksListPage, app.bookPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorsPage displays a single author or returns a list of authors
|
||||||
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
return listOrId(res, req, URL_AUTHORS, app.AuthorsListPage, app.AuthorPage)
|
return listOrID(res, req, URLAuthors, app.authorsListPage, app.authorPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeriesPage displays a single series or returns a list of series
|
||||||
func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
return listOrId(res, req, URL_SERIES, app.SeriesListPage, app.SeriePage)
|
return listOrID(res, req, URLSeries, app.seriesListPage, app.seriePage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchPage displays search form and results
|
||||||
func (app *Bouquins) SearchPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) SearchPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
return app.render(res, TPL_SEARCH, NewSearchModel())
|
return app.render(res, tplSearch, NewSearchModel())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AboutPage displays about page
|
||||||
func (app *Bouquins) AboutPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) AboutPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
return app.render(res, TPL_ABOUT, NewBouquinsModel("A propos", "about"))
|
return app.render(res, tplAbout, NewModel("A propos", "about"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexPage displays index page: list of books/authors/series
|
||||||
func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) error {
|
func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) error {
|
||||||
count, err := app.BookCount()
|
count, err := app.BookCount()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
model := NewIndexModel("", count)
|
model := NewIndexModel("", count)
|
||||||
if isJson(req) {
|
if isJSON(req) {
|
||||||
return writeJson(res, model)
|
return writeJSON(res, model)
|
||||||
}
|
}
|
||||||
return app.render(res, TPL_INDEX, model)
|
return app.render(res, tplIndex, model)
|
||||||
}
|
}
|
||||||
|
236
bouquins/db.go
236
bouquins/db.go
@ -2,48 +2,47 @@ package bouquins
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
STMT_BOOKS0 = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
|
sqlBooks0 = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
|
||||||
FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
|
FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
|
||||||
LEFT OUTER JOIN series ON series.id = books_series_link.series `
|
LEFT OUTER JOIN series ON series.id = books_series_link.series `
|
||||||
STMT_BOOKS_TAGS0 = `SELECT name, books_tags_link.book as book FROM tags, books_tags_link
|
sqlBooksTags0 = `SELECT name, books_tags_link.book as book FROM tags, books_tags_link
|
||||||
WHERE tags.id = books_tags_link.tag AND books_tags_link.book IN ( SELECT id FROM books `
|
WHERE tags.id = books_tags_link.tag AND books_tags_link.book IN ( SELECT id FROM books `
|
||||||
STMT_BOOKS_AUTHORS0 = `SELECT authors.id, authors.name, books_authors_link.book as book
|
sqlBooksAuthors0 = `SELECT authors.id, authors.name, books_authors_link.book as book
|
||||||
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
|
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
|
||||||
AND books_authors_link.book IN ( SELECT id FROM books `
|
AND books_authors_link.book IN ( SELECT id FROM books `
|
||||||
STMT_SEARCH_TERM_BOOKS = " books.sort like ? "
|
sqlBooksTerm = " books.sort like ? "
|
||||||
|
|
||||||
STMT_SERIES0 = `SELECT series.id, series.name, count(book) FROM series
|
sqlSeries0 = `SELECT series.id, series.name, count(book) FROM series
|
||||||
LEFT OUTER JOIN books_series_link ON books_series_link.series = series.id
|
LEFT OUTER JOIN books_series_link ON books_series_link.series = series.id
|
||||||
GROUP BY series.id `
|
GROUP BY series.id `
|
||||||
STMT_SERIES_AUTHORS0 = `SELECT DISTINCT authors.id, authors.name, books_series_link.series
|
sqlSeriesAuthors0 = `SELECT DISTINCT authors.id, authors.name, books_series_link.series
|
||||||
FROM authors, books_authors_link, books_series_link
|
FROM authors, books_authors_link, books_series_link
|
||||||
WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id
|
WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id
|
||||||
AND books_series_link.series IN ( SELECT id FROM series `
|
AND books_series_link.series IN ( SELECT id FROM series `
|
||||||
STMT_SERIES_SEARCH = "SELECT series.id, series.name FROM series WHERE "
|
sqlSeriesSearch = "SELECT series.id, series.name FROM series WHERE "
|
||||||
STMT_SEARCH_TERM_SERIES = " series.sort like ? "
|
sqlSeriesTerm = " series.sort like ? "
|
||||||
|
|
||||||
STMT_AUTHORS0 = `SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link
|
sqlAuthors0 = `SELECT authors.id, authors.name, count(book) as count FROM authors, books_authors_link
|
||||||
WHERE authors.id = books_authors_link.author GROUP BY author `
|
WHERE authors.id = books_authors_link.author GROUP BY author `
|
||||||
STMT_AUTHORS_SEARCH = "SELECT id, name FROM authors WHERE "
|
sqlAuthorsSearch = "SELECT id, name FROM authors WHERE "
|
||||||
STMT_SEARCH_TERM_AUTHOR = " sort like ? "
|
sqlAuthorsTerm = " sort like ? "
|
||||||
|
|
||||||
STMT_PAGE = " LIMIT ? OFFSET ?"
|
sqlPage = " LIMIT ? OFFSET ?"
|
||||||
STMT_WHERE = " WHERE "
|
sqlWhere = " WHERE "
|
||||||
STMT_BOOL_AND = " AND "
|
sqlAnd = " AND "
|
||||||
STMT_BOOL_OR = " OR "
|
sqlOr = " OR "
|
||||||
|
|
||||||
STMT_SEARCH_ORDER_BOOKS = " ORDER BY books.sort"
|
sqlBooksOrder = " ORDER BY books.sort"
|
||||||
STMT_SEARCH_ORDER_AUTHORS = " ORDER BY authors.sort"
|
sqlAuthorsOrder = " ORDER BY authors.sort"
|
||||||
STMT_SEARCH_ORDER_SERIES = " ORDER BY series.sort"
|
sqlSeriesOrder = " ORDER BY series.sort"
|
||||||
|
|
||||||
STMT_BOOKS_COUNT = "SELECT count(id) FROM books"
|
sqlBooksCount = "SELECT count(id) FROM books"
|
||||||
STMT_BOOK = `SELECT books.id AS id,title, series_index, series.name AS series_name, series.id AS series_id,
|
sqlBook = `SELECT books.id AS id,title, series_index, series.name AS series_name, series.id AS series_id,
|
||||||
strftime('%s', timestamp), strftime('%Y', pubdate), isbn,lccn,path,uuid,has_cover,
|
strftime('%s', timestamp), strftime('%Y', pubdate), isbn,lccn,path,uuid,has_cover,
|
||||||
languages.lang_code, publishers.name AS pubname FROM books
|
languages.lang_code, publishers.name AS pubname FROM books
|
||||||
LEFT OUTER JOIN books_languages_link ON books_languages_link.book = books.id
|
LEFT OUTER JOIN books_languages_link ON books_languages_link.book = books.id
|
||||||
@ -54,118 +53,121 @@ const (
|
|||||||
LEFT OUTER JOIN books_publishers_link ON books.id = books_publishers_link.book
|
LEFT OUTER JOIN books_publishers_link ON books.id = books_publishers_link.book
|
||||||
LEFT OUTER JOIN publishers ON publishers.id = books_publishers_link.publisher
|
LEFT OUTER JOIN publishers ON publishers.id = books_publishers_link.publisher
|
||||||
WHERE books.id = ?`
|
WHERE books.id = ?`
|
||||||
STMT_BOOK_TAGS = "SELECT name FROM tags, books_tags_link WHERE tags.id = books_tags_link.tag AND books_tags_link.book = ?"
|
sqlBookTags = "SELECT name FROM tags, books_tags_link WHERE tags.id = books_tags_link.tag AND books_tags_link.book = ?"
|
||||||
STMT_BOOK_AUTHORS = `SELECT authors.id, authors.name, books_authors_link.book as book
|
sqlBookAuthors = `SELECT authors.id, authors.name, books_authors_link.book as book
|
||||||
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
|
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
|
||||||
AND books_authors_link.book = ?`
|
AND books_authors_link.book = ?`
|
||||||
STMT_BOOK_DATA = "SELECT data.name, data.format, data.uncompressed_size FROM data WHERE data.book = ?"
|
sqlBookData = "SELECT data.name, data.format, data.uncompressed_size FROM data WHERE data.book = ?"
|
||||||
STMT_BOOKS_ID_ASC = STMT_BOOKS0 + " ORDER BY id" + STMT_PAGE
|
sqlBooksIDAsc = sqlBooks0 + " ORDER BY id" + sqlPage
|
||||||
STMT_BOOKS_ID_DESC = STMT_BOOKS0 + "ORDER BY id DESC" + STMT_PAGE
|
sqlBooksIDDesc = sqlBooks0 + "ORDER BY id DESC" + sqlPage
|
||||||
STMT_BOOKS_TITLE_ASC = STMT_BOOKS0 + "ORDER BY books.sort" + STMT_PAGE
|
sqlBooksTitleAsc = sqlBooks0 + "ORDER BY books.sort" + sqlPage
|
||||||
STMT_BOOKS_TITLE_DESC = STMT_BOOKS0 + "ORDER BY books.sort DESC" + STMT_PAGE
|
sqlBooksTitleDesc = sqlBooks0 + "ORDER BY books.sort DESC" + sqlPage
|
||||||
STMT_BOOKS_TAGS_ID_ASC = STMT_BOOKS_TAGS0 + "ORDER BY id" + STMT_PAGE + ")"
|
sqlBooksTagsIDAsc = sqlBooksTags0 + "ORDER BY id" + sqlPage + ")"
|
||||||
STMT_BOOKS_TAGS_ID_DESC = STMT_BOOKS_TAGS0 + "ORDER BY id DESC" + STMT_PAGE + ")"
|
sqlBooksTagsIDDesc = sqlBooksTags0 + "ORDER BY id DESC" + sqlPage + ")"
|
||||||
STMT_BOOKS_TAGS_TITLE_ASC = STMT_BOOKS_TAGS0 + "ORDER BY books.sort" + STMT_PAGE + ")"
|
sqlBooksTagsTitleAsc = sqlBooksTags0 + "ORDER BY books.sort" + sqlPage + ")"
|
||||||
STMT_BOOKS_TAGS_TITLE_DESC = STMT_BOOKS_TAGS0 + "ORDER BY books.sort DESC" + STMT_PAGE + ")"
|
sqlBooksTagsTitleDesc = sqlBooksTags0 + "ORDER BY books.sort DESC" + sqlPage + ")"
|
||||||
STMT_BOOKS_AUTHORS_ID_ASC = STMT_BOOKS_AUTHORS0 + "ORDER BY id" + STMT_PAGE + ")"
|
sqlBooksAuthorsIDAsc = sqlBooksAuthors0 + "ORDER BY id" + sqlPage + ")"
|
||||||
STMT_BOOKS_AUTHORS_ID_DESC = STMT_BOOKS_AUTHORS0 + "ORDER BY id DESC" + STMT_PAGE + ")"
|
sqlBooksAuthorsIDDesc = sqlBooksAuthors0 + "ORDER BY id DESC" + sqlPage + ")"
|
||||||
STMT_BOOKS_AUTHORS_TITLE_ASC = STMT_BOOKS_AUTHORS0 + "ORDER BY books.sort" + STMT_PAGE + ")"
|
sqlBooksAuthorsTitleAsc = sqlBooksAuthors0 + "ORDER BY books.sort" + sqlPage + ")"
|
||||||
STMT_BOOKS_AUTHORS_TITLE_DESC = STMT_BOOKS_AUTHORS0 + "ORDER BY books.sort DESC" + STMT_PAGE + ")"
|
sqlBooksAuthorsTitleDesc = sqlBooksAuthors0 + "ORDER BY books.sort DESC" + sqlPage + ")"
|
||||||
|
|
||||||
STMT_SERIES_ID_ASC = STMT_SERIES0 + " ORDER BY series.id" + STMT_PAGE
|
sqlSeriesIDAsc = sqlSeries0 + " ORDER BY series.id" + sqlPage
|
||||||
STMT_SERIES_ID_DESC = STMT_SERIES0 + " ORDER BY series.id DESC" + STMT_PAGE
|
sqlSeriesIDDesc = sqlSeries0 + " ORDER BY series.id DESC" + sqlPage
|
||||||
STMT_SERIES_NAME_ASC = STMT_SERIES0 + " ORDER BY series.sort" + STMT_PAGE
|
sqlSeriesNameAsc = sqlSeries0 + " ORDER BY series.sort" + sqlPage
|
||||||
STMT_SERIES_NAME_DESC = STMT_SERIES0 + " ORDER BY series.sort DESC" + STMT_PAGE
|
sqlSeriesNameDesc = sqlSeries0 + " ORDER BY series.sort DESC" + sqlPage
|
||||||
STMT_SERIES_AUTHORS_ID_ASC = STMT_SERIES_AUTHORS0 + " ORDER BY series.id" + STMT_PAGE + ")"
|
sqlSeriesAuthorsIDAsc = sqlSeriesAuthors0 + " ORDER BY series.id" + sqlPage + ")"
|
||||||
STMT_SERIES_AUTHORS_ID_DESC = STMT_SERIES_AUTHORS0 + " ORDER BY series.id DESC" + STMT_PAGE + ")"
|
sqlSeriesAuthorsIDDesc = sqlSeriesAuthors0 + " ORDER BY series.id DESC" + sqlPage + ")"
|
||||||
STMT_SERIES_AUTHORS_NAME_ASC = STMT_SERIES_AUTHORS0 + " ORDER BY series.sort" + STMT_PAGE + ")"
|
sqlSeriesAuthorsNameAsc = sqlSeriesAuthors0 + " ORDER BY series.sort" + sqlPage + ")"
|
||||||
STMT_SERIES_AUTHORS_NAME_DESC = STMT_SERIES_AUTHORS0 + " ORDER BY series.sort DESC" + STMT_PAGE + ")"
|
sqlSeriesAuthorsNameDesc = sqlSeriesAuthors0 + " ORDER BY series.sort DESC" + sqlPage + ")"
|
||||||
STMT_SERIE = "SELECT series.id, series.name FROM series WHERE series.id = ?"
|
sqlSerie = "SELECT series.id, series.name FROM series WHERE series.id = ?"
|
||||||
STMT_SERIE_BOOKS = `SELECT books.id, title, series_index FROM books
|
sqlSerieBooks = `SELECT books.id, title, series_index FROM books
|
||||||
LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
|
LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
|
||||||
WHERE books_series_link.series = ? ORDER BY series_index ASC`
|
WHERE books_series_link.series = ? ORDER BY series_index ASC`
|
||||||
STMT_SERIE_AUTHORS = `SELECT DISTINCT authors.id, authors.name
|
sqlSerieAuthors = `SELECT DISTINCT authors.id, authors.name
|
||||||
FROM authors, books_authors_link, books_series_link
|
FROM authors, books_authors_link, books_series_link
|
||||||
WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id
|
WHERE books_authors_link.book = books_series_link.book AND books_authors_link.author = authors.id
|
||||||
AND books_series_link.series = ?`
|
AND books_series_link.series = ?`
|
||||||
|
|
||||||
STMT_AUTHORS_ID_ASC = STMT_AUTHORS0 + "ORDER BY authors.id " + STMT_PAGE
|
sqlAuthorsIDAsc = sqlAuthors0 + "ORDER BY authors.id " + sqlPage
|
||||||
STMT_AUTHORS_ID_DESC = STMT_AUTHORS0 + "ORDER BY authors.id DESC " + STMT_PAGE
|
sqlAuthorsIDDesc = sqlAuthors0 + "ORDER BY authors.id DESC " + sqlPage
|
||||||
STMT_AUTHORS_NAME_ASC = STMT_AUTHORS0 + "ORDER BY authors.sort " + STMT_PAGE
|
sqlAuthorsNameAsc = sqlAuthors0 + "ORDER BY authors.sort " + sqlPage
|
||||||
STMT_AUTHORS_NAME_DESC = STMT_AUTHORS0 + "ORDER BY authors.sort DESC " + STMT_PAGE
|
sqlAuthorsNameDesc = sqlAuthors0 + "ORDER BY authors.sort DESC " + sqlPage
|
||||||
STMT_AUTHOR_BOOKS = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
|
sqlAuthorBooks = `SELECT books.id AS id,title,series_index,name as series_name,series.id AS series_id
|
||||||
FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
|
FROM books LEFT OUTER JOIN books_series_link ON books.id = books_series_link.book
|
||||||
LEFT OUTER JOIN series ON series.id = books_series_link.series
|
LEFT OUTER JOIN series ON series.id = books_series_link.series
|
||||||
LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book
|
LEFT OUTER JOIN books_authors_link ON books.id = books_authors_link.book
|
||||||
WHERE books_authors_link.author = ? ORDER BY id`
|
WHERE books_authors_link.author = ? ORDER BY id`
|
||||||
STMT_AUTHOR_AUTHORS = `SELECT DISTINCT authors.id, authors.name
|
sqlAuthorAuthors = `SELECT DISTINCT authors.id, authors.name
|
||||||
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
|
FROM authors, books_authors_link WHERE books_authors_link.author = authors.id
|
||||||
AND books_authors_link.book IN ( SELECT books.id FROM books LEFT OUTER JOIN books_authors_link
|
AND books_authors_link.book IN ( SELECT books.id FROM books LEFT OUTER JOIN books_authors_link
|
||||||
ON books.id = books_authors_link.book WHERE books_authors_link.author = ? ORDER BY books.id)
|
ON books.id = books_authors_link.book WHERE books_authors_link.author = ? ORDER BY books.id)
|
||||||
AND authors.id != ? ORDER BY authors.id`
|
AND authors.id != ? ORDER BY authors.id`
|
||||||
STMT_AUTHOR = "SELECT name FROM authors WHERE id = ?"
|
sqlAuthor = "SELECT name FROM authors WHERE id = ?"
|
||||||
|
|
||||||
DEF_LIM = 10
|
defaultLimit = 10
|
||||||
|
|
||||||
BOOKS QueryType = iota
|
qtBook QueryType = iota
|
||||||
BOOKS_TAGS
|
qtBookTags
|
||||||
BOOKS_AUTHORS
|
qtBookData
|
||||||
BOOK
|
qtBookAuthors
|
||||||
BOOK_TAGS
|
qtBookCount
|
||||||
BOOK_DATA
|
qtBooks
|
||||||
BOOK_AUTHORS
|
qtBooksTags
|
||||||
BOOKS_COUNT
|
qtBooksAuthors
|
||||||
SERIE
|
qtSerie
|
||||||
SERIES
|
qtSerieAuthors
|
||||||
SERIES_AUTHORS
|
qtSerieBooks
|
||||||
SERIE_AUTHORS
|
qtSeries
|
||||||
SERIE_BOOKS
|
qtSeriesAuthors
|
||||||
AUTHORS
|
qtAuthor
|
||||||
AUTHOR
|
qtAuthorBooks
|
||||||
AUTHOR_BOOKS
|
qtAuthorCoauthors
|
||||||
AUTHOR_COAUTHORS
|
qtAuthors
|
||||||
)
|
)
|
||||||
|
|
||||||
var QUERIES = map[Query]string{
|
var queries = map[Query]string{
|
||||||
Query{BOOKS, true, true}: STMT_BOOKS_TITLE_DESC,
|
Query{qtBooks, true, true}: sqlBooksTitleDesc,
|
||||||
Query{BOOKS, true, false}: STMT_BOOKS_TITLE_ASC,
|
Query{qtBooks, true, false}: sqlBooksTitleAsc,
|
||||||
Query{BOOKS, false, true}: STMT_BOOKS_ID_DESC,
|
Query{qtBooks, false, true}: sqlBooksIDDesc,
|
||||||
Query{BOOKS, false, false}: STMT_BOOKS_ID_ASC,
|
Query{qtBooks, false, false}: sqlBooksIDAsc,
|
||||||
Query{BOOKS_TAGS, true, true}: STMT_BOOKS_TAGS_TITLE_DESC,
|
Query{qtBooksTags, true, true}: sqlBooksTagsTitleDesc,
|
||||||
Query{BOOKS_TAGS, true, false}: STMT_BOOKS_TAGS_TITLE_ASC,
|
Query{qtBooksTags, true, false}: sqlBooksTagsTitleAsc,
|
||||||
Query{BOOKS_TAGS, false, true}: STMT_BOOKS_TAGS_ID_DESC,
|
Query{qtBooksTags, false, true}: sqlBooksTagsIDDesc,
|
||||||
Query{BOOKS_TAGS, false, false}: STMT_BOOKS_TAGS_ID_ASC,
|
Query{qtBooksTags, false, false}: sqlBooksTagsIDAsc,
|
||||||
Query{BOOKS_AUTHORS, true, true}: STMT_BOOKS_AUTHORS_TITLE_DESC,
|
Query{qtBooksAuthors, true, true}: sqlBooksAuthorsTitleDesc,
|
||||||
Query{BOOKS_AUTHORS, true, false}: STMT_BOOKS_AUTHORS_TITLE_ASC,
|
Query{qtBooksAuthors, true, false}: sqlBooksAuthorsTitleAsc,
|
||||||
Query{BOOKS_AUTHORS, false, true}: STMT_BOOKS_AUTHORS_ID_DESC,
|
Query{qtBooksAuthors, false, true}: sqlBooksAuthorsIDDesc,
|
||||||
Query{BOOKS_AUTHORS, false, false}: STMT_BOOKS_AUTHORS_ID_ASC,
|
Query{qtBooksAuthors, false, false}: sqlBooksAuthorsIDAsc,
|
||||||
Query{BOOK, false, false}: STMT_BOOK,
|
Query{qtBook, false, false}: sqlBook,
|
||||||
Query{BOOK_TAGS, false, false}: STMT_BOOK_TAGS,
|
Query{qtBookTags, false, false}: sqlBookTags,
|
||||||
Query{BOOK_DATA, false, false}: STMT_BOOK_DATA,
|
Query{qtBookData, false, false}: sqlBookData,
|
||||||
Query{BOOK_AUTHORS, false, false}: STMT_BOOK_AUTHORS,
|
Query{qtBookAuthors, false, false}: sqlBookAuthors,
|
||||||
Query{BOOKS_COUNT, false, false}: STMT_BOOKS_COUNT,
|
Query{qtBookCount, false, false}: sqlBooksCount,
|
||||||
Query{SERIE, false, false}: STMT_SERIE,
|
Query{qtSerie, false, false}: sqlSerie,
|
||||||
Query{SERIES, true, true}: STMT_SERIES_NAME_DESC,
|
Query{qtSeries, true, true}: sqlSeriesNameDesc,
|
||||||
Query{SERIES, true, false}: STMT_SERIES_NAME_ASC,
|
Query{qtSeries, true, false}: sqlSeriesNameAsc,
|
||||||
Query{SERIES, false, true}: STMT_SERIES_ID_DESC,
|
Query{qtSeries, false, true}: sqlSeriesIDDesc,
|
||||||
Query{SERIES, false, false}: STMT_SERIES_ID_ASC,
|
Query{qtSeries, false, false}: sqlSeriesIDAsc,
|
||||||
Query{SERIES_AUTHORS, true, true}: STMT_SERIES_AUTHORS_NAME_DESC,
|
Query{qtSeriesAuthors, true, true}: sqlSeriesAuthorsNameDesc,
|
||||||
Query{SERIES_AUTHORS, true, false}: STMT_SERIES_AUTHORS_NAME_ASC,
|
Query{qtSeriesAuthors, true, false}: sqlSeriesAuthorsNameAsc,
|
||||||
Query{SERIES_AUTHORS, false, true}: STMT_SERIES_AUTHORS_ID_DESC,
|
Query{qtSeriesAuthors, false, true}: sqlSeriesAuthorsIDDesc,
|
||||||
Query{SERIES_AUTHORS, false, false}: STMT_SERIES_AUTHORS_ID_ASC,
|
Query{qtSeriesAuthors, false, false}: sqlSeriesAuthorsIDAsc,
|
||||||
Query{SERIE_AUTHORS, false, false}: STMT_SERIE_AUTHORS,
|
Query{qtSerieAuthors, false, false}: sqlSerieAuthors,
|
||||||
Query{SERIE_BOOKS, false, false}: STMT_SERIE_BOOKS,
|
Query{qtSerieBooks, false, false}: sqlSerieBooks,
|
||||||
Query{AUTHORS, true, true}: STMT_AUTHORS_NAME_DESC,
|
Query{qtAuthors, true, true}: sqlAuthorsNameDesc,
|
||||||
Query{AUTHORS, true, false}: STMT_AUTHORS_NAME_ASC,
|
Query{qtAuthors, true, false}: sqlAuthorsNameAsc,
|
||||||
Query{AUTHORS, false, true}: STMT_AUTHORS_ID_DESC,
|
Query{qtAuthors, false, true}: sqlAuthorsIDDesc,
|
||||||
Query{AUTHORS, false, false}: STMT_AUTHORS_ID_ASC,
|
Query{qtAuthors, false, false}: sqlAuthorsIDAsc,
|
||||||
Query{AUTHOR, false, false}: STMT_AUTHOR,
|
Query{qtAuthor, false, false}: sqlAuthor,
|
||||||
Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS,
|
Query{qtAuthorBooks, false, false}: sqlAuthorBooks,
|
||||||
Query{AUTHOR_COAUTHORS, false, false}: STMT_AUTHOR_AUTHORS,
|
Query{qtAuthorCoauthors, false, false}: sqlAuthorAuthors,
|
||||||
}
|
}
|
||||||
var STMTS = make(map[Query]*sql.Stmt)
|
var stmts = make(map[Query]*sql.Stmt)
|
||||||
|
|
||||||
|
// QueryType is a type of query, with variants for sort and order
|
||||||
type QueryType uint
|
type QueryType uint
|
||||||
|
|
||||||
|
// Query is a key for SQL queries catalog
|
||||||
type Query struct {
|
type Query struct {
|
||||||
Type QueryType
|
Type QueryType
|
||||||
SortField bool // sort by name or title
|
SortField bool // sort by name or title
|
||||||
@ -179,10 +181,10 @@ func (app *Bouquins) searchHelper(all bool, terms []string, stub, termExpr, orde
|
|||||||
queryTerms = append(queryTerms, "%"+term+"%")
|
queryTerms = append(queryTerms, "%"+term+"%")
|
||||||
query += termExpr
|
query += termExpr
|
||||||
if i < len(terms)-1 && all {
|
if i < len(terms)-1 && all {
|
||||||
query += STMT_BOOL_AND
|
query += sqlAnd
|
||||||
}
|
}
|
||||||
if i < len(terms)-1 && !all {
|
if i < len(terms)-1 && !all {
|
||||||
query += STMT_BOOL_OR
|
query += sqlOr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
query += orderExpr
|
query += orderExpr
|
||||||
@ -200,18 +202,20 @@ func (app *Bouquins) searchHelper(all bool, terms []string, stub, termExpr, orde
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PREPARED STATEMENTS //
|
// PREPARED STATEMENTS //
|
||||||
|
|
||||||
|
// PrepareAll prepares statement for (almost) all queries
|
||||||
func (app *Bouquins) PrepareAll() error {
|
func (app *Bouquins) PrepareAll() error {
|
||||||
errcount := 0
|
errcount := 0
|
||||||
for q, v := range QUERIES {
|
for q, v := range queries {
|
||||||
stmt, err := app.DB.Prepare(v)
|
stmt, err := app.DB.Prepare(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err, v)
|
log.Println(err, v)
|
||||||
errcount++
|
errcount++
|
||||||
}
|
}
|
||||||
STMTS[q] = stmt
|
stmts[q] = stmt
|
||||||
}
|
}
|
||||||
if errcount > 0 {
|
if errcount > 0 {
|
||||||
return errors.New(fmt.Sprintf("%d errors on queries, see logs", errcount))
|
return fmt.Errorf("%d errors on queries, see logs", errcount)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -228,9 +232,9 @@ func (app *Bouquins) psSortSeries(qt QueryType, sort, order string) (*sql.Stmt,
|
|||||||
}
|
}
|
||||||
func (app *Bouquins) psSort(sortNameField string, qt QueryType, sort, order string) (*sql.Stmt, error) {
|
func (app *Bouquins) psSort(sortNameField string, qt QueryType, sort, order string) (*sql.Stmt, error) {
|
||||||
q := Query{qt, sort == sortNameField, order == "desc"}
|
q := Query{qt, sort == sortNameField, order == "desc"}
|
||||||
query := QUERIES[q]
|
query := queries[q]
|
||||||
log.Println(query)
|
log.Println(query)
|
||||||
stmt := STMTS[q]
|
stmt := stmts[q]
|
||||||
if stmt == nil {
|
if stmt == nil {
|
||||||
log.Println("Missing statement for ", q)
|
log.Println("Missing statement for ", q)
|
||||||
var err error
|
var err error
|
||||||
|
@ -7,7 +7,7 @@ import (
|
|||||||
// SUB QUERIES //
|
// SUB QUERIES //
|
||||||
|
|
||||||
func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*AuthorAdv, int, error) {
|
func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*AuthorAdv, int, error) {
|
||||||
rows, err := app.searchHelper(all, terms, STMT_AUTHORS_SEARCH, STMT_SEARCH_TERM_AUTHOR, STMT_SEARCH_ORDER_AUTHORS)
|
rows, err := app.searchHelper(all, terms, sqlAuthorsSearch, sqlAuthorsTerm, sqlAuthorsOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -17,7 +17,7 @@ func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*Auth
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
if len(authors) <= limit {
|
if len(authors) <= limit {
|
||||||
author := new(AuthorAdv)
|
author := new(AuthorAdv)
|
||||||
if err := rows.Scan(&author.Id, &author.Name); err != nil {
|
if err := rows.Scan(&author.ID, &author.Name); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
authors = append(authors, author)
|
authors = append(authors, author)
|
||||||
@ -32,7 +32,7 @@ func (app *Bouquins) searchAuthors(limit int, terms []string, all bool) ([]*Auth
|
|||||||
|
|
||||||
func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*AuthorAdv, bool, error) {
|
func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*AuthorAdv, bool, error) {
|
||||||
authors := make([]*AuthorAdv, 0, limit)
|
authors := make([]*AuthorAdv, 0, limit)
|
||||||
stmt, err := app.psSortAuthors(AUTHORS, sort, order)
|
stmt, err := app.psSortAuthors(qtAuthors, sort, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@ -47,7 +47,7 @@ func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*Aut
|
|||||||
more = true
|
more = true
|
||||||
} else {
|
} else {
|
||||||
author := new(AuthorAdv)
|
author := new(AuthorAdv)
|
||||||
if err := rows.Scan(&author.Id, &author.Name, &author.Count); err != nil {
|
if err := rows.Scan(&author.ID, &author.Name, &author.Count); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
authors = append(authors, author)
|
authors = append(authors, author)
|
||||||
@ -60,11 +60,11 @@ func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*Aut
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
|
func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
|
||||||
stmt, err := app.ps(AUTHOR_BOOKS)
|
stmt, err := app.ps(qtAuthorBooks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(author.Id)
|
rows, err := stmt.Query(author.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -72,14 +72,14 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
|
|||||||
series := make(map[int64]*Series, 0)
|
series := make(map[int64]*Series, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
book := new(Book)
|
book := new(Book)
|
||||||
var seriesId sql.NullInt64
|
var seriesID sql.NullInt64
|
||||||
var seriesName sql.NullString
|
var seriesName sql.NullString
|
||||||
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &seriesName, &seriesId); err != nil {
|
if err = rows.Scan(&book.ID, &book.Title, &book.SeriesIndex, &seriesName, &seriesID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if seriesId.Valid && seriesName.Valid {
|
if seriesID.Valid && seriesName.Valid {
|
||||||
series[seriesId.Int64] = &Series{
|
series[seriesID.Int64] = &Series{
|
||||||
seriesId.Int64,
|
seriesID.Int64,
|
||||||
seriesName.String,
|
seriesName.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,18 +96,18 @@ func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
|
func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
|
||||||
stmt, err := app.ps(AUTHOR_COAUTHORS)
|
stmt, err := app.ps(qtAuthorCoauthors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(author.Id, author.Id)
|
rows, err := stmt.Query(author.ID, author.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
coauthor := new(Author)
|
coauthor := new(Author)
|
||||||
if err = rows.Scan(&coauthor.Id, &coauthor.Name); err != nil {
|
if err = rows.Scan(&coauthor.ID, &coauthor.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
author.CoAuthors = append(author.CoAuthors, coauthor)
|
author.CoAuthors = append(author.CoAuthors, coauthor)
|
||||||
@ -119,12 +119,12 @@ func (app *Bouquins) queryAuthorAuthors(author *AuthorFull) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
|
func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
|
||||||
stmt, err := app.ps(AUTHOR)
|
stmt, err := app.ps(qtAuthor)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
author := new(AuthorFull)
|
author := new(AuthorFull)
|
||||||
author.Id = id
|
author.ID = id
|
||||||
err = stmt.QueryRow(id).Scan(&author.Name)
|
err = stmt.QueryRow(id).Scan(&author.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -134,6 +134,7 @@ func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
|
|||||||
|
|
||||||
// DB LOADS //
|
// DB LOADS //
|
||||||
|
|
||||||
|
// AuthorsAdv loads a list of authors
|
||||||
func (app *Bouquins) AuthorsAdv(params *ReqParams) ([]*AuthorAdv, int, bool, error) {
|
func (app *Bouquins) AuthorsAdv(params *ReqParams) ([]*AuthorAdv, int, bool, error) {
|
||||||
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
|
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
|
||||||
if len(params.Terms) > 0 {
|
if len(params.Terms) > 0 {
|
||||||
@ -147,6 +148,7 @@ func (app *Bouquins) AuthorsAdv(params *ReqParams) ([]*AuthorAdv, int, bool, err
|
|||||||
return authors, 0, more, nil
|
return authors, 0, more, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorFull loads an author
|
||||||
func (app *Bouquins) AuthorFull(id int64) (*AuthorFull, error) {
|
func (app *Bouquins) AuthorFull(id int64) (*AuthorFull, error) {
|
||||||
author, err := app.queryAuthor(id)
|
author, err := app.queryAuthor(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -7,15 +7,15 @@ import (
|
|||||||
// MERGE SUB QUERIES //
|
// MERGE SUB QUERIES //
|
||||||
func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags map[int64][]string) {
|
func assignAuthorsTagsBooks(books []*BookAdv, authors map[int64][]*Author, tags map[int64][]string) {
|
||||||
for _, b := range books {
|
for _, b := range books {
|
||||||
b.Authors = authors[b.Id]
|
b.Authors = authors[b.ID]
|
||||||
b.Tags = tags[b.Id]
|
b.Tags = tags[b.ID]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUB QUERIES //
|
// SUB QUERIES //
|
||||||
|
|
||||||
func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAdv, int, error) {
|
func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAdv, int, error) {
|
||||||
rows, err := app.searchHelper(all, terms, STMT_BOOKS0+STMT_WHERE, STMT_SEARCH_TERM_BOOKS, STMT_SEARCH_ORDER_BOOKS)
|
rows, err := app.searchHelper(all, terms, sqlBooks0+sqlWhere, sqlBooksTerm, sqlBooksOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -25,15 +25,15 @@ func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAd
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
if len(books) <= limit {
|
if len(books) <= limit {
|
||||||
book := new(BookAdv)
|
book := new(BookAdv)
|
||||||
var series_name sql.NullString
|
var seriesName sql.NullString
|
||||||
var series_id sql.NullInt64
|
var seriesID sql.NullInt64
|
||||||
if err := rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &series_name, &series_id); err != nil {
|
if err := rows.Scan(&book.ID, &book.Title, &book.SeriesIndex, &seriesName, &seriesID); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
if series_name.Valid && series_id.Valid {
|
if seriesName.Valid && seriesID.Valid {
|
||||||
book.Series = &Series{
|
book.Series = &Series{
|
||||||
series_id.Int64,
|
seriesID.Int64,
|
||||||
series_name.String,
|
seriesName.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
books = append(books, book)
|
books = append(books, book)
|
||||||
@ -48,7 +48,7 @@ func (app *Bouquins) searchBooks(limit int, terms []string, all bool) ([]*BookAd
|
|||||||
|
|
||||||
func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookAdv, bool, error) {
|
func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookAdv, bool, error) {
|
||||||
books := make([]*BookAdv, 0, limit)
|
books := make([]*BookAdv, 0, limit)
|
||||||
stmt, err := app.psSortBooks(BOOKS, sort, order)
|
stmt, err := app.psSortBooks(qtBooks, sort, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@ -63,15 +63,15 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA
|
|||||||
more = true
|
more = true
|
||||||
} else {
|
} else {
|
||||||
book := new(BookAdv)
|
book := new(BookAdv)
|
||||||
var series_name sql.NullString
|
var seriesName sql.NullString
|
||||||
var series_id sql.NullInt64
|
var seriesID sql.NullInt64
|
||||||
if err := rows.Scan(&book.Id, &book.Title, &book.SeriesIndex, &series_name, &series_id); err != nil {
|
if err := rows.Scan(&book.ID, &book.Title, &book.SeriesIndex, &seriesName, &seriesID); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if series_name.Valid && series_id.Valid {
|
if seriesName.Valid && seriesID.Valid {
|
||||||
book.Series = &Series{
|
book.Series = &Series{
|
||||||
series_id.Int64,
|
seriesID.Int64,
|
||||||
series_name.String,
|
seriesName.String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
books = append(books, book)
|
books = append(books, book)
|
||||||
@ -85,7 +85,7 @@ func (app *Bouquins) queryBooks(limit, offset int, sort, order string) ([]*BookA
|
|||||||
|
|
||||||
func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
|
func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
|
||||||
authors := make(map[int64][]*Author)
|
authors := make(map[int64][]*Author)
|
||||||
stmt, err := app.psSortBooks(BOOKS_AUTHORS, sort, order)
|
stmt, err := app.psSortBooks(qtBooksAuthors, sort, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -97,7 +97,7 @@ func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (m
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
author := new(Author)
|
author := new(Author)
|
||||||
var book int64
|
var book int64
|
||||||
if err := rows.Scan(&author.Id, &author.Name, &book); err != nil {
|
if err := rows.Scan(&author.ID, &author.Name, &book); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if authors[book] == nil {
|
if authors[book] == nil {
|
||||||
@ -113,7 +113,7 @@ func (app *Bouquins) queryBooksAuthors(limit, offset int, sort, order string) (m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[int64][]string, error) {
|
func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[int64][]string, error) {
|
||||||
stmt, err := app.psSortBooks(BOOKS_TAGS, sort, order)
|
stmt, err := app.psSortBooks(qtBooksTags, sort, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -143,23 +143,23 @@ func (app *Bouquins) queryBooksTags(limit, offset int, sort, order string) (map[
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
|
func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
|
||||||
stmt, err := app.ps(BOOK)
|
stmt, err := app.ps(qtBook)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
book := new(BookFull)
|
book := new(BookFull)
|
||||||
var seriesIdx sql.NullFloat64
|
var seriesIdx sql.NullFloat64
|
||||||
var seriesId, timestamp, pubdate sql.NullInt64
|
var seriesID, timestamp, pubdate sql.NullInt64
|
||||||
var seriesName, isbn, lccn, uuid, lang, publisher sql.NullString
|
var seriesName, isbn, lccn, uuid, lang, publisher sql.NullString
|
||||||
var cover sql.NullBool
|
var cover sql.NullBool
|
||||||
err = stmt.QueryRow(id).Scan(&book.Id, &book.Title, &seriesIdx, &seriesName, &seriesId,
|
err = stmt.QueryRow(id).Scan(&book.ID, &book.Title, &seriesIdx, &seriesName, &seriesID,
|
||||||
×tamp, &pubdate, &isbn, &lccn, &book.Path, &uuid, &cover, &lang, &publisher)
|
×tamp, &pubdate, &isbn, &lccn, &book.Path, &uuid, &cover, &lang, &publisher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if seriesId.Valid && seriesName.Valid && seriesIdx.Valid {
|
if seriesID.Valid && seriesName.Valid && seriesIdx.Valid {
|
||||||
book.SeriesIndex = seriesIdx.Float64
|
book.SeriesIndex = seriesIdx.Float64
|
||||||
book.Series = &Series{seriesId.Int64, seriesName.String}
|
book.Series = &Series{seriesID.Int64, seriesName.String}
|
||||||
}
|
}
|
||||||
if timestamp.Valid {
|
if timestamp.Valid {
|
||||||
book.Timestamp = timestamp.Int64
|
book.Timestamp = timestamp.Int64
|
||||||
@ -174,7 +174,7 @@ func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
|
|||||||
book.Lccn = lccn.String
|
book.Lccn = lccn.String
|
||||||
}
|
}
|
||||||
if uuid.Valid {
|
if uuid.Valid {
|
||||||
book.Uuid = uuid.String
|
book.UUID = uuid.String
|
||||||
}
|
}
|
||||||
if lang.Valid {
|
if lang.Valid {
|
||||||
book.Lang = lang.String
|
book.Lang = lang.String
|
||||||
@ -183,16 +183,16 @@ func (app *Bouquins) queryBook(id int64) (*BookFull, error) {
|
|||||||
book.Publisher = publisher.String
|
book.Publisher = publisher.String
|
||||||
}
|
}
|
||||||
if cover.Valid {
|
if cover.Valid {
|
||||||
book.Has_cover = cover.Bool
|
book.HasCover = cover.Bool
|
||||||
}
|
}
|
||||||
return book, nil
|
return book, nil
|
||||||
}
|
}
|
||||||
func (app *Bouquins) queryBookTags(book *BookFull) error {
|
func (app *Bouquins) queryBookTags(book *BookFull) error {
|
||||||
stmt, err := app.ps(BOOK_TAGS)
|
stmt, err := app.ps(qtBookTags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(book.Id)
|
rows, err := stmt.Query(book.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -210,11 +210,11 @@ func (app *Bouquins) queryBookTags(book *BookFull) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (app *Bouquins) queryBookData(book *BookFull) error {
|
func (app *Bouquins) queryBookData(book *BookFull) error {
|
||||||
stmt, err := app.ps(BOOK_DATA)
|
stmt, err := app.ps(qtBookData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(book.Id)
|
rows, err := stmt.Query(book.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -232,19 +232,19 @@ func (app *Bouquins) queryBookData(book *BookFull) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (app *Bouquins) queryBookAuthors(book *BookFull) error {
|
func (app *Bouquins) queryBookAuthors(book *BookFull) error {
|
||||||
stmt, err := app.ps(BOOK_AUTHORS)
|
stmt, err := app.ps(qtBookAuthors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(book.Id)
|
rows, err := stmt.Query(book.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
author := new(Author)
|
author := new(Author)
|
||||||
var bookId int64
|
var bookID int64
|
||||||
if err = rows.Scan(&author.Id, &author.Name, &bookId); err != nil {
|
if err = rows.Scan(&author.ID, &author.Name, &bookID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
book.Authors = append(book.Authors, author)
|
book.Authors = append(book.Authors, author)
|
||||||
@ -257,9 +257,10 @@ func (app *Bouquins) queryBookAuthors(book *BookFull) error {
|
|||||||
|
|
||||||
// DB LOADS //
|
// DB LOADS //
|
||||||
|
|
||||||
|
// BookCount counts books in database
|
||||||
func (app *Bouquins) BookCount() (int64, error) {
|
func (app *Bouquins) BookCount() (int64, error) {
|
||||||
var count int64
|
var count int64
|
||||||
stmt, err := app.ps(BOOKS_COUNT)
|
stmt, err := app.ps(qtBookCount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
@ -268,6 +269,7 @@ func (app *Bouquins) BookCount() (int64, error) {
|
|||||||
return count, err
|
return count, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BookFull loads a book
|
||||||
func (app *Bouquins) BookFull(id int64) (*BookFull, error) {
|
func (app *Bouquins) BookFull(id int64) (*BookFull, error) {
|
||||||
book, err := app.queryBook(id)
|
book, err := app.queryBook(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -288,6 +290,7 @@ func (app *Bouquins) BookFull(id int64) (*BookFull, error) {
|
|||||||
return book, nil
|
return book, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BooksAdv loads a list of books
|
||||||
func (app *Bouquins) BooksAdv(params *ReqParams) ([]*BookAdv, int, bool, error) {
|
func (app *Bouquins) BooksAdv(params *ReqParams) ([]*BookAdv, int, bool, error) {
|
||||||
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
|
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
|
||||||
if len(params.Terms) > 0 {
|
if len(params.Terms) > 0 {
|
||||||
|
@ -4,14 +4,14 @@ package bouquins
|
|||||||
|
|
||||||
func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) {
|
func assignAuthorsSeries(series []*SeriesAdv, authors map[int64][]*Author) {
|
||||||
for _, s := range series {
|
for _, s := range series {
|
||||||
s.Authors = authors[s.Id]
|
s.Authors = authors[s.ID]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SUB QUERIES //
|
// SUB QUERIES //
|
||||||
|
|
||||||
func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*SeriesAdv, int, error) {
|
func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*SeriesAdv, int, error) {
|
||||||
rows, err := app.searchHelper(all, terms, STMT_SERIES_SEARCH, STMT_SEARCH_TERM_SERIES, STMT_SEARCH_ORDER_SERIES)
|
rows, err := app.searchHelper(all, terms, sqlSeriesSearch, sqlSeriesTerm, sqlSeriesOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
@ -21,7 +21,7 @@ func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*Serie
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
if len(series) <= limit {
|
if len(series) <= limit {
|
||||||
serie := new(SeriesAdv)
|
serie := new(SeriesAdv)
|
||||||
if err := rows.Scan(&serie.Id, &serie.Name); err != nil {
|
if err := rows.Scan(&serie.ID, &serie.Name); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
series = append(series, serie)
|
series = append(series, serie)
|
||||||
@ -36,7 +36,7 @@ func (app *Bouquins) searchSeries(limit int, terms []string, all bool) ([]*Serie
|
|||||||
|
|
||||||
func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*SeriesAdv, bool, error) {
|
func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*SeriesAdv, bool, error) {
|
||||||
series := make([]*SeriesAdv, 0, limit)
|
series := make([]*SeriesAdv, 0, limit)
|
||||||
stmt, err := app.psSortSeries(SERIES, sort, order)
|
stmt, err := app.psSortSeries(qtSeries, sort, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*
|
|||||||
more = true
|
more = true
|
||||||
} else {
|
} else {
|
||||||
serie := new(SeriesAdv)
|
serie := new(SeriesAdv)
|
||||||
if err := rows.Scan(&serie.Id, &serie.Name, &serie.Count); err != nil {
|
if err := rows.Scan(&serie.ID, &serie.Name, &serie.Count); err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
series = append(series, serie)
|
series = append(series, serie)
|
||||||
@ -64,7 +64,7 @@ func (app *Bouquins) querySeriesList(limit, offset int, sort, order string) ([]*
|
|||||||
}
|
}
|
||||||
func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
|
func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order string) (map[int64][]*Author, error) {
|
||||||
authors := make(map[int64][]*Author)
|
authors := make(map[int64][]*Author)
|
||||||
stmt, err := app.psSortBooks(SERIES_AUTHORS, sort, order)
|
stmt, err := app.psSortBooks(qtSeriesAuthors, sort, order)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -75,14 +75,14 @@ func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order strin
|
|||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
author := new(Author)
|
author := new(Author)
|
||||||
var serId int64
|
var seriesID int64
|
||||||
if err := rows.Scan(&author.Id, &author.Name, &serId); err != nil {
|
if err := rows.Scan(&author.ID, &author.Name, &seriesID); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if authors[serId] == nil {
|
if authors[seriesID] == nil {
|
||||||
authors[serId] = append(make([]*Author, 0), author)
|
authors[seriesID] = append(make([]*Author, 0), author)
|
||||||
} else {
|
} else {
|
||||||
authors[serId] = append(authors[serId], author)
|
authors[seriesID] = append(authors[seriesID], author)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
if err := rows.Err(); err != nil {
|
||||||
@ -92,27 +92,27 @@ func (app *Bouquins) querySeriesListAuthors(limit, offset int, sort, order strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *Bouquins) querySeries(id int64) (*SeriesFull, error) {
|
func (app *Bouquins) querySeries(id int64) (*SeriesFull, error) {
|
||||||
stmt, err := app.ps(SERIE)
|
stmt, err := app.ps(qtSerie)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
series := new(SeriesFull)
|
series := new(SeriesFull)
|
||||||
err = stmt.QueryRow(id).Scan(&series.Id, &series.Name)
|
err = stmt.QueryRow(id).Scan(&series.ID, &series.Name)
|
||||||
return series, nil
|
return series, nil
|
||||||
}
|
}
|
||||||
func (app *Bouquins) querySeriesAuthors(series *SeriesFull) error {
|
func (app *Bouquins) querySeriesAuthors(series *SeriesFull) error {
|
||||||
stmt, err := app.ps(SERIE_AUTHORS)
|
stmt, err := app.ps(qtSerieAuthors)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(series.Id)
|
rows, err := stmt.Query(series.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
author := new(Author)
|
author := new(Author)
|
||||||
if err = rows.Scan(&author.Id, &author.Name); err != nil {
|
if err = rows.Scan(&author.ID, &author.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
series.Authors = append(series.Authors, author)
|
series.Authors = append(series.Authors, author)
|
||||||
@ -123,18 +123,18 @@ func (app *Bouquins) querySeriesAuthors(series *SeriesFull) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (app *Bouquins) querySeriesBooks(series *SeriesFull) error {
|
func (app *Bouquins) querySeriesBooks(series *SeriesFull) error {
|
||||||
stmt, err := app.ps(SERIE_BOOKS)
|
stmt, err := app.ps(qtSerieBooks)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
rows, err := stmt.Query(series.Id)
|
rows, err := stmt.Query(series.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
book := new(Book)
|
book := new(Book)
|
||||||
if err = rows.Scan(&book.Id, &book.Title, &book.SeriesIndex); err != nil {
|
if err = rows.Scan(&book.ID, &book.Title, &book.SeriesIndex); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
series.Books = append(series.Books, book)
|
series.Books = append(series.Books, book)
|
||||||
@ -147,6 +147,7 @@ func (app *Bouquins) querySeriesBooks(series *SeriesFull) error {
|
|||||||
|
|
||||||
// DB LOADS //
|
// DB LOADS //
|
||||||
|
|
||||||
|
// SeriesFull loads a series
|
||||||
func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
|
func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
|
||||||
series, err := app.querySeries(id)
|
series, err := app.querySeries(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -163,6 +164,7 @@ func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
|
|||||||
return series, nil
|
return series, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeriesAdv loads a list of series
|
||||||
func (app *Bouquins) SeriesAdv(params *ReqParams) ([]*SeriesAdv, int, bool, error) {
|
func (app *Bouquins) SeriesAdv(params *ReqParams) ([]*SeriesAdv, int, bool, error) {
|
||||||
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
|
limit, offset, sort, order := params.Limit, params.Offset, params.Sort, params.Order
|
||||||
if len(params.Terms) > 0 {
|
if len(params.Terms) > 0 {
|
||||||
|
33
main.go
33
main.go
@ -9,9 +9,10 @@ import (
|
|||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
|
||||||
. "meutel.net/meutel/go-bouquins/bouquins"
|
"meutel.net/meutel/go-bouquins/bouquins"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BouquinsConf App configuration
|
||||||
type BouquinsConf struct {
|
type BouquinsConf struct {
|
||||||
BindAddress string `json:"bind-address"`
|
BindAddress string `json:"bind-address"`
|
||||||
DbPath string `json:"db-path"`
|
DbPath string `json:"db-path"`
|
||||||
@ -20,7 +21,7 @@ type BouquinsConf struct {
|
|||||||
|
|
||||||
var db *sql.DB
|
var db *sql.DB
|
||||||
|
|
||||||
// load config
|
// ReadConfig loads configuration file and initialize default value
|
||||||
func ReadConfig() (*BouquinsConf, error) {
|
func ReadConfig() (*BouquinsConf, error) {
|
||||||
conf := new(BouquinsConf)
|
conf := new(BouquinsConf)
|
||||||
confPath := "bouquins.json"
|
confPath := "bouquins.json"
|
||||||
@ -55,7 +56,7 @@ func initApp() *BouquinsConf {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tpl, err := TemplatesFunc().ParseGlob("templates/*.html")
|
tpl, err := bouquins.TemplatesFunc().ParseGlob("templates/*.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
@ -63,7 +64,7 @@ func initApp() *BouquinsConf {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
app := &Bouquins{tpl, db}
|
app := &bouquins.Bouquins{Tpl: tpl, DB: db}
|
||||||
err = app.PrepareAll()
|
err = app.PrepareAll()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
@ -74,10 +75,10 @@ func initApp() *BouquinsConf {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func assets(calibre string) {
|
func assets(calibre string) {
|
||||||
http.Handle(URL_JS, http.FileServer(http.Dir("assets")))
|
http.Handle(bouquins.URLJs, http.FileServer(http.Dir("assets")))
|
||||||
http.Handle(URL_CSS, http.FileServer(http.Dir("assets")))
|
http.Handle(bouquins.URLCss, http.FileServer(http.Dir("assets")))
|
||||||
http.Handle(URL_FONTS, http.FileServer(http.Dir("assets")))
|
http.Handle(bouquins.URLFonts, http.FileServer(http.Dir("assets")))
|
||||||
http.Handle(URL_CALIBRE, http.StripPrefix(URL_CALIBRE, http.FileServer(http.Dir(calibre))))
|
http.Handle(bouquins.URLCalibre, http.StripPrefix(bouquins.URLCalibre, http.FileServer(http.Dir(calibre))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func handle(f func(res http.ResponseWriter, req *http.Request) error) func(res http.ResponseWriter, req *http.Request) {
|
func handle(f func(res http.ResponseWriter, req *http.Request) error) func(res http.ResponseWriter, req *http.Request) {
|
||||||
@ -90,17 +91,17 @@ func handle(f func(res http.ResponseWriter, req *http.Request) error) func(res h
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUrl(url string, f func(res http.ResponseWriter, req *http.Request) error) {
|
func handleURL(url string, f func(res http.ResponseWriter, req *http.Request) error) {
|
||||||
http.HandleFunc(url, handle(f))
|
http.HandleFunc(url, handle(f))
|
||||||
}
|
}
|
||||||
|
|
||||||
func router(app *Bouquins) {
|
func router(app *bouquins.Bouquins) {
|
||||||
handleUrl(URL_INDEX, app.IndexPage)
|
handleURL(bouquins.URLIndex, app.IndexPage)
|
||||||
handleUrl(URL_BOOKS, app.BooksPage)
|
handleURL(bouquins.URLBooks, app.BooksPage)
|
||||||
handleUrl(URL_AUTHORS, app.AuthorsPage)
|
handleURL(bouquins.URLAuthors, app.AuthorsPage)
|
||||||
handleUrl(URL_SERIES, app.SeriesPage)
|
handleURL(bouquins.URLSeries, app.SeriesPage)
|
||||||
handleUrl(URL_SEARCH, app.SearchPage)
|
handleURL(bouquins.URLSearch, app.SearchPage)
|
||||||
handleUrl(URL_ABOUT, app.AboutPage)
|
handleURL(bouquins.URLAbout, app.AboutPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
<div class="container" id="author">
|
<div class="container" id="author">
|
||||||
{{ if .Id }}
|
{{ if .ID }}
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>
|
<h1>
|
||||||
<span class="glyphicon glyphicon-user"></span>
|
<span class="glyphicon glyphicon-user"></span>
|
||||||
@ -21,7 +21,7 @@
|
|||||||
{{ range .Books }}
|
{{ range .Books }}
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li><span class="glyphicon glyphicon-book"></span>
|
<li><span class="glyphicon glyphicon-book"></span>
|
||||||
<a href="/books/{{ .Id }}">{{ .Title }}</a>
|
<a href="/books/{{ .ID }}">{{ .Title }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
@ -33,7 +33,7 @@
|
|||||||
{{ range .Series }}
|
{{ range .Series }}
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li><span class="glyphicon glyphicon-list"></span>
|
<li><span class="glyphicon glyphicon-list"></span>
|
||||||
<a href="/series/{{ .Id }}">{{ .Name }}</a>
|
<a href="/series/{{ .ID }}">{{ .Name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
@ -46,7 +46,7 @@
|
|||||||
{{ range .CoAuthors }}
|
{{ range .CoAuthors }}
|
||||||
<ul class="list-unstyled">
|
<ul class="list-unstyled">
|
||||||
<li> <span class="glyphicon glyphicon-user"></span>
|
<li> <span class="glyphicon glyphicon-user"></span>
|
||||||
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
|
<a href="/authors/{{ .ID }}">{{ .Name }}</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
<div class="container" id="app">
|
<div class="container" id="app">
|
||||||
{{ if .Id }}
|
{{ if .ID }}
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
{{ if .Has_cover }}
|
{{ if .HasCover }}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<img src="{{ bookCover .BookFull }}" alt="Pas de couverture" title="Couverture" class="img-responsive img-rounded" width="400px"/>
|
<img src="{{ bookCover .BookFull }}" alt="Pas de couverture" title="Couverture" class="img-responsive img-rounded" width="400px"/>
|
||||||
</div>
|
</div>
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{{ range .Authors }}
|
{{ range .Authors }}
|
||||||
<li>
|
<li>
|
||||||
<a href="/authors/{{.Id}}">{{ .Name }}</a>
|
<a href="/authors/{{.ID}}">{{ .Name }}</a>
|
||||||
</li>
|
</li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<span class="glyphicon glyphicon-list"></span> Serie
|
<span class="glyphicon glyphicon-list"></span> Serie
|
||||||
</h2>
|
</h2>
|
||||||
<div>
|
<div>
|
||||||
<a href="/series/{{ .Series.Id }}">{{ .Series.Name }}</a>
|
<a href="/series/{{ .Series.ID }}">{{ .Series.Name }}</a>
|
||||||
<span class="badge">{{ .SeriesIndex }}</span>
|
<span class="badge">{{ .SeriesIndex }}</span>
|
||||||
</div>
|
</div>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{{ template "header.html" . }}
|
{{ template "header.html" . }}
|
||||||
<div class="container" id="app">
|
<div class="container" id="app">
|
||||||
{{ if .Id }}
|
{{ if .ID }}
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>
|
<h1>
|
||||||
<span class="glyphicon glyphicon-list"></span>
|
<span class="glyphicon glyphicon-list"></span>
|
||||||
@ -13,7 +13,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
{{ range .Books }}
|
{{ range .Books }}
|
||||||
<li class="list-unstyled">{{ .SeriesIndex }}.
|
<li class="list-unstyled">{{ .SeriesIndex }}.
|
||||||
<a href="/books/{{ .Id }}">{{ .Title }}</a>
|
<a href="/books/{{ .ID }}">{{ .Title }}</a>
|
||||||
</li>
|
</li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
@ -24,7 +24,7 @@
|
|||||||
{{ range .Authors }}
|
{{ range .Authors }}
|
||||||
<li class="list-unstyled">
|
<li class="list-unstyled">
|
||||||
<span class="glyphicon glyphicon-user"></span>
|
<span class="glyphicon glyphicon-user"></span>
|
||||||
<a href="/authors/{{ .Id }}">{{ .Name }}</a>
|
<a href="/authors/{{ .ID }}">{{ .Name }}</a>
|
||||||
</li>
|
</li>
|
||||||
{{ end }}
|
{{ end }}
|
||||||
</ul>
|
</ul>
|
||||||
|
Loading…
Reference in New Issue
Block a user