Make "want read" button work
This commit is contained in:
@@ -36,7 +36,7 @@ INSERT INTO static_files(name, path) VALUES ('noisy.jpg', 'noisy.jpg');
|
|||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'O dingos, o chateaux!','Jean-Patrick Manchette', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'odingosochateaux.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'O dingos, o chateaux!','Jean-Patrick Manchette', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'odingosochateaux.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'O dingos, o chateaux!'), true,7);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'O dingos, o chateaux!'), true,7);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Le petit bleu de la côte Ouest','Jean-Patrick Manchette', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'le-petit-bleu-de-la-cote-ouest.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Le petit bleu de la côte Ouest','Jean-Patrick Manchette', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'le-petit-bleu-de-la-cote-ouest.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Le petit bleu de la côte Ouest'), true,7);
|
INSERT INTO user_books(created_at, user_id, book_id, want_read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Le petit bleu de la côte Ouest'), true,7);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'D''un château l''autre','Louis-Ferdinand Céline', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'dunchateaulautre.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'D''un château l''autre','Louis-Ferdinand Céline', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'dunchateaulautre.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'D''un château l''autre'), true,10);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'D''un château l''autre'), true,10);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Les dieux ont soif','Anatole France', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lesdieuxontsoif.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Les dieux ont soif','Anatole France', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lesdieuxontsoif.jpg'));
|
||||||
@@ -46,7 +46,7 @@ INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW'
|
|||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Un barrage contre le Pacifique','Marguerite Duras', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'Un_barrage_contre_le_Pacifique.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Un barrage contre le Pacifique','Marguerite Duras', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'Un_barrage_contre_le_Pacifique.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Un barrage contre le Pacifique'), true,7);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Un barrage contre le Pacifique'), true,7);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Salammbô','Flaubert Gustave', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'salammbo.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Salammbô','Flaubert Gustave', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'salammbo.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Salammbô'), true,8);
|
INSERT INTO user_books(created_at, user_id, book_id, want_read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Salammbô'), true,8);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Langage Machine','Romain Lucazeau', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'Langage Machine.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Langage Machine','Romain Lucazeau', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'Langage Machine.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Langage Machine'), true,5);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Langage Machine'), true,5);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'La Ville et les chiens','Mario Vargas Llosa', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lavilleetleschiens.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'La Ville et les chiens','Mario Vargas Llosa', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lavilleetleschiens.jpg'));
|
||||||
@@ -65,7 +65,7 @@ INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW
|
|||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'L''Homme sans qualités, tome 1'), true,7);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'L''Homme sans qualités, tome 1'), true,7);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'The Green House','Mario Vargas Llosa', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lamaisonverte.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'The Green House','Mario Vargas Llosa', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lamaisonverte.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'The Green House'), true,6);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'The Green House'), true,6);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Le coup de pistolet','Alexandre Pouchkine', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'lecoupdepistolet.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'Le coup de pistolet','Alexandre Pouchkine', (SELECT id FROM users WHERE name = 'demo2'),(SELECT id FROM static_files WHERE name = 'lecoupdepistolet.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Le coup de pistolet'),true,8);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM books WHERE title = 'Le coup de pistolet'),true,8);
|
||||||
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'De sang-froid','Truman Capote', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'desangfroid.jpg'));
|
INSERT INTO books(created_at, title, author, added_by_id, cover_id) VALUES ('NOW', 'De sang-froid','Truman Capote', (SELECT id FROM users WHERE name = 'demo'),(SELECT id FROM static_files WHERE name = 'desangfroid.jpg'));
|
||||||
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo2'),(SELECT id FROM books WHERE title = 'De sang-froid'),true,6);
|
INSERT INTO user_books(created_at, user_id, book_id, read, rating) VALUES ('NOW',(SELECT id FROM users WHERE name = 'demo2'),(SELECT id FROM books WHERE title = 'De sang-froid'),true,6);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { getBook, getImagePathOrDefault, putBookUpdate } from './api.js'
|
import { getBook, getImagePathOrDefault, putReadBook, putWantReadBook, putRateBook } from './api.js'
|
||||||
import { onBeforeRouteUpdate } from 'vue-router'
|
import { onBeforeRouteUpdate } from 'vue-router'
|
||||||
import { VRating } from 'vuetify/components/VRating';
|
import { VRating } from 'vuetify/components/VRating';
|
||||||
import BigIcon from './BigIcon.vue';
|
import BigIcon from './BigIcon.vue';
|
||||||
@@ -19,12 +19,20 @@
|
|||||||
|
|
||||||
function onRatingUpdate(rating) {
|
function onRatingUpdate(rating) {
|
||||||
data.value.rating = rating * 2;
|
data.value.rating = rating * 2;
|
||||||
putBookUpdate(props.id, {rating: data.value.rating});
|
putRateBook(props.id, {rating: data.value.rating});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReadIconClick() {
|
function onReadIconClick() {
|
||||||
data.value.read = !data.value.read;
|
data.value.read = !data.value.read;
|
||||||
putBookUpdate(props.id, {read: data.value.read});
|
if (data.value.read) {
|
||||||
|
data.value.wantread = false;
|
||||||
|
}
|
||||||
|
putReadBook(props.id, {read: data.value.read});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onWantReadIconClick() {
|
||||||
|
data.value.wantread = !data.value.wantread;
|
||||||
|
putWantReadBook(props.id, {wantread: data.value.wantread});
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@@ -55,9 +63,16 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div class="iconscontainer">
|
<div class="iconscontainer">
|
||||||
<BigIcon icon="BIconEye" :legend="$t('bookform.wantread')" :isSet="false"/>
|
<BigIcon icon="BIconEye"
|
||||||
<BigIcon icon="BIconBook" :legend="$t('bookform.startread')" :isSet="false"/>
|
:legend="$t('bookform.wantread')"
|
||||||
<BigIcon icon="BIconCheckCircle" :legend="$t('bookform.read')" :isSet="data.read"
|
:isSet="data.wantread"
|
||||||
|
@click="onWantReadIconClick"/>
|
||||||
|
<BigIcon icon="BIconBook"
|
||||||
|
:legend="$t('bookform.startread')"
|
||||||
|
:isSet="false"/>
|
||||||
|
<BigIcon icon="BIconCheckCircle"
|
||||||
|
:legend="$t('bookform.read')"
|
||||||
|
:isSet="data.read"
|
||||||
@click="onReadIconClick"/>
|
@click="onReadIconClick"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
const error = ref(null)
|
const error = ref(null)
|
||||||
|
|
||||||
async function onUserBookRead() {
|
async function onUserBookRead() {
|
||||||
const res = await putReadBook(props.id);
|
const res = await putReadBook(props.id, {read: true});
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
router.push('/books')
|
router.push('/books')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ const baseUrl = "http://localhost:8080"
|
|||||||
|
|
||||||
export function getImagePathOrDefault(path) {
|
export function getImagePathOrDefault(path) {
|
||||||
return (path == "" || typeof path === 'undefined') ?
|
return (path == "" || typeof path === 'undefined') ?
|
||||||
"../defaultbook.png" : "http://localhost:8080" + path;
|
"../defaultbook.png" : baseUrl + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
function useFetch(url) {
|
function useFetch(url) {
|
||||||
@@ -45,12 +45,16 @@ export function postBook(book) {
|
|||||||
return genericPayloadCall('/book', book.value, 'POST')
|
return genericPayloadCall('/book', book.value, 'POST')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putReadBook(bookId) {
|
export async function putReadBook(bookId, payload) {
|
||||||
return putBookUpdate(bookId, {read: true})
|
return genericPayloadCall('/book/' + bookId + "/read", payload, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putBookUpdate(bookId, payload) {
|
export async function putWantReadBook(bookId, payload) {
|
||||||
return genericPayloadCall('/book/' + bookId, payload, 'PUT')
|
return genericPayloadCall('/book/' + bookId + "/wantread", payload, 'PUT')
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function putRateBook(bookId, payload) {
|
||||||
|
return genericPayloadCall('/book/' + bookId + "/rate", payload, 'PUT')
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postLogin(user) {
|
export function postLogin(user) {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ type fetchedBook struct {
|
|||||||
Summary string `json:"summary"`
|
Summary string `json:"summary"`
|
||||||
Rating int `json:"rating"`
|
Rating int `json:"rating"`
|
||||||
Read bool `json:"read"`
|
Read bool `json:"read"`
|
||||||
|
WantRead bool `json:"wantread"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetBook_Ok(t *testing.T) {
|
func TestGetBook_Ok(t *testing.T) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ type bookUserGet struct {
|
|||||||
Author string `json:"author" binding:"max=100"`
|
Author string `json:"author" binding:"max=100"`
|
||||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||||
Read bool `json:"read"`
|
Read bool `json:"read"`
|
||||||
|
WantRead bool `json:"wantread"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetBooksHandler_Demo(t *testing.T) {
|
func TestGetBooksHandler_Demo(t *testing.T) {
|
||||||
|
|||||||
25
internal/apitest/put_userbook_read_test.go
Normal file
25
internal/apitest/put_userbook_read_test.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package apitest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPutReadUserBooks_NewReadOk(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"read": true
|
||||||
|
}`
|
||||||
|
bookId := "21"
|
||||||
|
testPutReadUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPutReadUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
||||||
|
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/book/"+bookId+"/read")
|
||||||
|
}
|
||||||
@@ -1,90 +1,74 @@
|
|||||||
package apitest
|
package apitest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPutBookUpdate_NewReadOk(t *testing.T) {
|
func TestPutRatingUserBooksHandler_UpdateRating(t *testing.T) {
|
||||||
payload :=
|
|
||||||
`{
|
|
||||||
"read": true
|
|
||||||
}`
|
|
||||||
testPutUserBooksHandler(t, payload, "21", http.StatusOK)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPutUserBooksHandler_UpdateRating(t *testing.T) {
|
|
||||||
payload :=
|
payload :=
|
||||||
`{
|
`{
|
||||||
"rating": 5
|
"rating": 5
|
||||||
}`
|
}`
|
||||||
bookId := "17"
|
bookId := "17"
|
||||||
testPutUserBooksHandler(t, payload, bookId, http.StatusOK)
|
testPutRateUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
assert.Equal(t, 5, book.Rating)
|
assert.Equal(t, 5, book.Rating)
|
||||||
assert.Equal(t, true, book.Read)
|
assert.Equal(t, true, book.Read)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutUserBooksHandler_RateNewBookMakeItRead(t *testing.T) {
|
func TestPutRatingUserBooksHandler_RateNewBookMakeItRead(t *testing.T) {
|
||||||
payload :=
|
payload :=
|
||||||
`{
|
`{
|
||||||
"rating": 7
|
"rating": 7
|
||||||
}`
|
}`
|
||||||
bookId := "18"
|
bookId := "18"
|
||||||
testPutUserBooksHandler(t, payload, bookId, http.StatusOK)
|
testPutRateUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
book := testGetBook(t, bookId, http.StatusOK)
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
assert.Equal(t, 7, book.Rating)
|
assert.Equal(t, 7, book.Rating)
|
||||||
assert.Equal(t, true, book.Read)
|
assert.Equal(t, true, book.Read)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutUserBooksHandler_RatingTypeWrong(t *testing.T) {
|
func TestPutRatingUserBooksHandler_RatingTypeWrong(t *testing.T) {
|
||||||
payload :=
|
payload :=
|
||||||
`{
|
`{
|
||||||
"rating": "bad"
|
"rating": "bad"
|
||||||
}`
|
}`
|
||||||
bookId := "18"
|
bookId := "18"
|
||||||
testPutUserBooksHandler(t, payload, bookId, http.StatusInternalServerError)
|
testPutRateUserBooks(t, payload, bookId, http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutUserBooksHandler_RatingMin(t *testing.T) {
|
func TestPutRatingUserBooksHandler_RatingMin(t *testing.T) {
|
||||||
payload :=
|
payload :=
|
||||||
`{
|
`{
|
||||||
"rating": -3
|
"rating": -3
|
||||||
}`
|
}`
|
||||||
bookId := "18"
|
bookId := "18"
|
||||||
testPutUserBooksHandler(t, payload, bookId, http.StatusBadRequest)
|
testPutRateUserBooks(t, payload, bookId, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutUserBooksHandler_RatingMax(t *testing.T) {
|
func TestPutRatingUserBooksHandler_RatingMax(t *testing.T) {
|
||||||
payload :=
|
payload :=
|
||||||
`{
|
`{
|
||||||
"rating": 15
|
"rating": 15
|
||||||
}`
|
}`
|
||||||
bookId := "18"
|
bookId := "18"
|
||||||
testPutUserBooksHandler(t, payload, bookId, http.StatusBadRequest)
|
testPutRateUserBooks(t, payload, bookId, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPutUserBooksHandler_BadBookId(t *testing.T) {
|
func TestPutRatingUserBooksHandler_BadBookId(t *testing.T) {
|
||||||
payload :=
|
payload :=
|
||||||
`{
|
`{
|
||||||
"rating": 15
|
"rating": 15
|
||||||
}`
|
}`
|
||||||
bookId := "18574"
|
bookId := "18574"
|
||||||
testPutUserBooksHandler(t, payload, bookId, http.StatusNotFound)
|
testPutRateUserBooks(t, payload, bookId, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPutUserBooksHandler(t *testing.T, payload string, bookId string, expectedCode int) {
|
func testPutRateUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
||||||
router := testutils.TestSetup()
|
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/book/"+bookId+"/rate")
|
||||||
token := testutils.ConnectDemoUser(router)
|
|
||||||
req, _ := http.NewRequest("PUT", "/book/"+bookId, strings.NewReader(payload))
|
|
||||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
|
||||||
w := httptest.NewRecorder()
|
|
||||||
router.ServeHTTP(w, req)
|
|
||||||
assert.Equal(t, expectedCode, w.Code)
|
|
||||||
}
|
}
|
||||||
|
|||||||
35
internal/apitest/put_userbook_wantread_test.go
Normal file
35
internal/apitest/put_userbook_wantread_test.go
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package apitest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPutWantRead_SetTrue(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"wantread": true
|
||||||
|
}`
|
||||||
|
bookId := "17"
|
||||||
|
testPutWantReadUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, true, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPutWantRead_SetFalse(t *testing.T) {
|
||||||
|
payload :=
|
||||||
|
`{
|
||||||
|
"wantread": false
|
||||||
|
}`
|
||||||
|
bookId := "2"
|
||||||
|
testPutWantReadUserBooks(t, payload, bookId, http.StatusOK)
|
||||||
|
book := testGetBook(t, bookId, http.StatusOK)
|
||||||
|
assert.Equal(t, false, book.WantRead)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testPutWantReadUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
||||||
|
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/book/"+bookId+"/wantread")
|
||||||
|
}
|
||||||
@@ -10,4 +10,5 @@ type UserBook struct {
|
|||||||
Book Book
|
Book Book
|
||||||
Rating int
|
Rating int
|
||||||
Read bool
|
Read bool
|
||||||
|
WantRead bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,14 @@ type BookGet struct {
|
|||||||
Summary string `json:"summary"`
|
Summary string `json:"summary"`
|
||||||
Rating int `json:"rating"`
|
Rating int `json:"rating"`
|
||||||
Read bool `json:"read"`
|
Read bool `json:"read"`
|
||||||
|
WantRead bool `json:"wantread"`
|
||||||
CoverPath string `json:"coverPath"`
|
CoverPath string `json:"coverPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (BookGet, error) {
|
func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (BookGet, error) {
|
||||||
var book BookGet
|
var book BookGet
|
||||||
query := db.Model(&model.Book{})
|
query := db.Model(&model.Book{})
|
||||||
query = query.Select("books.title, books.author, books.summary, user_books.rating, user_books.read, " + selectStaticFilesPath())
|
query = query.Select("books.title, books.author, books.summary, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||||
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId)
|
query = query.Joins("left join user_books on (user_books.book_id = books.id and user_books.user_id = ?)", userId)
|
||||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||||
query = query.Where("books.id = ?", bookId)
|
query = query.Where("books.id = ?", bookId)
|
||||||
@@ -51,13 +52,14 @@ type BookUserGet struct {
|
|||||||
Author string `json:"author" binding:"max=100"`
|
Author string `json:"author" binding:"max=100"`
|
||||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||||
Read bool `json:"read" binding:"boolean"`
|
Read bool `json:"read" binding:"boolean"`
|
||||||
|
WantRead bool `json:"wantread" binding:"boolean"`
|
||||||
CoverPath string `json:"coverPath"`
|
CoverPath string `json:"coverPath"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func FetchBookUserGet(db *gorm.DB, userId uint) ([]BookUserGet, error) {
|
func FetchBookUserGet(db *gorm.DB, userId uint) ([]BookUserGet, error) {
|
||||||
var books []BookUserGet
|
var books []BookUserGet
|
||||||
query := db.Model(&model.UserBook{})
|
query := db.Model(&model.UserBook{})
|
||||||
query = query.Select("books.id, books.title, books.author, user_books.rating, user_books.read," + selectStaticFilesPath())
|
query = query.Select("books.id, books.title, books.author, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||||
query = query.Joins("left join books on (books.id = user_books.book_id)")
|
query = query.Joins("left join books on (books.id = user_books.book_id)")
|
||||||
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
query = query.Joins("left join static_files on (static_files.id = books.cover_id)")
|
||||||
query = query.Where("user_id = ?", userId)
|
query = query.Where("user_id = ?", userId)
|
||||||
|
|||||||
@@ -12,69 +12,150 @@ import (
|
|||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type userbookPutUpdate struct {
|
func PutReadUserBookHandler(ac appcontext.AppContext) {
|
||||||
|
data, err := retrieveDataFromContext(ac)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bookId := data.BookId
|
||||||
|
user := data.User
|
||||||
|
var read userbookPutRead
|
||||||
|
err = ac.C.ShouldBindJSON(&read)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userbook.Read = read.Read
|
||||||
|
|
||||||
|
//remove the book from "wanted" list when it is marked as read.
|
||||||
|
if userbook.Read {
|
||||||
|
userbook.WantRead = false
|
||||||
|
}
|
||||||
|
|
||||||
|
ac.Db.Save(&userbook)
|
||||||
|
ac.C.String(http.StatusOK, "Success")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutWantReadUserBookHandler(ac appcontext.AppContext) {
|
||||||
|
data, err := retrieveDataFromContext(ac)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bookId := data.BookId
|
||||||
|
user := data.User
|
||||||
|
var wantread userbookPutWantRead
|
||||||
|
err = ac.C.ShouldBindJSON(&wantread)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userbook.WantRead = wantread.WantRead
|
||||||
|
ac.Db.Save(&userbook)
|
||||||
|
ac.C.String(http.StatusOK, "Success")
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutRateUserBookHandler(ac appcontext.AppContext) {
|
||||||
|
data, err := retrieveDataFromContext(ac)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
bookId := data.BookId
|
||||||
|
user := data.User
|
||||||
|
var rating userbookPutRating
|
||||||
|
err = ac.C.ShouldBindJSON(&rating)
|
||||||
|
if err != nil {
|
||||||
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
userbook.Rating = rating.Rating
|
||||||
|
|
||||||
|
//if rated, set to "read" (a rating = 0 means unrated)
|
||||||
|
if userbook.Rating > 0 {
|
||||||
|
userbook.Read = true
|
||||||
|
}
|
||||||
|
ac.Db.Save(&userbook)
|
||||||
|
ac.C.String(http.StatusOK, "Success")
|
||||||
|
}
|
||||||
|
|
||||||
|
type userbookPutRead struct {
|
||||||
Read bool `json:"read"`
|
Read bool `json:"read"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userbookPutWantRead struct {
|
||||||
|
WantRead bool `json:"wantread"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type userbookPutRating struct {
|
||||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func PutUserBookHandler(ac appcontext.AppContext) {
|
type apiCallData struct {
|
||||||
|
BookId uint
|
||||||
|
User model.User
|
||||||
|
}
|
||||||
|
|
||||||
|
func retrieveDataFromContext(ac appcontext.AppContext) (apiCallData, error) {
|
||||||
bookId64, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
|
bookId64, err := strconv.ParseUint(ac.C.Param("id"), 10, 64)
|
||||||
bookId := uint(bookId64)
|
bookId := uint(bookId64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ac.C.JSON(http.StatusBadRequest, gin.H{"error": err})
|
ac.C.JSON(http.StatusBadRequest, gin.H{"error": err})
|
||||||
return
|
return apiCallData{}, err
|
||||||
}
|
}
|
||||||
err = myvalidator.ValidateId(ac.Db, bookId, &model.Book{})
|
err = myvalidator.ValidateId(ac.Db, bookId, &model.Book{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return apiCallData{}, err
|
||||||
}
|
|
||||||
var userbook userbookPutUpdate
|
|
||||||
err = ac.C.ShouldBindJSON(&userbook)
|
|
||||||
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)
|
||||||
return
|
return apiCallData{}, fetchUserErr
|
||||||
|
}
|
||||||
|
return apiCallData{BookId: bookId, User: user}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//a rating of 0 means no rating
|
func fetchOrCreateUserBook(ac appcontext.AppContext, bookId uint, user *model.User) (model.UserBook, error) {
|
||||||
// if there is a rating, read is forced to true
|
var userbook model.UserBook
|
||||||
userbook.Read = userbook.Read || userbook.Rating > 0
|
res := ac.Db.Where("user_id = ? AND book_id = ?", user.ID, bookId).First(&userbook)
|
||||||
|
err := res.Error
|
||||||
var userbookDb model.UserBook
|
|
||||||
res := ac.Db.Where("user_id = ? AND book_id = ?", user.ID, bookId).First(&userbookDb)
|
|
||||||
err = res.Error
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
userbookDb = userBookWsToDb(userbook, bookId, &user)
|
userbook = createUserBook(bookId, user)
|
||||||
err = ac.Db.Save(&userbookDb).Error
|
err = ac.Db.Save(&userbook).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return userbook, err
|
||||||
}
|
}
|
||||||
|
return userbook, nil
|
||||||
} else {
|
} else {
|
||||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||||
return
|
return userbook, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
userbookDb.Read = userbook.Read
|
return userbook, nil
|
||||||
if userbook.Rating > 0 {
|
|
||||||
userbookDb.Rating = userbook.Rating
|
|
||||||
}
|
}
|
||||||
ac.Db.Save(&userbookDb)
|
|
||||||
}
|
|
||||||
ac.C.String(http.StatusOK, "Success")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func userBookWsToDb(ub userbookPutUpdate, bookId uint, user *model.User) model.UserBook {
|
func createUserBook(bookId uint, user *model.User) model.UserBook {
|
||||||
return model.UserBook{
|
return model.UserBook{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
BookID: bookId,
|
BookID: bookId,
|
||||||
Read: ub.Read,
|
Read: false,
|
||||||
Rating: ub.Rating,
|
WantRead: false,
|
||||||
|
Rating: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,14 @@ func Setup(config *config.Config) *gin.Engine {
|
|||||||
r.GET("/book/:id", func(c *gin.Context) {
|
r.GET("/book/:id", func(c *gin.Context) {
|
||||||
routes.GetBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.GetBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
})
|
})
|
||||||
r.PUT("/book/:id", func(c *gin.Context) {
|
r.PUT("/book/:id/read", func(c *gin.Context) {
|
||||||
routes.PutUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
routes.PutReadUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
|
})
|
||||||
|
r.PUT("/book/:id/wantread", func(c *gin.Context) {
|
||||||
|
routes.PutWantReadUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
|
})
|
||||||
|
r.PUT("/book/:id/rate", func(c *gin.Context) {
|
||||||
|
routes.PutRateUserBookHandler(appcontext.AppContext{C: c, Db: db, I18n: bundle, Config: config})
|
||||||
})
|
})
|
||||||
r.POST("/book", func(c *gin.Context) {
|
r.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})
|
||||||
|
|||||||
@@ -2,14 +2,17 @@ package testutils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"strings"
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
"git.artlef.fr/PersonalLibraryManager/internal/config"
|
"git.artlef.fr/PersonalLibraryManager/internal/config"
|
||||||
"git.artlef.fr/PersonalLibraryManager/internal/setup"
|
"git.artlef.fr/PersonalLibraryManager/internal/setup"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetup() *gin.Engine {
|
func TestSetup() *gin.Engine {
|
||||||
@@ -51,3 +54,13 @@ func connectUser(router *gin.Engine, loginJson string) string {
|
|||||||
}
|
}
|
||||||
return parsedResponse.Token
|
return parsedResponse.Token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBookPutCallWithDemoPayload(t *testing.T, payload string, bookId string, expectedCode int, url string) {
|
||||||
|
router := TestSetup()
|
||||||
|
token := ConnectDemoUser(router)
|
||||||
|
req, _ := http.NewRequest("PUT", url, strings.NewReader(payload))
|
||||||
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token))
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
router.ServeHTTP(w, req)
|
||||||
|
assert.Equal(t, expectedCode, w.Code)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user