Code style (go vet, go lint)

This commit is contained in:
Meutel 2017-08-06 20:25:20 +02:00
parent 0362051918
commit 2943d217a7
9 changed files with 346 additions and 313 deletions

View File

@ -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)
} }

View File

@ -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

View File

@ -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 {

View File

@ -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,
&timestamp, &pubdate, &isbn, &lccn, &book.Path, &uuid, &cover, &lang, &publisher) &timestamp, &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 {

View File

@ -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
View File

@ -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() {

View File

@ -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 }}

View File

@ -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 }}

View File

@ -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>