Authors list

This commit is contained in:
Meutel 2017-08-05 17:48:06 +02:00
parent 2f1e2a70fd
commit 6c11b38f2b
6 changed files with 165 additions and 83 deletions

View File

@ -33,6 +33,10 @@ Vue.component('result-cell', {
}, },
cellContent: function(h) { cellContent: function(h) {
switch (this.col.id) { switch (this.col.id) {
case 'name':
return this.link(h, 'user', this.item.name, this.authorUrl(this.item.id));
case 'count':
return this.item.count;
case 'title': case 'title':
return this.link(h, 'book', this.item.title, this.bookUrl(this.item.id)); return this.link(h, 'book', this.item.title, this.bookUrl(this.item.id));
case 'authors': case 'authors':
@ -52,6 +56,7 @@ Vue.component('result-cell', {
} }
return ''; return '';
default: default:
console.log('ERROR unknown col: ' + this.col.id)
return ''; return '';
} }
} }
@ -82,7 +87,7 @@ var index = new Vue({
console.log("Series"); console.log("Series");
}, },
showAuthors: function() { showAuthors: function() {
console.log("Authors"); this.sendQuery('/authors/', this.stdError, this.loadResults);
}, },
showBooks: function() { showBooks: function() {
this.sendQuery('/books/', this.stdError, this.loadResults); this.sendQuery('/books/', this.stdError, this.loadResults);
@ -105,8 +110,8 @@ var index = new Vue({
break; break;
case 'authors': case 'authors':
this.cols = [ this.cols = [
{ name: 'Nom', sortId: 'name' }, { id: 'name', name: 'Nom', sortable: true },
{ name: 'Livre(s)' } { id:'count', name: 'Livre(s)' }
]; ];
break; break;
} }

View File

@ -3,6 +3,7 @@ package bouquins
import ( import (
"database/sql" "database/sql"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"html/template" "html/template"
"log" "log"
@ -158,21 +159,35 @@ func NewIndexModel(title, js string, count int64) *IndexModel {
} }
} }
type BooksResultsModel struct { type ResultsModel struct {
Results []*BookAdv `json:"results,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
} }
type BooksResultsModel struct {
ResultsModel
Results []*BookAdv `json:"results,omitempty"`
}
func NewBooksResultsModel(books []*BookAdv) *BooksResultsModel { func NewBooksResultsModel(books []*BookAdv) *BooksResultsModel {
return &BooksResultsModel{ return &BooksResultsModel{ResultsModel{"books"}, books}
books,
"books",
}
} }
// Books []*BookAdv `json:"books,omitempty"` type AuthorsResultsModel struct {
// Series []*SeriesAdv `json:"series,omitempty"` ResultsModel
// Authors []*AuthorAdv `json:"authors,omitempty"` Results []*AuthorAdv `json:"results,omitempty"`
}
func NewAuthorsResultsModel(authors []*AuthorAdv) *AuthorsResultsModel {
return &AuthorsResultsModel{ResultsModel{"authors"}, authors}
}
type SerieResultsModel struct {
ResultsModel
Results []*SeriesAdv `json:"results,omitempty"`
}
func NewSerieResultsModel(series []*SeriesAdv) *SerieResultsModel {
return &SerieResultsModel{ResultsModel{"series"}, series}
}
type BookModel struct { type BookModel struct {
BouquinsModel BouquinsModel
@ -189,11 +204,8 @@ type AuthorModel struct {
*AuthorFull *AuthorFull
} }
func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) { func (app *Bouquins) render(res http.ResponseWriter, tpl string, model interface{}) error {
err := app.Template.ExecuteTemplate(res, tpl, model) return app.Template.ExecuteTemplate(res, tpl, model)
if err != nil {
log.Print(err)
}
} }
func TemplatesFunc() *template.Template { func TemplatesFunc() *template.Template {
tpl := template.New("") tpl := template.New("")
@ -212,6 +224,14 @@ func TemplatesFunc() *template.Template {
return tpl return tpl
} }
func writeJson(res http.ResponseWriter, model interface{}) error {
res.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(res)
return enc.Encode(model)
}
func isJson(req *http.Request) bool {
return req.Header.Get("Accept") == "application/json"
}
func paramInt(name string, req *http.Request) int { func paramInt(name string, req *http.Request) int {
val := req.URL.Query().Get(name) val := req.URL.Query().Get(name)
valInt, err := strconv.Atoi(val) valInt, err := strconv.Atoi(val)
@ -254,10 +274,8 @@ func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) {
log.Print(err) log.Print(err)
} }
*/ */
if req.Header.Get("Accept") == "application/json" { if isJson(req) {
res.Header().Set("Content-Type", "application/json") err := writeJson(res, model)
enc := json.NewEncoder(res)
err := enc.Encode(model)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
http.Error(res, err.Error(), 500) http.Error(res, err.Error(), 500)
@ -266,68 +284,83 @@ func (app *Bouquins) IndexPage(res http.ResponseWriter, req *http.Request) {
app.render(res, TPL_INDEX, model) app.render(res, TPL_INDEX, model)
} }
} }
func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) { func (app *Bouquins) BooksListPage(res http.ResponseWriter, req *http.Request) error {
if !strings.HasPrefix(req.URL.Path, URL_BOOKS) { if isJson(req) {
// FIXME 404
log.Fatalln("Invalid URL")
}
idParam := req.URL.Path[len(URL_BOOKS):]
if len(idParam) == 0 {
// books list
if req.Header.Get("Accept") == "application/json" {
books, err := app.BooksAdv(10, 0, "", "") books, err := app.BooksAdv(10, 0, "", "")
if err != nil { if err != nil {
log.Println(err) return err
http.Error(res, err.Error(), 500)
} }
model := NewBooksResultsModel(books) return writeJson(res, NewBooksResultsModel(books))
// FIXME params
res.Header().Set("Content-Type", "application/json")
enc := json.NewEncoder(res)
err = enc.Encode(model)
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
} }
return errors.New("Invalid mime")
} }
} else { func (app *Bouquins) BookPage(idParam string, res http.ResponseWriter, req *http.Request) error {
// book page
id, err := strconv.Atoi(idParam) id, err := strconv.Atoi(idParam)
if err != nil { if err != nil {
// FIXME 404 return nil
log.Fatalln(err)
} }
book, err := app.BookFull(int64(id)) book, err := app.BookFull(int64(id))
if err != nil { if err != nil {
// FIXME 500 return nil
log.Fatalln(err)
} }
model := &BookModel{ return app.render(res, TPL_BOOKS, &BookModel{*NewBouquinsModel(book.Title), book})
*NewBouquinsModel(book.Title),
book,
} }
app.render(res, TPL_BOOKS, model) func (app *Bouquins) BooksPage(res http.ResponseWriter, req *http.Request) {
var err error
var idParam = ""
if strings.HasPrefix(req.URL.Path, URL_BOOKS) {
idParam = req.URL.Path[len(URL_BOOKS):]
} else {
err = errors.New("Invalid URL") // FIXME 404
} }
if len(idParam) == 0 {
err = app.BooksListPage(res, req)
} else {
err = app.BookPage(idParam, res, req)
} }
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
if !strings.HasPrefix(req.URL.Path, URL_AUTHORS) {
// FIXME 404
log.Fatalln("Invalid URL")
}
id, err := strconv.Atoi(req.URL.Path[len(URL_AUTHORS):])
if err != nil { if err != nil {
// FIXME 404 log.Println(err)
log.Fatalln(err) http.Error(res, err.Error(), 500)
}
}
func (app *Bouquins) AuthorsListPage(res http.ResponseWriter, req *http.Request) error {
if isJson(req) {
authors, err := app.AuthorsAdv(10, 0, "", "")
if err != nil {
return err
}
return writeJson(res, NewAuthorsResultsModel(authors))
}
return errors.New("Invalid mime")
}
func (app *Bouquins) AuthorPage(idParam string, res http.ResponseWriter, req *http.Request) error {
id, err := strconv.Atoi(idParam)
if err != nil {
return err
} }
author, err := app.AuthorFull(int64(id)) author, err := app.AuthorFull(int64(id))
if err != nil { if err != nil {
// FIXME 500 return err
log.Fatalln(err) }
return app.render(res, TPL_AUTHORS, &AuthorModel{*NewBouquinsModelJs(author.Name, "author.js"), author})
}
func (app *Bouquins) AuthorsPage(res http.ResponseWriter, req *http.Request) {
var err error
var idParam = ""
if strings.HasPrefix(req.URL.Path, URL_AUTHORS) {
idParam = req.URL.Path[len(URL_AUTHORS):]
} else {
err = errors.New("Invalid URL") // FIXME 404
}
if len(idParam) == 0 {
err = app.AuthorsListPage(res, req)
} else {
err = app.AuthorPage(idParam, res, req)
}
if err != nil {
log.Println(err)
http.Error(res, err.Error(), 500)
} }
app.render(res, TPL_AUTHORS, &AuthorModel{
*NewBouquinsModelJs(author.Name, "author.js"),
author,
})
} }
func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) { func (app *Bouquins) SeriesPage(res http.ResponseWriter, req *http.Request) {
if !strings.HasPrefix(req.URL.Path, URL_SERIES) { if !strings.HasPrefix(req.URL.Path, URL_SERIES) {

View File

@ -115,6 +115,7 @@ const (
SERIES QueryType = iota SERIES QueryType = iota
SERIES_AUTHORS QueryType = iota SERIES_AUTHORS QueryType = iota
SERIES_BOOKS QueryType = iota SERIES_BOOKS QueryType = iota
AUTHORS QueryType = iota
AUTHOR QueryType = iota AUTHOR QueryType = iota
AUTHOR_BOOKS QueryType = iota AUTHOR_BOOKS QueryType = iota
AUTHOR_COAUTHORS QueryType = iota AUTHOR_COAUTHORS QueryType = iota
@ -141,6 +142,10 @@ var QUERIES = map[Query]string{
Query{SERIES, false, false}: STMT_SERIE, Query{SERIES, false, false}: STMT_SERIE,
Query{SERIES_AUTHORS, false, false}: STMT_SERIE_AUTHORS, Query{SERIES_AUTHORS, false, false}: STMT_SERIE_AUTHORS,
Query{SERIES_BOOKS, false, false}: STMT_SERIE_BOOKS, Query{SERIES_BOOKS, false, false}: STMT_SERIE_BOOKS,
Query{AUTHORS, true, true}: STMT_AUTHORS_NAME_DESC,
Query{AUTHORS, true, false}: STMT_AUTHORS_NAME_ASC,
Query{AUTHORS, false, true}: STMT_AUTHORS_ID_DESC,
Query{AUTHORS, false, false}: STMT_AUTHORS_ID_ASC,
Query{AUTHOR, false, false}: STMT_AUTHOR, Query{AUTHOR, false, false}: STMT_AUTHOR,
Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS, Query{AUTHOR_BOOKS, false, false}: STMT_AUTHOR_BOOKS,
Query{AUTHOR_COAUTHORS, false, false}: STMT_AUTHOR_AUTHORS, Query{AUTHOR_COAUTHORS, false, false}: STMT_AUTHOR_AUTHORS,
@ -150,7 +155,7 @@ var STMTS = make(map[Query]*sql.Stmt)
type QueryType uint type QueryType uint
type Query struct { type Query struct {
Type QueryType Type QueryType
Title bool SortField bool // sort by name or title
Desc bool Desc bool
} }
@ -173,7 +178,13 @@ func (app *Bouquins) PrepareAll() error {
// prepared statement with sort on books // prepared statement with sort on books
func (app *Bouquins) psSortBooks(qt QueryType, sort, order string) (*sql.Stmt, error) { func (app *Bouquins) psSortBooks(qt QueryType, sort, order string) (*sql.Stmt, error) {
q := Query{qt, sort == "title", order == "desc"} return app.psSort("title", qt, sort, order)
}
func (app *Bouquins) psSortAuthors(qt QueryType, sort, order string) (*sql.Stmt, error) {
return app.psSort("name", qt, sort, order)
}
func (app *Bouquins) psSort(sortNameField string, qt QueryType, sort, order string) (*sql.Stmt, error) {
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]

View File

@ -6,6 +6,30 @@ import (
// SUB QUERIES // // SUB QUERIES //
func (app *Bouquins) queryAuthors(limit, offset int, sort, order string) ([]*AuthorAdv, error) {
authors := make([]*AuthorAdv, 0, limit)
stmt, err := app.psSortAuthors(AUTHORS, sort, order)
if err != nil {
return nil, err
}
rows, err := stmt.Query(limit, offset)
if err != nil {
return nil, err
}
defer rows.Close()
for rows.Next() {
author := new(AuthorAdv)
if err := rows.Scan(&author.Id, &author.Name, &author.Count); err != nil {
return nil, err
}
authors = append(authors, author)
}
if err := rows.Err(); err != nil {
return nil, err
}
return authors, nil
}
func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error { func (app *Bouquins) queryAuthorBooks(author *AuthorFull) error {
stmt, err := app.ps(AUTHOR_BOOKS) stmt, err := app.ps(AUTHOR_BOOKS)
if err != nil { if err != nil {
@ -81,6 +105,17 @@ func (app *Bouquins) queryAuthor(id int64) (*AuthorFull, error) {
// DB LOADS // // DB LOADS //
func (app *Bouquins) AuthorsAdv(limit, offset int, sort, order string) ([]*AuthorAdv, error) {
if limit == 0 {
limit = DEF_LIM
}
authors, err := app.queryAuthors(limit, offset, sort, order)
if err != nil {
return nil, err
}
return authors, nil
}
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

@ -228,12 +228,6 @@ func (app *Bouquins) BookCount() (int64, error) {
err = row.Scan(&count) err = row.Scan(&count)
return count, err return count, err
} }
func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, error) {
panic("not implemented")
}
func (app *Bouquins) AuthorsAdv(limit, offset int, sort, order string) ([]*AuthorAdv, error) {
panic("not implemented")
}
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)

View File

@ -73,3 +73,7 @@ func (app *Bouquins) SeriesFull(id int64) (*SeriesFull, error) {
} }
return series, nil return series, nil
} }
func (app *Bouquins) SeriesAdv(limit, offset int, sort, order string) ([]*SeriesAdv, error) {
panic("not implemented")
}