Added start read date
This commit is contained in:
@@ -12,19 +12,20 @@ import (
|
||||
)
|
||||
|
||||
type fetchedBook struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Summary string `json:"summary"`
|
||||
Rating int `json:"rating"`
|
||||
Read bool `json:"read"`
|
||||
WantRead bool `json:"wantread"`
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Summary string `json:"summary"`
|
||||
Rating int `json:"rating"`
|
||||
Read bool `json:"read"`
|
||||
WantRead bool `json:"wantread"`
|
||||
StartReadDate string `json:"startReadDate"`
|
||||
}
|
||||
|
||||
func TestGetBook_Ok(t *testing.T) {
|
||||
book := testGetBook(t, "5", http.StatusOK)
|
||||
book := testGetBook(t, "3", http.StatusOK)
|
||||
assert.Equal(t,
|
||||
fetchedBook{
|
||||
Title: "Rigodon",
|
||||
Title: "D'un château l'autre",
|
||||
Author: "Louis-Ferdinand Céline",
|
||||
Rating: 10,
|
||||
Read: true,
|
||||
|
||||
@@ -31,7 +31,7 @@ func TestGetReadBooksCountHandler_Demo(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.Equal(t, 23, c.Count)
|
||||
assert.Equal(t, 22, c.Count)
|
||||
}
|
||||
|
||||
func TestGetWantReadBooksCountHandler_Demo(t *testing.T) {
|
||||
|
||||
@@ -14,7 +14,7 @@ func TestGetReadBooksHandler_Demo(t *testing.T) {
|
||||
|
||||
token := testutils.ConnectDemoUser(router)
|
||||
books := testGetReadBooksHandler(t, router, token, 200, "", "")
|
||||
assert.Equal(t, 23, len(books))
|
||||
assert.Equal(t, 22, len(books))
|
||||
}
|
||||
|
||||
func TestGetReadBooksHandler_DemoNoLimit(t *testing.T) {
|
||||
@@ -22,7 +22,7 @@ func TestGetReadBooksHandler_DemoNoLimit(t *testing.T) {
|
||||
|
||||
token := testutils.ConnectDemoUser(router)
|
||||
books := testGetReadBooksHandler(t, router, token, 200, "100", "")
|
||||
assert.Equal(t, 23, len(books))
|
||||
assert.Equal(t, 22, len(books))
|
||||
}
|
||||
|
||||
func TestGetReadBooksHandler_DemoLowerLimit(t *testing.T) {
|
||||
@@ -38,7 +38,7 @@ func TestGetReadBooksHandler_DemoOffset(t *testing.T) {
|
||||
|
||||
token := testutils.ConnectDemoUser(router)
|
||||
books := testGetReadBooksHandler(t, router, token, 200, "20", "10")
|
||||
assert.Equal(t, 13, len(books))
|
||||
assert.Equal(t, 12, len(books))
|
||||
}
|
||||
|
||||
func TestGetReadBooksHandler_Demo2(t *testing.T) {
|
||||
@@ -46,7 +46,7 @@ func TestGetReadBooksHandler_Demo2(t *testing.T) {
|
||||
|
||||
token := testutils.ConnectDemo2User(router)
|
||||
books := testGetReadBooksHandler(t, router, token, 200, "", "")
|
||||
assert.Equal(t, 2, len(books))
|
||||
assert.Equal(t, 3, len(books))
|
||||
}
|
||||
|
||||
func TestGetReadBooksHandler_CheckOneBook(t *testing.T) {
|
||||
|
||||
53
internal/apitest/put_userbook_startread_test.go
Normal file
53
internal/apitest/put_userbook_startread_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package apitest
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/testutils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestPutStartReadUserBooks_NoDate(t *testing.T) {
|
||||
payload :=
|
||||
`{
|
||||
"date": "2025-11-19"
|
||||
}`
|
||||
bookId := "6"
|
||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func TestPutStartReadUserBooks_WrongDateFormat(t *testing.T) {
|
||||
payload :=
|
||||
`{
|
||||
"startDate": "19/11/2025"
|
||||
}`
|
||||
bookId := "6"
|
||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func TestPutStartReadUserBooks_NewReadOk(t *testing.T) {
|
||||
payload :=
|
||||
`{
|
||||
"startDate": "2025-11-19"
|
||||
}`
|
||||
bookId := "6"
|
||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusOK)
|
||||
book := testGetBook(t, bookId, http.StatusOK)
|
||||
assert.Equal(t, "2025-11-19", book.StartReadDate)
|
||||
}
|
||||
|
||||
func TestPutStartReadUserBooks_Unset(t *testing.T) {
|
||||
payload :=
|
||||
`{
|
||||
"startDate": "null"
|
||||
}`
|
||||
bookId := "6"
|
||||
testPutStartReadUserBooks(t, payload, bookId, http.StatusOK)
|
||||
book := testGetBook(t, bookId, http.StatusOK)
|
||||
assert.Equal(t, "", book.StartReadDate)
|
||||
}
|
||||
|
||||
func testPutStartReadUserBooks(t *testing.T, payload string, bookId string, expectedCode int) {
|
||||
testutils.TestBookPutCallWithDemoPayload(t, payload, bookId, expectedCode, "/book/"+bookId+"/startread")
|
||||
}
|
||||
@@ -1,14 +1,19 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// describes the relationship between a user and a book.
|
||||
type UserBook struct {
|
||||
gorm.Model
|
||||
UserID uint
|
||||
BookID uint
|
||||
Book Book
|
||||
Rating int
|
||||
Read bool
|
||||
WantRead bool
|
||||
UserID uint
|
||||
BookID uint
|
||||
Book Book
|
||||
Rating int
|
||||
Read bool
|
||||
WantRead bool
|
||||
StartReadDate *time.Time
|
||||
}
|
||||
|
||||
@@ -9,19 +9,20 @@ import (
|
||||
)
|
||||
|
||||
type BookGet struct {
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Summary string `json:"summary"`
|
||||
Rating int `json:"rating"`
|
||||
Read bool `json:"read"`
|
||||
WantRead bool `json:"wantread"`
|
||||
CoverPath string `json:"coverPath"`
|
||||
Title string `json:"title" binding:"required,max=300"`
|
||||
Author string `json:"author" binding:"max=100"`
|
||||
Summary string `json:"summary"`
|
||||
Rating int `json:"rating"`
|
||||
Read bool `json:"read"`
|
||||
WantRead bool `json:"wantread"`
|
||||
StartReadDate string `json:"startReadDate"`
|
||||
CoverPath string `json:"coverPath"`
|
||||
}
|
||||
|
||||
func FetchBookGet(db *gorm.DB, userId uint, bookId uint64) (BookGet, error) {
|
||||
var book BookGet
|
||||
query := db.Model(&model.Book{})
|
||||
query = query.Select("books.title, books.author, books.summary, user_books.rating, user_books.read, user_books.want_read, " + selectStaticFilesPath())
|
||||
query = query.Select("books.title, books.author, books.summary, user_books.rating, user_books.read, user_books.want_read, user_books.start_read_date, " + 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 static_files on (static_files.id = books.cover_id)")
|
||||
query = query.Where("books.id = ?", bookId)
|
||||
|
||||
@@ -3,6 +3,7 @@ package routes
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
@@ -32,5 +33,22 @@ func GetBookHandler(ac appcontext.AppContext) {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
err = fixBookGetDateFields(&book)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
ac.C.JSON(http.StatusOK, book)
|
||||
}
|
||||
|
||||
func fixBookGetDateFields(book *query.BookGet) error {
|
||||
if book.StartReadDate == "" {
|
||||
return nil
|
||||
}
|
||||
startDate, err := time.Parse(time.RFC3339, book.StartReadDate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
book.StartReadDate = startDate.Format(time.DateOnly)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/appcontext"
|
||||
"git.artlef.fr/PersonalLibraryManager/internal/model"
|
||||
@@ -63,6 +64,42 @@ func PutWantReadUserBookHandler(ac appcontext.AppContext) {
|
||||
ac.C.String(http.StatusOK, "Success")
|
||||
}
|
||||
|
||||
func PutStartReadUserBookHandler(ac appcontext.AppContext) {
|
||||
data, err := retrieveDataFromContext(ac)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
bookId := data.BookId
|
||||
user := data.User
|
||||
|
||||
var startDateToParse userbookPutStartRead
|
||||
err = ac.C.ShouldBindJSON(&startDateToParse)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
userbook, err := fetchOrCreateUserBook(ac, bookId, &user)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
|
||||
//string equal to "null" to unset value
|
||||
if startDateToParse.StartDate == "null" {
|
||||
userbook.StartReadDate = nil
|
||||
} else {
|
||||
startDate, err := time.Parse(time.DateOnly, startDateToParse.StartDate)
|
||||
if err != nil {
|
||||
myvalidator.ReturnErrorsAsJsonResponse(&ac, err)
|
||||
return
|
||||
}
|
||||
userbook.StartReadDate = &startDate
|
||||
}
|
||||
|
||||
ac.Db.Save(&userbook)
|
||||
ac.C.String(http.StatusOK, "Success")
|
||||
}
|
||||
|
||||
func PutRateUserBookHandler(ac appcontext.AppContext) {
|
||||
data, err := retrieveDataFromContext(ac)
|
||||
if err != nil {
|
||||
@@ -104,6 +141,10 @@ type userbookPutRating struct {
|
||||
Rating int `json:"rating" binding:"min=0,max=10"`
|
||||
}
|
||||
|
||||
type userbookPutStartRead struct {
|
||||
StartDate string `json:"startDate" binding:"required"`
|
||||
}
|
||||
|
||||
type apiCallData struct {
|
||||
BookId uint
|
||||
User model.User
|
||||
|
||||
@@ -51,6 +51,9 @@ func Setup(config *config.Config) *gin.Engine {
|
||||
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/startread", func(c *gin.Context) {
|
||||
routes.PutStartReadUserBookHandler(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})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user