Added inventaire import from ISBN
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { putReadBook, getImagePathOrDefault } from './api.js'
|
import { putReadBook, getImagePathOrDefault, postImportBook } from './api.js'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: Number,
|
id: Number,
|
||||||
inventaireid: String,
|
inventaireid: String,
|
||||||
|
isinventaireedition: Boolean,
|
||||||
title: String,
|
title: String,
|
||||||
author: String,
|
author: String,
|
||||||
description: String,
|
description: String,
|
||||||
@@ -28,14 +29,26 @@ async function onUserBookRead() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openBook() {
|
async function openBook() {
|
||||||
if (props.id != 0) {
|
if (props.id != 0) {
|
||||||
router.push(`/book/${props.id}`);
|
router.push(`/book/${props.id}`);
|
||||||
} else {
|
} else if (props.isinventaireedition) {
|
||||||
|
importInventaireEdition()
|
||||||
|
} else if (props.inventaireid != "") {
|
||||||
router.push(`/import/inventaire/${props.inventaireid}`)
|
router.push(`/import/inventaire/${props.inventaireid}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function importInventaireEdition(inventaireid) {
|
||||||
|
const res = await postImportBook(props.inventaireid, navigator.language.substring(0,2));
|
||||||
|
const json = await res.json();
|
||||||
|
if (res.ok) {
|
||||||
|
router.push(`/book/${json.id}`);
|
||||||
|
} else {
|
||||||
|
error.value = json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -9,25 +9,11 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"git.artlef.fr/PersonalLibraryManager/internal/dto"
|
||||||
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
type bookSearchGet struct {
|
|
||||||
Count int64 `json:"count"`
|
|
||||||
Books []bookSearchGetBook `json:"books"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type bookSearchGetBook struct {
|
|
||||||
Id uint `json:"id"`
|
|
||||||
Title string `json:"title" binding:"required,max=300"`
|
|
||||||
Author string `json:"author" binding:"max=100"`
|
|
||||||
Rating int `json:"rating"`
|
|
||||||
Read bool `json:"read"`
|
|
||||||
WantRead bool `json:"wantread"`
|
|
||||||
CoverPath string `json:"coverPath"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSearchBook_MultipleBooks(t *testing.T) {
|
func TestSearchBook_MultipleBooks(t *testing.T) {
|
||||||
result := testSearchBook(t, "san", "", "")
|
result := testSearchBook(t, "san", "", "")
|
||||||
|
|
||||||
@@ -39,10 +25,10 @@ func TestSearchBook_OneBookNotUserBook(t *testing.T) {
|
|||||||
result := testSearchBook(t, "iliade", "", "")
|
result := testSearchBook(t, "iliade", "", "")
|
||||||
assert.Equal(t, int64(1), result.Count)
|
assert.Equal(t, int64(1), result.Count)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
[]bookSearchGetBook{{
|
[]dto.BookSearchGetBook{{
|
||||||
Title: "Iliade",
|
Title: "Iliade",
|
||||||
Author: "Homère",
|
Author: "Homère",
|
||||||
Id: 29,
|
ID: 29,
|
||||||
Rating: 0,
|
Rating: 0,
|
||||||
Read: false,
|
Read: false,
|
||||||
WantRead: false,
|
WantRead: false,
|
||||||
@@ -55,10 +41,10 @@ func TestSearchBook_OneBookRead(t *testing.T) {
|
|||||||
result := testSearchBook(t, "dieux", "", "")
|
result := testSearchBook(t, "dieux", "", "")
|
||||||
assert.Equal(t, int64(1), result.Count)
|
assert.Equal(t, int64(1), result.Count)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
[]bookSearchGetBook{{
|
[]dto.BookSearchGetBook{{
|
||||||
Title: "Les dieux ont soif",
|
Title: "Les dieux ont soif",
|
||||||
Author: "Anatole France",
|
Author: "Anatole France",
|
||||||
Id: 4,
|
ID: 4,
|
||||||
Rating: 7,
|
Rating: 7,
|
||||||
Read: true,
|
Read: true,
|
||||||
WantRead: false,
|
WantRead: false,
|
||||||
@@ -71,10 +57,10 @@ func TestSearchBook_ISBN(t *testing.T) {
|
|||||||
result := testSearchBook(t, "9782070337903", "", "")
|
result := testSearchBook(t, "9782070337903", "", "")
|
||||||
assert.Equal(t, int64(1), result.Count)
|
assert.Equal(t, int64(1), result.Count)
|
||||||
assert.Equal(t,
|
assert.Equal(t,
|
||||||
[]bookSearchGetBook{{
|
[]dto.BookSearchGetBook{{
|
||||||
Title: "Le complot contre l'Amérique",
|
Title: "Le complot contre l'Amérique",
|
||||||
Author: "Philip Roth",
|
Author: "Philip Roth",
|
||||||
Id: 22,
|
ID: 22,
|
||||||
Rating: 6,
|
Rating: 6,
|
||||||
Read: true,
|
Read: true,
|
||||||
WantRead: false,
|
WantRead: false,
|
||||||
@@ -83,6 +69,25 @@ func TestSearchBook_ISBN(t *testing.T) {
|
|||||||
result.Books)
|
result.Books)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSearchBook_ISBNInventaire(t *testing.T) {
|
||||||
|
result := testSearchBook(t, "9782253158400", "", "")
|
||||||
|
assert.Equal(t, int64(1), result.Count)
|
||||||
|
assert.Equal(t,
|
||||||
|
[]dto.BookSearchGetBook{{
|
||||||
|
ID: 0,
|
||||||
|
Title: "Les premières enquêtes de Maigret",
|
||||||
|
Author: "Georges Simenon",
|
||||||
|
Description: "roman de Georges Simenon",
|
||||||
|
InventaireID: "isbn:9782253158400",
|
||||||
|
IsInventaireEdition: true,
|
||||||
|
Rating: 0,
|
||||||
|
Read: false,
|
||||||
|
WantRead: false,
|
||||||
|
CoverPath: "https://inventaire.io/img/entities/17663a503d984204078c910d5bae68d52942b47d",
|
||||||
|
}},
|
||||||
|
result.Books)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSearchBook_Limit(t *testing.T) {
|
func TestSearchBook_Limit(t *testing.T) {
|
||||||
result := testSearchBook(t, "a", "10", "")
|
result := testSearchBook(t, "a", "10", "")
|
||||||
assert.Equal(t, 10, len(result.Books))
|
assert.Equal(t, 10, len(result.Books))
|
||||||
@@ -94,7 +99,7 @@ func TestSearchBook_Offset(t *testing.T) {
|
|||||||
assert.Equal(t, 3, len(result.Books))
|
assert.Equal(t, 3, len(result.Books))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSearchBook(t *testing.T, searchterm string, limit string, offset string) bookSearchGet {
|
func testSearchBook(t *testing.T, searchterm string, limit string, offset string) dto.BookSearchGet {
|
||||||
router := testutils.TestSetup()
|
router := testutils.TestSetup()
|
||||||
|
|
||||||
u, err := url.Parse("/search/" + searchterm)
|
u, err := url.Parse("/search/" + searchterm)
|
||||||
@@ -112,13 +117,17 @@ func testSearchBook(t *testing.T, searchterm string, limit string, offset string
|
|||||||
u.RawQuery = q.Encode()
|
u.RawQuery = q.Encode()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
q := u.Query()
|
||||||
|
q.Set("lang", "fr")
|
||||||
|
u.RawQuery = q.Encode()
|
||||||
|
|
||||||
token := testutils.ConnectDemoUser(router)
|
token := testutils.ConnectDemoUser(router)
|
||||||
req, _ := http.NewRequest("GET", u.String(), nil)
|
req, _ := http.NewRequest("GET", u.String(), nil)
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
router.ServeHTTP(w, req)
|
router.ServeHTTP(w, req)
|
||||||
|
|
||||||
var result bookSearchGet
|
var result dto.BookSearchGet
|
||||||
s := w.Body.String()
|
s := w.Body.String()
|
||||||
err = json.Unmarshal([]byte(s), &result)
|
err = json.Unmarshal([]byte(s), &result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ type BookSearchGetBook struct {
|
|||||||
Author string `json:"author" binding:"max=100"`
|
Author string `json:"author" binding:"max=100"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
InventaireID string `json:"inventaireid"`
|
InventaireID string `json:"inventaireid"`
|
||||||
|
IsInventaireEdition bool `json:"isinventaireedition"`
|
||||||
Rating int `json:"rating"`
|
Rating int `json:"rating"`
|
||||||
Read bool `json:"read"`
|
Read bool `json:"read"`
|
||||||
WantRead bool `json:"wantread"`
|
WantRead bool `json:"wantread"`
|
||||||
|
|||||||
@@ -125,3 +125,27 @@ func TestCallInventaireEdition(t *testing.T) {
|
|||||||
},
|
},
|
||||||
result)
|
result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCallInventaireEditionFromISBN(t *testing.T) {
|
||||||
|
result, err := CallInventaireFromISBN("9782070379248", "fr")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
assert.Equal(t,
|
||||||
|
&InventaireEditionDetailedSingleResult{
|
||||||
|
Id: "isbn:9782070379248",
|
||||||
|
Title: "Du côté de chez swann",
|
||||||
|
Author: &InventaireAuthorResult{
|
||||||
|
ID: "Q7199",
|
||||||
|
Name: "Marcel Proust",
|
||||||
|
Description: "écrivain, critique et essayiste français",
|
||||||
|
},
|
||||||
|
Description: "roman de Marcel Proust",
|
||||||
|
ISBN: "978-2-07-037924-8",
|
||||||
|
Publisher: "Éditions Gallimard",
|
||||||
|
ReleaseDate: "1988",
|
||||||
|
Image: "https://inventaire.io/img/entities/646a3ef031d6a1adc27cb5f556d2a403a2f525a7",
|
||||||
|
Lang: "fr",
|
||||||
|
},
|
||||||
|
result)
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,14 @@ type InventaireEditionDetailedSingleResult struct {
|
|||||||
Lang string
|
Lang string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ErrorEditionNotFound struct {
|
||||||
|
InventaireId string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *ErrorEditionNotFound) Error() string {
|
||||||
|
return fmt.Sprintf("No edition found on inventaire for id %s\n", e.InventaireId)
|
||||||
|
}
|
||||||
|
|
||||||
func CallInventaireEdition(inventaireId string, lang string) (InventaireEditionDetailedSingleResult, error) {
|
func CallInventaireEdition(inventaireId string, lang string) (InventaireEditionDetailedSingleResult, error) {
|
||||||
var result InventaireEditionDetailedSingleResult
|
var result InventaireEditionDetailedSingleResult
|
||||||
editionQueryResults, err := callInventaireEditionEntities([]string{inventaireId})
|
editionQueryResults, err := callInventaireEditionEntities([]string{inventaireId})
|
||||||
@@ -24,7 +32,7 @@ func CallInventaireEdition(inventaireId string, lang string) (InventaireEditionD
|
|||||||
}
|
}
|
||||||
var editionQueryResult inventaireEditionQueryEntity
|
var editionQueryResult inventaireEditionQueryEntity
|
||||||
if len(editionQueryResults.Entities) < 1 {
|
if len(editionQueryResults.Entities) < 1 {
|
||||||
return result, fmt.Errorf("No edition found on inventaire for id %s", inventaireId)
|
return result, &ErrorEditionNotFound{InventaireId: inventaireId}
|
||||||
}
|
}
|
||||||
|
|
||||||
editionQueryResult = editionQueryResults.Entities[0]
|
editionQueryResult = editionQueryResults.Entities[0]
|
||||||
|
|||||||
16
internal/inventaire/inventaireeditionfromisbn.go
Normal file
16
internal/inventaire/inventaireeditionfromisbn.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package inventaire
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
func CallInventaireFromISBN(isbn string, lang string) (*InventaireEditionDetailedSingleResult, error) {
|
||||||
|
inventaireInfo, err := CallInventaireEdition("isbn:"+isbn, lang)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, &ErrorEditionNotFound{}) {
|
||||||
|
//suppress the not found error, returns nil instead
|
||||||
|
return nil, nil
|
||||||
|
} else {
|
||||||
|
return &inventaireInfo, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &inventaireInfo, err
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package routes
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||||
@@ -51,17 +52,64 @@ func GetSearchBooksHandler(ac appcontext.AppContext) {
|
|||||||
returnedBooks = dto.BookSearchGet{Count: count, Inventaire: false, Books: books}
|
returnedBooks = dto.BookSearchGet{Count: count, Inventaire: false, Books: books}
|
||||||
}
|
}
|
||||||
if params.Inventaire || len(returnedBooks.Books) == 0 {
|
if params.Inventaire || len(returnedBooks.Books) == 0 {
|
||||||
queryResult, err := inventaire.CallInventaireSearch(searchterm, params.Lang, limit, offset)
|
returnedBooksPtr, err := searchInInventaireAPI(searchterm, limit, offset, params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
returnedBooks = InventaireBooksToBookSearchGet(queryResult)
|
returnedBooks = *returnedBooksPtr
|
||||||
}
|
}
|
||||||
ac.C.JSON(http.StatusOK, returnedBooks)
|
ac.C.JSON(http.StatusOK, returnedBooks)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InventaireBooksToBookSearchGet(results inventaire.InventaireSearchResult) dto.BookSearchGet {
|
func searchInInventaireAPI(searchterm string, limit int, offset int, params dto.BookSearchGetParam) (*dto.BookSearchGet, error) {
|
||||||
|
|
||||||
|
isIsbn, err := regexp.Match(`\d{10,13}`, []byte(searchterm))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isIsbn {
|
||||||
|
queryResult, err := inventaire.CallInventaireFromISBN(searchterm, params.Lang)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var bookSearchGet dto.BookSearchGet
|
||||||
|
if queryResult != nil {
|
||||||
|
bookSearchGet = inventaireEditionToBookSearchGet(*queryResult)
|
||||||
|
} else {
|
||||||
|
bookSearchGet = dto.BookSearchGet{Count: 0, Inventaire: true}
|
||||||
|
}
|
||||||
|
return &bookSearchGet, err
|
||||||
|
} else {
|
||||||
|
queryResult, err := inventaire.CallInventaireSearch(searchterm, params.Lang, limit, offset)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
bookSearchGet := inventaireBooksToBookSearchGet(queryResult)
|
||||||
|
return &bookSearchGet, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inventaireEditionToBookSearchGet(result inventaire.InventaireEditionDetailedSingleResult) dto.BookSearchGet {
|
||||||
|
var books []dto.BookSearchGetBook
|
||||||
|
bookSearchGetBook := dto.BookSearchGetBook{
|
||||||
|
ID: 0,
|
||||||
|
Title: result.Title,
|
||||||
|
Author: result.Author.Name,
|
||||||
|
Description: result.Description,
|
||||||
|
InventaireID: result.Id,
|
||||||
|
IsInventaireEdition: true,
|
||||||
|
Rating: 0,
|
||||||
|
Read: false,
|
||||||
|
WantRead: false,
|
||||||
|
CoverPath: result.Image,
|
||||||
|
}
|
||||||
|
books = append(books, bookSearchGetBook)
|
||||||
|
return dto.BookSearchGet{Count: 1, Inventaire: true, Books: books}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inventaireBooksToBookSearchGet(results inventaire.InventaireSearchResult) dto.BookSearchGet {
|
||||||
var books []dto.BookSearchGetBook
|
var books []dto.BookSearchGetBook
|
||||||
for _, b := range results.Results {
|
for _, b := range results.Results {
|
||||||
coverPath := ""
|
coverPath := ""
|
||||||
|
|||||||
Reference in New Issue
Block a user