Book form: can now edit an existing book
This commit is contained in:
@@ -1,11 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed } from 'vue'
|
import { ref, reactive, computed } from 'vue'
|
||||||
import { postBook, extractFormErrorFromField } from './api.js'
|
import { postBook, putBook, extractFormErrorFromField, getBookCall } from './api.js'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import CoverUpload from './CoverUpload.vue'
|
import CoverUpload from './CoverUpload.vue'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String,
|
||||||
|
})
|
||||||
|
|
||||||
|
const fetchError = ref(null)
|
||||||
|
|
||||||
const book = ref({
|
const book = ref({
|
||||||
title: '',
|
title: '',
|
||||||
author: '',
|
author: '',
|
||||||
@@ -16,6 +22,31 @@ const book = ref({
|
|||||||
summary: '',
|
summary: '',
|
||||||
coverId: null,
|
coverId: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (props.id) {
|
||||||
|
getBookCall(props.id)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === 401) {
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
authStore.logout()
|
||||||
|
}
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then(fillBookWithJson)
|
||||||
|
.catch((err) => (fetchError.value = err))
|
||||||
|
}
|
||||||
|
|
||||||
|
function fillBookWithJson(json) {
|
||||||
|
book.value.title = json.title
|
||||||
|
book.value.author = json.author
|
||||||
|
book.value.isbn = json.isbn
|
||||||
|
book.value.inventaireid = json.inventaireid
|
||||||
|
book.value.openlibraryid = json.openlibraryid
|
||||||
|
book.value.shortdescription = json.shortdescription
|
||||||
|
book.value.summary = json.summary
|
||||||
|
book.value.coverId = json.coverId
|
||||||
|
}
|
||||||
|
|
||||||
const errors = ref(null)
|
const errors = ref(null)
|
||||||
const titleError = computed(() => {
|
const titleError = computed(() => {
|
||||||
return extractFormErrorFromField('Title', errors.value)
|
return extractFormErrorFromField('Title', errors.value)
|
||||||
@@ -39,20 +70,39 @@ const summaryError = computed(() => {
|
|||||||
return extractFormErrorFromField('ShortDescription', errors.value)
|
return extractFormErrorFromField('ShortDescription', errors.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function postOrPutBook(book) {
|
||||||
|
if (props.id) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
return postBook(book)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function onSubmit(e) {
|
function onSubmit(e) {
|
||||||
postBook(book).then((res) => {
|
if (props.id) {
|
||||||
if (res.ok) {
|
putBook(props.id, book).then((res) => {
|
||||||
res.json().then((json) => router.push('/book/' + json.id))
|
if (res.ok) {
|
||||||
return
|
router.push('/book/' + props.id)
|
||||||
} else {
|
} else {
|
||||||
res.json().then((json) => (errors.value = json))
|
res.json().then((json) => (errors.value = json))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
postBook(book).then((res) => {
|
||||||
|
if (res.ok) {
|
||||||
|
res.json().then((json) => router.push('/book/' + json.id))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
res.json().then((json) => (errors.value = json))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form @submit.prevent="onSubmit">
|
<div v-if="error">{{ $t('bookform.error', { error: fetchError.message }) }}</div>
|
||||||
|
<form v-else @submit.prevent="onSubmit">
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label">{{ $t('addbook.title') }}</label>
|
<label class="label">{{ $t('addbook.title') }}</label>
|
||||||
<div class="control">
|
<div class="control">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
putEndReadDateUnset,
|
putEndReadDateUnset,
|
||||||
putUnreadBook,
|
putUnreadBook,
|
||||||
} from './api.js'
|
} from './api.js'
|
||||||
import { useRouter, onBeforeRouteUpdate } from 'vue-router'
|
import { useRouter, onBeforeRouteUpdate, RouterLink } from 'vue-router'
|
||||||
import { VRating } from 'vuetify/components/VRating'
|
import { VRating } from 'vuetify/components/VRating'
|
||||||
import BookFormIcons from './BookFormIcons.vue'
|
import BookFormIcons from './BookFormIcons.vue'
|
||||||
import ReviewWidget from './ReviewWidget.vue'
|
import ReviewWidget from './ReviewWidget.vue'
|
||||||
@@ -105,6 +105,14 @@ function goToAuthor() {
|
|||||||
<figure class="image">
|
<figure class="image">
|
||||||
<img v-bind:src="imagePathOrDefault" v-bind:alt="data.title" />
|
<img v-bind:src="imagePathOrDefault" v-bind:alt="data.title" />
|
||||||
</figure>
|
</figure>
|
||||||
|
<div class="centered mt-2">
|
||||||
|
<RouterLink :to="'/book/' + props.id + '/edit'">
|
||||||
|
<span>
|
||||||
|
<b-icon-pencil-fill />
|
||||||
|
</span>
|
||||||
|
Modifier le livre
|
||||||
|
</RouterLink>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<h3 class="title">{{ data.title }}</h3>
|
<h3 class="title">{{ data.title }}</h3>
|
||||||
|
|||||||
@@ -18,28 +18,34 @@ export function getImagePathOrGivenDefault(path, defaultpath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function useFetch(data, error, url) {
|
function userFetch(url) {
|
||||||
const { user } = useAuthStore()
|
const { user } = useAuthStore()
|
||||||
|
|
||||||
if (user != null) {
|
if (user != null) {
|
||||||
fetch(url, {
|
return fetch(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: 'Bearer ' + user.token,
|
Authorization: 'Bearer ' + user.token,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.then((res) => {
|
} else {
|
||||||
if (res.status === 401) {
|
return Promise.resolve()
|
||||||
const authStore = useAuthStore()
|
|
||||||
authStore.logout()
|
|
||||||
}
|
|
||||||
return res.json()
|
|
||||||
})
|
|
||||||
.then((json) => (data.value = json))
|
|
||||||
.catch((err) => (error.value = err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useFetch(data, error, url) {
|
||||||
|
userFetch(url)
|
||||||
|
.then((res) => {
|
||||||
|
if (res.status === 401) {
|
||||||
|
const authStore = useAuthStore()
|
||||||
|
authStore.logout()
|
||||||
|
}
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then((json) => (data.value = json))
|
||||||
|
.catch((err) => (error.value = err))
|
||||||
|
}
|
||||||
|
|
||||||
export async function getAppInfo(appInfo, appInfoErr) {
|
export async function getAppInfo(appInfo, appInfoErr) {
|
||||||
return fetch('/ws/appinfo', {
|
return fetch('/ws/appinfo', {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
@@ -98,6 +104,10 @@ export function getBook(data, error, id) {
|
|||||||
return useFetch(data, error, '/ws/book/' + id)
|
return useFetch(data, error, '/ws/book/' + id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getBookCall(id) {
|
||||||
|
return userFetch('/ws/book/' + id)
|
||||||
|
}
|
||||||
|
|
||||||
export function postBook(book) {
|
export function postBook(book) {
|
||||||
return genericPayloadCall('/ws/book', book.value, 'POST')
|
return genericPayloadCall('/ws/book', book.value, 'POST')
|
||||||
}
|
}
|
||||||
@@ -106,6 +116,10 @@ export async function postImportBook(id, language) {
|
|||||||
return genericPayloadCall('/ws/importbook', { inventaireid: id, lang: language }, 'POST')
|
return genericPayloadCall('/ws/importbook', { inventaireid: id, lang: language }, 'POST')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function putBook(id, book) {
|
||||||
|
return genericPayloadCall('/ws/book/edit/' + id, book.value, 'PUT')
|
||||||
|
}
|
||||||
|
|
||||||
export async function putReadBook(bookId) {
|
export async function putReadBook(bookId) {
|
||||||
return putEndReadDate(bookId, new Date().toISOString().slice(0, 10))
|
return putEndReadDate(bookId, new Date().toISOString().slice(0, 10))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ const routes = [
|
|||||||
{ path: '/browse', component: InstanceBrowser },
|
{ path: '/browse', component: InstanceBrowser },
|
||||||
{ path: '/books', component: BooksBrowser },
|
{ path: '/books', component: BooksBrowser },
|
||||||
{ path: '/book/:id', component: BookFormView, props: true },
|
{ path: '/book/:id', component: BookFormView, props: true },
|
||||||
|
{ path: '/book/:id/edit', component: BookFormEdit, props: true },
|
||||||
{ path: '/author/:id', component: AuthorForm, props: true },
|
{ path: '/author/:id', component: AuthorForm, props: true },
|
||||||
{ path: '/search/:searchterm', component: SearchBook, props: true },
|
{ path: '/search/:searchterm', component: SearchBook, props: true },
|
||||||
{ path: '/import/inventaire/:inventaireid', component: ImportInventaire, props: true },
|
{ path: '/import/inventaire/:inventaireid', component: ImportInventaire, props: true },
|
||||||
|
|||||||
63
internal/adapter/adapter.go
Normal file
63
internal/adapter/adapter.go
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
package adapter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"git.artlef.fr/bibliomane/internal/appcontext"
|
||||||
|
"git.artlef.fr/bibliomane/internal/dto"
|
||||||
|
"git.artlef.fr/bibliomane/internal/model"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FillBookDbFromFields(ac appcontext.AppContext, fields *dto.BookFields, book *model.Book) error {
|
||||||
|
if fields.Title != nil {
|
||||||
|
book.Title = *fields.Title
|
||||||
|
}
|
||||||
|
if fields.ISBN != nil {
|
||||||
|
book.ISBN = *fields.ISBN
|
||||||
|
}
|
||||||
|
if fields.InventaireID != nil {
|
||||||
|
book.InventaireID = *fields.InventaireID
|
||||||
|
}
|
||||||
|
if fields.OpenLibraryId != nil {
|
||||||
|
book.OpenLibraryId = *fields.OpenLibraryId
|
||||||
|
}
|
||||||
|
if fields.ShortDescription != nil {
|
||||||
|
book.SmallDescription = *fields.ShortDescription
|
||||||
|
}
|
||||||
|
if fields.Summary != nil {
|
||||||
|
book.Summary = *fields.Summary
|
||||||
|
}
|
||||||
|
if fields.CoverID != nil {
|
||||||
|
book.CoverID = *fields.CoverID
|
||||||
|
}
|
||||||
|
|
||||||
|
if fields.Author != nil {
|
||||||
|
author, err := fetchOrCreateAuthor(ac, *fields.Author)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
book.AuthorID = author.ID
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchOrCreateAuthor(ac appcontext.AppContext, name string) (*model.Author, error) {
|
||||||
|
var author model.Author
|
||||||
|
res := ac.Db.Where("name = ?", name).First(&author)
|
||||||
|
err := res.Error
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
author = model.Author{Name: name}
|
||||||
|
err = ac.Db.Save(&author).Error
|
||||||
|
if err != nil {
|
||||||
|
return &author, err
|
||||||
|
}
|
||||||
|
return &author, nil
|
||||||
|
} else {
|
||||||
|
return &author, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return &author, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.artlef.fr/bibliomane/internal/dto"
|
|
||||||
"git.artlef.fr/bibliomane/internal/testutils"
|
"git.artlef.fr/bibliomane/internal/testutils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
@@ -62,20 +61,12 @@ func TestPostBookHandler_AllFields(t *testing.T) {
|
|||||||
id := testPostBookHandler(t, bookJson, 200)
|
id := testPostBookHandler(t, bookJson, 200)
|
||||||
createdBook := testGetBook(t, strconv.FormatUint(uint64(id), 10), http.StatusOK)
|
createdBook := testGetBook(t, strconv.FormatUint(uint64(id), 10), http.StatusOK)
|
||||||
|
|
||||||
assert.Equal(t,
|
assert.Equal(t, "Amerika", createdBook.Title)
|
||||||
dto.FullBookGet{
|
assert.Equal(t, "Kafka", createdBook.Author)
|
||||||
Title: "Amerika",
|
assert.Equal(t, "978-2-07-036803-7", createdBook.ISBN)
|
||||||
Author: "Kafka",
|
assert.Equal(t, "isbn:9782070368037", createdBook.InventaireId)
|
||||||
AuthorID: 27,
|
assert.Equal(t, "OL8838048M", createdBook.OpenLibraryId)
|
||||||
ISBN: "978-2-07-036803-7",
|
assert.Equal(t, "L'Amérique (Amerika en version originale allemande) ou Le Disparu (Der Verschollene, titre voulu par l'auteur et rendu au livre dans ses plus récentes éditions) est le premier roman de Franz Kafka (1883-1924).", createdBook.Summary)
|
||||||
InventaireId: "isbn:9782070368037",
|
|
||||||
OpenLibraryId: "OL8838048M",
|
|
||||||
Summary: "L'Amérique (Amerika en version originale allemande) ou Le Disparu (Der Verschollene, titre voulu par l'auteur et rendu au livre dans ses plus récentes éditions) est le premier roman de Franz Kafka (1883-1924).",
|
|
||||||
Rating: 0,
|
|
||||||
Read: false,
|
|
||||||
CoverPath: "",
|
|
||||||
Review: "",
|
|
||||||
}, createdBook)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPostBookHandler_TitleTooLong(t *testing.T) {
|
func TestPostBookHandler_TitleTooLong(t *testing.T) {
|
||||||
|
|||||||
56
internal/apitest/put_book_test.go
Normal file
56
internal/apitest/put_book_test.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
package apitest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.artlef.fr/bibliomane/internal/testutils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPutBookHandler_TitleChange(t *testing.T) {
|
||||||
|
bookId := "17"
|
||||||
|
bookJson :=
|
||||||
|
`{
|
||||||
|
"title": "Le coup de pistolaid"
|
||||||
|
}`
|
||||||
|
testPutBook(t, bookJson, bookId, 200)
|
||||||
|
modifiedBook := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, "Le coup de pistolaid", modifiedBook.Title)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutBookHandler_Author(t *testing.T) {
|
||||||
|
bookId := "17"
|
||||||
|
bookJson :=
|
||||||
|
`{
|
||||||
|
"author": "Alexander Pouchkine"
|
||||||
|
}`
|
||||||
|
testPutBook(t, bookJson, bookId, 200)
|
||||||
|
modifiedBook := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, "Alexander Pouchkine", modifiedBook.Author)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutBookHandler_MultipleFields(t *testing.T) {
|
||||||
|
bookId := "17"
|
||||||
|
bookJson :=
|
||||||
|
`{
|
||||||
|
"title": "Le pistolet",
|
||||||
|
"author": "Pouchkine",
|
||||||
|
"isbn": "978-2-07-036803-7",
|
||||||
|
"inventaireid": "isbn:9782070368037",
|
||||||
|
"openlibraryid": "OL8838048M",
|
||||||
|
"shortdescription": "Roman de Pouchkine",
|
||||||
|
"summary": "En garnison dans une petite ville, un officier de l'armée impériale russe rencontre Silvio, ancien soldat et tireur exceptionnel. Celui-ci fait forte impression sur lui, jusqu'au jour où il refuse, à la suite d'un affront, de se battre en duel."
|
||||||
|
}`
|
||||||
|
testPutBook(t, bookJson, bookId, 200)
|
||||||
|
modifiedBook := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, "Le pistolet", modifiedBook.Title)
|
||||||
|
assert.Equal(t, "Pouchkine", modifiedBook.Author)
|
||||||
|
assert.Equal(t, "978-2-07-036803-7", modifiedBook.ISBN)
|
||||||
|
assert.Equal(t, "OL8838048M", modifiedBook.OpenLibraryId)
|
||||||
|
assert.Equal(t, "En garnison dans une petite ville, un officier de l'armée impériale russe rencontre Silvio, ancien soldat et tireur exceptionnel. Celui-ci fait forte impression sur lui, jusqu'au jour où il refuse, à la suite d'un affront, de se battre en duel.", modifiedBook.Summary)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPutBook(t *testing.T, payload string, bookId string, expectedCode int) {
|
||||||
|
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/ws/book/edit/"+bookId)
|
||||||
|
}
|
||||||
@@ -10,15 +10,15 @@ type BookSearchGetParam struct {
|
|||||||
Inventaire bool `form:"inventaire"`
|
Inventaire bool `form:"inventaire"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BookPostCreate struct {
|
type BookFields struct {
|
||||||
Title string `json:"title" binding:"required,max=300"`
|
Title *string `json:"title" binding:"omitempty,max=300"`
|
||||||
Author string `json:"author" binding:"max=100"`
|
Author *string `json:"author" binding:"omitempty,max=100"`
|
||||||
ISBN string `json:"isbn" binding:"max=18"`
|
ISBN *string `json:"isbn" binding:"omitempty,max=18"`
|
||||||
InventaireID string `json:"inventaireid" binding:"max=50"`
|
InventaireID *string `json:"inventaireid" binding:"omitempty,max=50"`
|
||||||
OpenLibraryId string `json:"openlibraryid" binding:"max=50"`
|
OpenLibraryId *string `json:"openlibraryid" binding:"omitempty,max=50"`
|
||||||
ShortDescription string `json:"shortdescription" binding:"max=300"`
|
ShortDescription *string `json:"shortdescription" binding:"omitempty,max=300"`
|
||||||
Summary string `json:"summary"`
|
Summary *string `json:"summary"`
|
||||||
CoverID uint `json:"coverId"`
|
CoverID *uint `json:"coverId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BookPostImport struct {
|
type BookPostImport struct {
|
||||||
|
|||||||
@@ -4,26 +4,38 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"git.artlef.fr/bibliomane/internal/adapter"
|
||||||
"git.artlef.fr/bibliomane/internal/appcontext"
|
"git.artlef.fr/bibliomane/internal/appcontext"
|
||||||
"git.artlef.fr/bibliomane/internal/dto"
|
"git.artlef.fr/bibliomane/internal/dto"
|
||||||
|
"git.artlef.fr/bibliomane/internal/i18nresource"
|
||||||
"git.artlef.fr/bibliomane/internal/model"
|
"git.artlef.fr/bibliomane/internal/model"
|
||||||
"git.artlef.fr/bibliomane/internal/myvalidator"
|
"git.artlef.fr/bibliomane/internal/myvalidator"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func PostBookHandler(ac appcontext.AppContext) {
|
func PostBookHandler(ac appcontext.AppContext) {
|
||||||
var book dto.BookPostCreate
|
var book dto.BookFields
|
||||||
err := ac.C.ShouldBindJSON(&book)
|
err := ac.C.ShouldBindJSON(&book)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = myvalidator.ValidateId(ac.Db, book.CoverID, &model.StaticFile{})
|
//when creating a book, title is required
|
||||||
if err != nil {
|
if book.Title == nil {
|
||||||
|
err = myvalidator.HttpError{
|
||||||
|
StatusCode: http.StatusBadRequest,
|
||||||
|
Err: errors.New(i18nresource.GetTranslatedMessage(&ac, "ValidationRequired")),
|
||||||
|
}
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if book.CoverID != nil {
|
||||||
|
err = myvalidator.ValidateId(ac.Db, *book.CoverID, &model.StaticFile{})
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
user, fetchUserErr := ac.GetAuthenticatedUser()
|
user, fetchUserErr := ac.GetAuthenticatedUser()
|
||||||
if fetchUserErr != nil {
|
if fetchUserErr != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
@@ -38,44 +50,15 @@ func PostBookHandler(ac appcontext.AppContext) {
|
|||||||
ac.C.JSON(http.StatusOK, gin.H{"id": id})
|
ac.C.JSON(http.StatusOK, gin.H{"id": id})
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveBookToDb(ac appcontext.AppContext, b dto.BookPostCreate, user *model.User) (uint, error) {
|
func saveBookToDb(ac appcontext.AppContext, b dto.BookFields, user *model.User) (uint, error) {
|
||||||
author, err := fetchOrCreateAuthor(ac, b.Author)
|
book := model.Book{
|
||||||
|
AddedBy: *user,
|
||||||
|
}
|
||||||
|
err := adapter.FillBookDbFromFields(ac, &b, &book)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
book := model.Book{
|
|
||||||
Title: b.Title,
|
|
||||||
AuthorID: author.ID,
|
|
||||||
ISBN: b.ISBN,
|
|
||||||
InventaireID: b.InventaireID,
|
|
||||||
OpenLibraryId: b.OpenLibraryId,
|
|
||||||
SmallDescription: b.ShortDescription,
|
|
||||||
Summary: b.Summary,
|
|
||||||
AddedBy: *user,
|
|
||||||
}
|
|
||||||
if b.CoverID > 0 {
|
|
||||||
book.CoverID = b.CoverID
|
|
||||||
}
|
|
||||||
err = ac.Db.Save(&book).Error
|
err = ac.Db.Save(&book).Error
|
||||||
return book.ID, err
|
return book.ID, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchOrCreateAuthor(ac appcontext.AppContext, name string) (*model.Author, error) {
|
|
||||||
var author model.Author
|
|
||||||
res := ac.Db.Where("name = ?", name).First(&author)
|
|
||||||
err := res.Error
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
author = model.Author{Name: name}
|
|
||||||
err = ac.Db.Save(&author).Error
|
|
||||||
if err != nil {
|
|
||||||
return &author, err
|
|
||||||
}
|
|
||||||
return &author, nil
|
|
||||||
} else {
|
|
||||||
return &author, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return &author, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
43
internal/routes/bookputupdate.go
Normal file
43
internal/routes/bookputupdate.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"git.artlef.fr/bibliomane/internal/adapter"
|
||||||
|
"git.artlef.fr/bibliomane/internal/appcontext"
|
||||||
|
"git.artlef.fr/bibliomane/internal/dto"
|
||||||
|
"git.artlef.fr/bibliomane/internal/model"
|
||||||
|
"git.artlef.fr/bibliomane/internal/myvalidator"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PutBookHandler(ac appcontext.AppContext) {
|
||||||
|
bookId64, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
|
||||||
|
bookId := uint(bookId64)
|
||||||
|
if err != nil {
|
||||||
|
ac.C.JSON(http.StatusBadRequest, gin.H{"error": err})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var book model.Book
|
||||||
|
err = ac.Db.First(&book, bookId).Error
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var bookPut dto.BookFields
|
||||||
|
err = ac.C.ShouldBindJSON(&bookPut)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = adapter.FillBookDbFromFields(ac, &bookPut, &book)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ac.Db.Save(&book)
|
||||||
|
ac.C.String(http.StatusOK, "Success")
|
||||||
|
}
|
||||||
@@ -63,6 +63,9 @@ func Setup(config *config.Config) *gin.Engine {
|
|||||||
ws.PUT("/book/:id", func(c *gin.Context) {
|
ws.PUT("/book/:id", func(c *gin.Context) {
|
||||||
routes.PutUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.PutUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
})
|
})
|
||||||
|
ws.PUT("/book/edit/:id", func(c *gin.Context) {
|
||||||
|
routes.PutBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
|
})
|
||||||
ws.POST("/book", func(c *gin.Context) {
|
ws.POST("/book", func(c *gin.Context) {
|
||||||
routes.PostBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.PostBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user