From 624dfe0faaea6d27ca2a667856c634e989c91f2e Mon Sep 17 00:00:00 2001 From: Arthur Lefebvre Date: Tue, 25 Nov 2025 14:14:24 +0100 Subject: [PATCH] Add basic author form --- demodata.sql | 4 ++- front/src/AuthorForm.vue | 30 +++++++++++++++++ front/src/api.js | 4 +++ front/src/locales/en.json | 3 ++ front/src/locales/fr.json | 3 ++ front/src/router.js | 3 +- internal/apitest/get_author_test.go | 51 +++++++++++++++++++++++++++++ internal/routes/authorget.go | 38 +++++++++++++++++++++ internal/routes/bookget.go | 2 +- internal/setup/setup.go | 3 ++ 10 files changed, 138 insertions(+), 3 deletions(-) create mode 100644 front/src/AuthorForm.vue create mode 100644 internal/apitest/get_author_test.go create mode 100644 internal/routes/authorget.go diff --git a/demodata.sql b/demodata.sql index 892ba21..5497239 100644 --- a/demodata.sql +++ b/demodata.sql @@ -36,7 +36,9 @@ INSERT INTO static_files(name, path) VALUES ('Recherches-philosophiques.jpg', 'R INSERT INTO static_files(name, path) VALUES ('le_chateau.jpg', 'le_chateau.jpg'); -- authors -INSERT INTO authors(created_at, name) VALUES ('NOW', 'Jean-Patrick Manchette'); +INSERT INTO authors(created_at, name, description) VALUES ('NOW', 'Jean-Patrick Manchette', 'Jean-Patrick Manchette, né le 19 décembre 1942 à Marseille et mort le 3 juin 1995 à Paris 12e, est un écrivain français, auteur de romans policiers, critique littéraire et de cinéma, scénariste et dialoguiste de cinéma, et traducteur. + +Considéré comme l''un des auteurs les plus marquants du polar français des années 1970-1980, il est également connu pour ses opinions libertaires d''extrême gauche, proches de l''Internationale situationniste. Sur la couverture de la plupart de ses ouvrages, il est crédité en tant que J.P. Manchette, ou J-P Manchette.'); INSERT INTO authors(created_at, name) VALUES ('NOW', 'Louis-Ferdinand Céline'); INSERT INTO authors(created_at, name) VALUES ('NOW', 'Anatole France'); INSERT INTO authors(created_at, name) VALUES ('NOW', 'Marguerite Duras'); diff --git a/front/src/AuthorForm.vue b/front/src/AuthorForm.vue new file mode 100644 index 0000000..2b086ca --- /dev/null +++ b/front/src/AuthorForm.vue @@ -0,0 +1,30 @@ + + + + + diff --git a/front/src/api.js b/front/src/api.js index a784e7e..191991e 100644 --- a/front/src/api.js +++ b/front/src/api.js @@ -41,6 +41,10 @@ export function getSearchBooks(data, error, searchterm, limit, offset) { return useFetch(data, error, baseUrl + '/search/' + encodeURIComponent(searchterm) + "?" + queryParams.toString()); } +export function getAuthor(data, error, id) { + return useFetch(data, error, baseUrl + '/author/' + id); +} + export function getBook(data, error, id) { return useFetch(data, error, baseUrl + '/book/' + id); } diff --git a/front/src/locales/en.json b/front/src/locales/en.json index b326ea4..c533d07 100644 --- a/front/src/locales/en.json +++ b/front/src/locales/en.json @@ -43,6 +43,9 @@ "startread": "Start reading", "wantread": "I want to read it" }, + "authorform": { + "error": "Erreur when loading author: {error}" + }, "bookform": { "error": "Error when loading book: {error}", "read": "Read", diff --git a/front/src/locales/fr.json b/front/src/locales/fr.json index 0ea2f79..9abb105 100644 --- a/front/src/locales/fr.json +++ b/front/src/locales/fr.json @@ -43,6 +43,9 @@ "startread": "Commencer la lecture", "wantread": "Je veux le lire" }, + "authorform": { + "error": "Erreur pendant le chargement de l'auteur: {error}" + }, "bookform": { "error": "Erreur pendant le chargement du livre: {error}", "read": "Lu", diff --git a/front/src/router.js b/front/src/router.js index a017e2b..33a9d02 100644 --- a/front/src/router.js +++ b/front/src/router.js @@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router' import BooksBrowser from './BooksBrowser.vue' import AddBook from './AddBook.vue' +import AuthorForm from './AuthorForm.vue' import BookForm from './BookForm.vue' import SignUp from './SignUp.vue' import LogIn from './LogIn.vue' @@ -13,11 +14,11 @@ const routes = [ { path: '/', component: Home }, { path: '/books', component: BooksBrowser }, { path: '/book/:id', component: BookForm, props: true }, + { path: '/author/:id', component: AuthorForm, props: true }, { path: '/search/:searchterm', component: SearchBook, props: true }, { path: '/add', component: AddBook }, { path: '/signup', component: SignUp }, { path: '/login', component: LogIn }, - { path: '/book', component: LogIn }, ] export const router = createRouter({ diff --git a/internal/apitest/get_author_test.go b/internal/apitest/get_author_test.go new file mode 100644 index 0000000..db8b66c --- /dev/null +++ b/internal/apitest/get_author_test.go @@ -0,0 +1,51 @@ +package apitest + +import ( + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "testing" + + "git.artlef.fr/PersonalLibraryManager/internal/testutils" + "github.com/stretchr/testify/assert" +) + +type fetchedAuthor struct { + Name string + Description string +} + +func TestGetAuthor_Ok(t *testing.T) { + author := testGetAuthor(t, "1", http.StatusOK) + expectedDescription := `Jean-Patrick Manchette, né le 19 décembre 1942 à Marseille et mort le 3 juin 1995 à Paris 12e, est un écrivain français, auteur de romans policiers, critique littéraire et de cinéma, scénariste et dialoguiste de cinéma, et traducteur. + +Considéré comme l'un des auteurs les plus marquants du polar français des années 1970-1980, il est également connu pour ses opinions libertaires d'extrême gauche, proches de l'Internationale situationniste. Sur la couverture de la plupart de ses ouvrages, il est crédité en tant que J.P. Manchette, ou J-P Manchette.` + assert.Equal(t, fetchedAuthor{Name: "Jean-Patrick Manchette", Description: expectedDescription}, author) +} + +func TestGetAuthor_IdNotFound(t *testing.T) { + testGetAuthor(t, "46544", http.StatusNotFound) +} + +func TestGetAuthor_IdNotInt(t *testing.T) { + testGetAuthor(t, "wrong", http.StatusBadRequest) +} + +func testGetAuthor(t *testing.T, authorId string, status int) fetchedAuthor { + router := testutils.TestSetup() + + token := testutils.ConnectDemoUser(router) + req, _ := http.NewRequest("GET", "/author/"+authorId, nil) + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) + w := httptest.NewRecorder() + router.ServeHTTP(w, req) + + var author fetchedAuthor + err := json.Unmarshal(w.Body.Bytes(), &author) + if err != nil { + t.Error(err) + } + assert.Equal(t, status, w.Code) + return author +} diff --git a/internal/routes/authorget.go b/internal/routes/authorget.go new file mode 100644 index 0000000..eaba881 --- /dev/null +++ b/internal/routes/authorget.go @@ -0,0 +1,38 @@ +package routes + +import ( + "net/http" + "strconv" + + "git.artlef.fr/PersonalLibraryManager/internal/appcontext" + "git.artlef.fr/PersonalLibraryManager/internal/model" + "git.artlef.fr/PersonalLibraryManager/internal/myvalidator" + "github.com/gin-gonic/gin" +) + +type AuthorGet struct { + Name string `json:"name" binding:"required,max=100"` + Description string `json:"description"` +} + +func GetAuthorHandler(ac appcontext.AppContext) { + authorId, err := strconv.ParseUint(ac.C.Param("id"), 10, 64) + if err != nil { + ac.C.JSON(http.StatusBadRequest, gin.H{"error": err}) + return + } + err = myvalidator.ValidateId(ac.Db, uint(authorId), &model.Author{}) + if err != nil { + myvalidator.ReturnErrorsAsJsonResponse(&ac, err) + return + } + var author model.Author + res := ac.Db.First(&author, authorId) + if res.Error != nil { + myvalidator.ReturnErrorsAsJsonResponse(&ac, res.Error) + return + } + ac.C.JSON(http.StatusOK, AuthorGet{ + Name: author.Name, + Description: author.Description}) +} diff --git a/internal/routes/bookget.go b/internal/routes/bookget.go index cda15f7..24562bc 100644 --- a/internal/routes/bookget.go +++ b/internal/routes/bookget.go @@ -29,7 +29,7 @@ func GetBookHandler(ac appcontext.AppContext) { } book, queryErr := query.FetchBookGet(ac.Db, user.ID, bookId) if queryErr != nil { - myvalidator.ReturnErrorsAsJsonResponse(&ac, err) + myvalidator.ReturnErrorsAsJsonResponse(&ac, queryErr) return } ac.C.JSON(http.StatusOK, book) diff --git a/internal/setup/setup.go b/internal/setup/setup.go index 5460042..ff2cad3 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -66,6 +66,9 @@ func Setup(config *config.Config) *gin.Engine { r.POST("/book", func(c *gin.Context) { routes.PostBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config}) }) + r.GET("/author/:id", func(c *gin.Context) { + routes.GetAuthorHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config}) + }) r.POST("/auth/signup", func(c *gin.Context) { routes.PostSignupHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config}) })