From f444cbb19f26c5f5e9bdca7d5e7306a98f1ae17e Mon Sep 17 00:00:00 2001 From: Arthur Lefebvre Date: Wed, 28 Jan 2026 19:10:19 +0100 Subject: [PATCH] New view to see available editions from inventaire --- front/public/defaultinventairebook.png | Bin 0 -> 22180 bytes front/src/BookListElement.vue | 2 +- front/src/ImportInventaire.vue | 68 +++++++ front/src/ImportListElement.vue | 69 +++++++ front/src/api.js | 15 +- front/src/locales/en.json | 10 +- front/src/locales/fr.json | 9 +- front/src/router.js | 2 + internal/inventaire/inventaire.go | 2 +- internal/inventaire/inventaire_test.go | 54 +++++ internal/inventaire/inventaireedition.go | 240 +++++++++++++++++++++++ internal/routes/booksinventaireget.go | 38 ++++ internal/setup/setup.go | 3 + 13 files changed, 507 insertions(+), 5 deletions(-) create mode 100644 front/public/defaultinventairebook.png create mode 100644 front/src/ImportInventaire.vue create mode 100644 front/src/ImportListElement.vue create mode 100644 internal/inventaire/inventaireedition.go create mode 100644 internal/routes/booksinventaireget.go diff --git a/front/public/defaultinventairebook.png b/front/public/defaultinventairebook.png new file mode 100644 index 0000000000000000000000000000000000000000..d76c53f9db748c12e6cc3f3e5e1fe7b423ea69fd GIT binary patch literal 22180 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 literal 0 HcmV?d00001 diff --git a/front/src/BookListElement.vue b/front/src/BookListElement.vue index c9812dc..4a0c378 100644 --- a/front/src/BookListElement.vue +++ b/front/src/BookListElement.vue @@ -32,7 +32,7 @@ function openBook() { if (props.id != 0) { router.push(`/book/${props.id}`); } else { - router.push(`/importinventaire/${props.inventaireid}`) + router.push(`/import/inventaire/${props.inventaireid}`) } } diff --git a/front/src/ImportInventaire.vue b/front/src/ImportInventaire.vue new file mode 100644 index 0000000..9d2353c --- /dev/null +++ b/front/src/ImportInventaire.vue @@ -0,0 +1,68 @@ + + + + + + diff --git a/front/src/ImportListElement.vue b/front/src/ImportListElement.vue new file mode 100644 index 0000000..9abb5d0 --- /dev/null +++ b/front/src/ImportListElement.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/front/src/api.js b/front/src/api.js index 7871494..c0ee8b0 100644 --- a/front/src/api.js +++ b/front/src/api.js @@ -2,9 +2,17 @@ import { useAuthStore } from './auth.store.js' const baseUrl = "http://localhost:8080" +export function getInventaireImagePathOrDefault(path) { + return getImagePathOrGivenDefault(path, "../../defaultinventairebook.png") +} + export function getImagePathOrDefault(path) { + return getImagePathOrGivenDefault(path, "../defaultbook.png") +} + +export function getImagePathOrGivenDefault(path, defaultpath) { if (path == "" || typeof path === 'undefined') { - return "../defaultbook.png"; + return defaultpath; } else if (path.startsWith("https://")) { return path; } else { @@ -38,6 +46,11 @@ export function getSearchBooks(data, error, searchterm, lang, limit, offset) { return useFetch(data, error, baseUrl + '/search/' + encodeURIComponent(searchterm) + "?" + queryParams.toString()); } +export function getInventaireEditionBooks(data, error, inventaireId, lang, limit, offset) { + const queryParams = new URLSearchParams({lang: lang, limit: limit, offset: offset}); + return useFetch(data, error, baseUrl + '/inventaire/books/' + encodeURIComponent(inventaireId) + "?" + queryParams.toString()); +} + export function getAuthor(data, error, id) { return useFetch(data, error, baseUrl + '/author/' + id); } diff --git a/front/src/locales/en.json b/front/src/locales/en.json index c533d07..2588da8 100644 --- a/front/src/locales/en.json +++ b/front/src/locales/en.json @@ -58,8 +58,16 @@ "goto":"Goto page {pageNumber}", "page":"Page {pageNumber}" }, - "bookdatewidget" :{ + "bookdatewidget": { "started": "Started at :", "finished": "Finished at :" + }, + "importinventaire": { + "title":"Please select a book to import" + }, + "importlistelement": { + "releasedate":"Release date:", + "publisher":"Publisher:" } + } diff --git a/front/src/locales/fr.json b/front/src/locales/fr.json index 9abb105..5b30cdf 100644 --- a/front/src/locales/fr.json +++ b/front/src/locales/fr.json @@ -58,8 +58,15 @@ "goto":"Aller à la page {pageNumber}", "page":"Page {pageNumber}" }, - "bookdatewidget" :{ + "bookdatewidget": { "started": "Commencé le :", "finished": "Fini le :" + }, + "importinventaire": { + "title":"Sélectionner l'édition à importer" + }, + "importlistelement": { + "releasedate":"Date de publication : ", + "publisher":"Maison d'édition : " } } diff --git a/front/src/router.js b/front/src/router.js index c3af796..676013c 100644 --- a/front/src/router.js +++ b/front/src/router.js @@ -8,6 +8,7 @@ import SignUp from './SignUp.vue' import LogIn from './LogIn.vue' import Home from './Home.vue' import SearchBook from './SearchBook.vue' +import ImportInventaire from './ImportInventaire.vue' import InventaireImport from './InventaireImport.vue' import { useAuthStore } from './auth.store' @@ -18,6 +19,7 @@ const routes = [ { path: '/importinventaire/:inventaireid', component: InventaireImport, props: true }, { path: '/author/:id', component: AuthorForm, props: true }, { path: '/search/:searchterm', component: SearchBook, props: true }, + { path: '/import/inventaire/:inventaireid', component: ImportInventaire, props: true }, { path: '/add', component: AddBook }, { path: '/signup', component: SignUp }, { path: '/login', component: LogIn }, diff --git a/internal/inventaire/inventaire.go b/internal/inventaire/inventaire.go index c835bad..3ea5ffe 100644 --- a/internal/inventaire/inventaire.go +++ b/internal/inventaire/inventaire.go @@ -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"` diff --git a/internal/inventaire/inventaire_test.go b/internal/inventaire/inventaire_test.go index be289c8..a3f0bdc 100644 --- a/internal/inventaire/inventaire_test.go +++ b/internal/inventaire/inventaire_test.go @@ -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]) +} diff --git a/internal/inventaire/inventaireedition.go b/internal/inventaire/inventaireedition.go new file mode 100644 index 0000000..6c2d41a --- /dev/null +++ b/internal/inventaire/inventaireedition.go @@ -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 +} diff --git a/internal/routes/booksinventaireget.go b/internal/routes/booksinventaireget.go new file mode 100644 index 0000000..2b48995 --- /dev/null +++ b/internal/routes/booksinventaireget.go @@ -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) +} diff --git a/internal/setup/setup.go b/internal/setup/setup.go index 785c39c..fb72c86 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -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}) })