package routes import ( "errors" "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" "gorm.io/gorm" ) 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 //if set to read, remove want read userbook.WantRead = false } ac.Db.Save(&userbook) ac.C.String(http.StatusOK, "Success") } type userbookPutRead struct { Read bool `json:"read"` } type userbookPutWantRead struct { WantRead bool `json:"wantread"` } type userbookPutRating struct { Rating int `json:"rating" binding:"min=0,max=10"` } 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) bookId := uint(bookId64) if err != nil { ac.C.JSON(http.StatusBadRequest, gin.H{"error": err}) return apiCallData{}, err } err = myvalidator.ValidateId(ac.Db, bookId, &model.Book{}) if err != nil { myvalidator.ReturnErrorsAsJsonResponse(&ac, err) return apiCallData{}, err } user, fetchUserErr := ac.GetAuthenticatedUser() if fetchUserErr != nil { myvalidator.ReturnErrorsAsJsonResponse(&ac, err) return apiCallData{}, fetchUserErr } return apiCallData{BookId: bookId, User: user}, nil } func fetchOrCreateUserBook(ac appcontext.AppContext, bookId uint, user *model.User) (model.UserBook, error) { var userbook model.UserBook res := ac.Db.Where("user_id = ? AND book_id = ?", user.ID, bookId).First(&userbook) err := res.Error if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { userbook = createUserBook(bookId, user) err = ac.Db.Save(&userbook).Error if err != nil { myvalidator.ReturnErrorsAsJsonResponse(&ac, err) return userbook, err } return userbook, nil } else { myvalidator.ReturnErrorsAsJsonResponse(&ac, err) return userbook, err } } else { return userbook, nil } } func createUserBook(bookId uint, user *model.User) model.UserBook { return model.UserBook{ UserID: user.ID, BookID: bookId, Read: false, WantRead: false, Rating: 0, } }