New view to see available editions from inventaire
This commit is contained in:
@@ -12,7 +12,7 @@ type InventaireSearchResult struct {
|
||||
}
|
||||
|
||||
type InventaireSearchBook struct {
|
||||
ID string `json:"id"`
|
||||
ID string `json:"uri"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Image string `json:"image"`
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package inventaire
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -53,3 +54,56 @@ func TestCallInventaireBook_BraveNewWorld(t *testing.T) {
|
||||
assert.Equal(t, "Aldous Huxley", result.Author.Name)
|
||||
assert.Equal(t, "écrivain, romancier et philosophe britannique (1894–1963)", result.Author.Description)
|
||||
}
|
||||
|
||||
func TestCallInventaireEdition_TestLimit(t *testing.T) {
|
||||
result, err := CallInventaireEdition("wd:Q339761", "fr", 10, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Equal(t, int64(34), result.Count)
|
||||
assert.Equal(t, 10, len(result.Results))
|
||||
}
|
||||
|
||||
func TestCallInventaireEdition_TestOffset(t *testing.T) {
|
||||
result, err := CallInventaireEdition("wd:Q3213142", "fr", 0, 0)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Equal(t, 3, len(result.Results))
|
||||
sortedResults := result.Results
|
||||
sort.Slice(sortedResults, func(i, j int) bool {
|
||||
return sortedResults[i].Id > sortedResults[j].Id
|
||||
})
|
||||
|
||||
assert.Equal(t,
|
||||
InventaireEditionResultBook{
|
||||
Id: "isbn:9782072525216",
|
||||
Title: "La théorie de l'information",
|
||||
ISBN: "978-2-07-252521-6",
|
||||
ReleaseDate: "",
|
||||
Image: "https://inventaire.io/img/entities/fac578440d9bf7afc7f4c5698aa618b8a4d80d21",
|
||||
Lang: "fr",
|
||||
},
|
||||
result.Results[0])
|
||||
assert.Equal(t,
|
||||
InventaireEditionResultBook{
|
||||
Id: "isbn:9782070456260",
|
||||
Title: "La théorie de l'information",
|
||||
ISBN: "978-2-07-045626-0",
|
||||
ReleaseDate: "2014",
|
||||
Image: "https://inventaire.io/img/entities/5044c2265cc42675ac4335387aef189862cbeec1",
|
||||
Lang: "fr",
|
||||
},
|
||||
result.Results[1])
|
||||
assert.Equal(t,
|
||||
InventaireEditionResultBook{
|
||||
Id: "isbn:9782070138098",
|
||||
Title: "La théorie de l'information",
|
||||
ISBN: "978-2-07-013809-8",
|
||||
Publisher: "Éditions Gallimard",
|
||||
ReleaseDate: "2012",
|
||||
Image: "https://inventaire.io/img/entities/a7b9d05c041b98e98c2f429e11cb2b424d78223b",
|
||||
Lang: "fr",
|
||||
},
|
||||
result.Results[2])
|
||||
}
|
||||
|
||||
240
internal/inventaire/inventaireedition.go
Normal file
240
internal/inventaire/inventaireedition.go
Normal file
@@ -0,0 +1,240 @@
|
||||
package inventaire
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/callapiutils"
|
||||
)
|
||||
|
||||
type InventaireEditionResult struct {
|
||||
Results []InventaireEditionResultBook `json:"results"`
|
||||
Count int64 `json:"count"`
|
||||
}
|
||||
|
||||
type InventaireEditionResultBook struct {
|
||||
Id string `json:"uri"`
|
||||
Title string `json:"title"`
|
||||
ISBN string `json:"isbn"`
|
||||
Publisher string `json:"publisher"`
|
||||
ReleaseDate string `json:"date"`
|
||||
Image string `json:"image"`
|
||||
Lang string `json:"lang"`
|
||||
}
|
||||
|
||||
type inventaireReverseClaimsResult struct {
|
||||
Uris []string `json:"uris"`
|
||||
}
|
||||
|
||||
type inventaireEditionQueryResult struct {
|
||||
Entities []inventaireEditionQueryEntity
|
||||
}
|
||||
|
||||
type inventaireEditionQueryEntity struct {
|
||||
WdId string
|
||||
EditionId string
|
||||
Title string
|
||||
ISBN string
|
||||
Uri string
|
||||
Image string
|
||||
Lang string
|
||||
ReleaseDate string
|
||||
}
|
||||
|
||||
func (i *inventaireEditionQueryResult) UnmarshalJSON(b []byte) error {
|
||||
var parsed struct {
|
||||
Entities map[string]json.RawMessage `json:"entities"`
|
||||
}
|
||||
err := json.Unmarshal(b, &parsed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entity := range parsed.Entities {
|
||||
var parsedEntity struct {
|
||||
WdId string `json:"wdId"`
|
||||
Labels map[string]json.RawMessage `json:"labels"`
|
||||
Type string `json:"type"`
|
||||
Uri string `json:"uri"`
|
||||
Image map[string]json.RawMessage `json:"image"`
|
||||
Lang string `json:"originalLang"`
|
||||
Claims map[string]json.RawMessage `json:"claims"`
|
||||
}
|
||||
err = json.Unmarshal(entity, &parsedEntity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if parsedEntity.Type == "edition" {
|
||||
editionId, err := parseStringArrayFieldInJsonRaw(parsedEntity.Claims, "wdt:P123")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
releaseDate, err := parseStringArrayFieldInJsonRaw(parsedEntity.Claims, "wdt:P577")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isbn, err := parseStringArrayFieldInJsonRaw(parsedEntity.Claims, "wdt:P212")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
label, err := findLangageField(parsedEntity.Labels, "fromclaims")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
image := ""
|
||||
imageFieldToParse, ok := parsedEntity.Image["url"]
|
||||
if ok {
|
||||
err := json.Unmarshal(imageFieldToParse, &image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if image != "" {
|
||||
image = GetBaseInventaireUrl() + image
|
||||
}
|
||||
}
|
||||
i.Entities = append(i.Entities, inventaireEditionQueryEntity{
|
||||
WdId: parsedEntity.WdId,
|
||||
EditionId: editionId,
|
||||
Title: label,
|
||||
ISBN: isbn,
|
||||
Uri: parsedEntity.Uri,
|
||||
Image: image,
|
||||
Lang: parsedEntity.Lang,
|
||||
ReleaseDate: releaseDate,
|
||||
})
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func parseStringArrayFieldInJsonRaw(jsonRawMap map[string]json.RawMessage, key string) (string, error) {
|
||||
fieldToParse, ok := jsonRawMap[key]
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
var fieldArray []string
|
||||
s := ""
|
||||
err := json.Unmarshal(fieldToParse, &fieldArray)
|
||||
if err != nil {
|
||||
return s, err
|
||||
}
|
||||
if len(fieldArray) > 0 {
|
||||
s = fieldArray[0]
|
||||
}
|
||||
return s, err
|
||||
}
|
||||
|
||||
func CallInventaireEdition(inventaireId string, lang string, limit int, offset int) (InventaireEditionResult, error) {
|
||||
var queryResult InventaireEditionResult
|
||||
uris, err := callInventaireUris(inventaireId)
|
||||
if err != nil {
|
||||
return queryResult, err
|
||||
}
|
||||
queryResult.Count = int64(len(uris.Uris))
|
||||
limitedUris := uris.Uris
|
||||
if limit != 0 {
|
||||
l := len(uris.Uris)
|
||||
startIndex := int(math.Min(float64(offset), float64(l)))
|
||||
endIndex := int(math.Min(float64(limit+offset), float64(l)))
|
||||
limitedUris = uris.Uris[startIndex:endIndex]
|
||||
}
|
||||
editionEntities, err := callInventaireEditionEntities(limitedUris)
|
||||
|
||||
if err != nil {
|
||||
return queryResult, err
|
||||
}
|
||||
|
||||
for _, entity := range editionEntities.Entities {
|
||||
publisher := ""
|
||||
if entity.EditionId != "" {
|
||||
publisher, err = callInventairePublisherGetName(entity.EditionId, lang)
|
||||
if err != nil {
|
||||
return queryResult, err
|
||||
}
|
||||
}
|
||||
queryResult.Results = append(queryResult.Results, InventaireEditionResultBook{
|
||||
Id: entity.Uri,
|
||||
ISBN: entity.ISBN,
|
||||
Title: entity.Title,
|
||||
ReleaseDate: entity.ReleaseDate,
|
||||
Image: entity.Image,
|
||||
Publisher: publisher,
|
||||
Lang: entity.Lang,
|
||||
})
|
||||
}
|
||||
return queryResult, err
|
||||
}
|
||||
|
||||
func callInventaireUris(inventaireId string) (inventaireReverseClaimsResult, error) {
|
||||
var queryResult inventaireReverseClaimsResult
|
||||
u, err := computeInventaireApiUrl("entities")
|
||||
if err != nil {
|
||||
return queryResult, err
|
||||
}
|
||||
callapiutils.AddQueryParam(u, "action", "reverse-claims")
|
||||
callapiutils.AddQueryParam(u, "property", "wdt:P629")
|
||||
callapiutils.AddQueryParam(u, "value", inventaireId)
|
||||
|
||||
err = callapiutils.FetchAndParseResult(u, &queryResult)
|
||||
return queryResult, err
|
||||
}
|
||||
|
||||
func callInventaireEditionEntities(uris []string) (inventaireEditionQueryResult, error) {
|
||||
var queryResult inventaireEditionQueryResult
|
||||
u, err := computeInventaireApiUrl("entities")
|
||||
if err != nil {
|
||||
return queryResult, err
|
||||
}
|
||||
|
||||
callapiutils.AddQueryParam(u, "action", "by-uris")
|
||||
callapiutils.AddQueryParam(u, "uris", strings.Join(uris, "|"))
|
||||
|
||||
err = callapiutils.FetchAndParseResult(u, &queryResult)
|
||||
|
||||
return queryResult, err
|
||||
}
|
||||
|
||||
type inventaireEditionPublisherResult struct {
|
||||
Lang string
|
||||
Label string
|
||||
}
|
||||
|
||||
func (i *inventaireEditionPublisherResult) UnmarshalJSON(b []byte) error {
|
||||
var parsed struct {
|
||||
Entities map[string]json.RawMessage
|
||||
}
|
||||
err := json.Unmarshal(b, &parsed)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entity := range parsed.Entities {
|
||||
var publisherEntity struct {
|
||||
Type string `json:"type"`
|
||||
Labels map[string]json.RawMessage `json:"labels"`
|
||||
}
|
||||
err := json.Unmarshal(entity, &publisherEntity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
label, _ := findLangageField(publisherEntity.Labels, i.Lang)
|
||||
i.Label = label
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func callInventairePublisherGetName(editionId string, lang string) (string, error) {
|
||||
var queryResult inventaireEditionPublisherResult
|
||||
u, err := computeInventaireApiUrl("entities")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
queryResult.Lang = lang
|
||||
|
||||
callapiutils.AddQueryParam(u, "action", "by-uris")
|
||||
callapiutils.AddQueryParam(u, "uris", editionId)
|
||||
callapiutils.AddQueryParam(u, "attributes", "info|labels")
|
||||
|
||||
err = callapiutils.FetchAndParseResult(u, &queryResult)
|
||||
return queryResult.Label, err
|
||||
}
|
||||
38
internal/routes/booksinventaireget.go
Normal file
38
internal/routes/booksinventaireget.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/dto"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/inventaire"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/myvalidator"
|
||||
)
|
||||
|
||||
func GetInventaireBooks(ac appcontext.AppContext) {
|
||||
workId := ac.C.Param("workId")
|
||||
var params dto.BookSearchGetParam
|
||||
err := ac.C.ShouldBind(¶ms)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
|
||||
limit, err := ac.GetQueryLimit()
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
offset, err := ac.GetQueryOffset()
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
|
||||
inventaireEditionResult, err := inventaire.CallInventaireEdition(workId, params.Lang, limit, offset)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
ac.C.JSON(http.StatusOK, inventaireEditionResult)
|
||||
}
|
||||
@@ -36,6 +36,9 @@ func Setup(config *config.Config) *gin.Engine {
|
||||
r.GET("/search/:searchterm", func(c *gin.Context) {
|
||||
routes.GetSearchBooksHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||
})
|
||||
r.GET("/inventaire/books/:workId", func(c *gin.Context) {
|
||||
routes.GetInventaireBooks(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||
})
|
||||
r.GET("/book/:id", func(c *gin.Context) {
|
||||
routes.GetBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user