Skip to content

Commit 46c8334

Browse files
committed
fixes
1 parent 5f7084c commit 46c8334

File tree

5 files changed

+113
-23
lines changed

5 files changed

+113
-23
lines changed

database/database.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ func Models() []interface{} {
2727
&models.Genre{},
2828
&models.SubSection{},
2929
&models.Section{},
30+
&models.BookSubSection{},
3031
&models.Book{},
3132
&models.BookRead{},
3233
&models.BookReport{},

managers/books.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -968,16 +968,28 @@ func (g GenreManager) GetSectionBySlug(db *gorm.DB, slug string) *models.Section
968968
return &section
969969
}
970970

971-
func (g GenreManager) GetSubSectionBySlug(db *gorm.DB, slug string) *models.SubSection {
971+
func (g GenreManager) GetSubSectionBySlug(db *gorm.DB, slug string) (*models.SubSection, []schemas.BookWithOrder) {
972+
var subSection models.SubSection
973+
err := db.Preload("Section").Where("slug = ?", slug).First(&subSection).Error
974+
if err != nil || subSection.ID == uuid.Nil {
975+
return nil, []schemas.BookWithOrder{}
976+
}
972977

973-
subSection := models.SubSection{Slug: slug}
974-
db.Preload("Section").Preload("Books").Preload("Books.Author").Take(&subSection, subSection)
978+
// Fetch books with pivot data
979+
var booksWithOrder []schemas.BookWithOrder
980+
err = db.Table("books").
981+
Select("books.*, book_sub_sections.order_in_section, users.id AS author_id, users.username AS author_username, users.name AS author_name, users.avatar AS author_avatar").
982+
Joins("JOIN book_sub_sections ON book_sub_sections.book_id = books.id").
983+
Joins("LEFT JOIN users ON users.id = books.author_id").
984+
Where("book_sub_sections.sub_section_id = ?", subSection.ID).
985+
Order("book_sub_sections.order_in_section ASC").
986+
Scan(&booksWithOrder).Error
975987

976-
if subSection.ID == uuid.Nil {
977-
return nil
988+
if err != nil {
989+
return nil, []schemas.BookWithOrder{}
978990
}
979991

980-
return &subSection
992+
return &subSection, booksWithOrder
981993
}
982994

983995
type ReviewManager struct {

models/book.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ type SubSection struct {
5757
BaseModel
5858
Name string `gorm:"unique"`
5959
Slug string `gorm:"unique"`
60-
Books []Book `gorm:"many2many:book_sub_sections"`
60+
Books []Book `gorm:"many2many:book_sub_sections;joinForeignKey:SubSectionID;joinReferences:BookID"`
6161
SectionID uuid.UUID
6262
Section Section `gorm:"foreignKey:SectionID;constraint:OnDelete:SET NULL;<-:false"`
6363
}
@@ -79,7 +79,7 @@ type Book struct {
7979
GenreID uuid.UUID
8080
Genre Genre `gorm:"foreignKey:GenreID;constraint:OnDelete:SET NULL;<-:false"`
8181

82-
SubSections []SubSection `gorm:"many2many:book_sub_sections"`
82+
SubSections []SubSection `gorm:"many2many:book_sub_sections;joinForeignKey:BookID;joinReferences:SubSectionID"`
8383

8484
Tags []Tag `gorm:"many2many:book_tags"`
8585
Chapters []Chapter `gorm:"constraint:OnDelete:CASCADE"`
@@ -177,6 +177,13 @@ func (b *Book) BeforeCreate(tx *gorm.DB) (err error) {
177177
return
178178
}
179179

180+
type BookSubSection struct {
181+
BookID uuid.UUID `gorm:"primaryKey"`
182+
SubSectionID uuid.UUID `gorm:"primaryKey"`
183+
OrderInSection uint
184+
CreatedAt time.Time
185+
}
186+
180187
type BookRead struct {
181188
BaseModel
182189
UserID uuid.UUID

routes/admin_books.go

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/LitPad/backend/utils"
88
"github.com/gofiber/fiber/v2"
99
"github.com/google/uuid"
10+
"gorm.io/gorm"
1011
)
1112

1213
// @Summary Add Genre
@@ -218,7 +219,7 @@ func (ep Endpoint) AdminUpdateBookSection(c *fiber.Ctx) error {
218219
// @Security BearerAuth
219220
func (ep Endpoint) AdminUpdateBookSubSection(c *fiber.Ctx) error {
220221
db := ep.DB
221-
subsection := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
222+
subsection, _ := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
222223
if subsection == nil {
223224
return c.Status(404).JSON(utils.NotFoundErr("SubSection does not exist"))
224225
}
@@ -332,7 +333,7 @@ func (ep Endpoint) AdminDeleteBookSection(c *fiber.Ctx) error {
332333
// @Security BearerAuth
333334
func (ep Endpoint) AdminDeleteBookSubSection(c *fiber.Ctx) error {
334335
db := ep.DB
335-
subsection := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
336+
subsection, _ := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
336337
if subsection == nil {
337338
return c.Status(404).JSON(utils.NotFoundErr("SubSection does not exist"))
338339
}
@@ -354,15 +355,44 @@ func (ep Endpoint) AdminDeleteBookSubSection(c *fiber.Ctx) error {
354355
// @Security BearerAuth
355356
func (ep Endpoint) AddBookToSubSection(c *fiber.Ctx) error {
356357
db := ep.DB
357-
subsection := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
358+
359+
subsection, _ := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
358360
if subsection == nil {
359361
return c.Status(404).JSON(utils.NotFoundErr("SubSection does not exist"))
360362
}
363+
361364
book, err := bookManager.GetBySlug(db, c.Params("book_slug"), false)
362365
if err != nil {
363366
return c.Status(404).JSON(err)
364367
}
365-
db.Model(&book).Association("SubSections").Append(subsection)
368+
369+
// Check if already exists to prevent duplicates
370+
var count int64
371+
db.Model(&models.BookSubSection{}).
372+
Where("book_id = ? AND sub_section_id = ?", book.ID, subsection.ID).
373+
Count(&count)
374+
375+
if count > 0 {
376+
return c.Status(200).JSON(ResponseMessage("Book already in subsection"))
377+
}
378+
379+
// Determine order in section
380+
var order int64
381+
db.Model(&models.BookSubSection{}).
382+
Where("sub_section_id = ?", subsection.ID).
383+
Count(&order)
384+
385+
// Add association manually to maintain ordering
386+
bookSub := models.BookSubSection{
387+
BookID: book.ID,
388+
SubSectionID: subsection.ID,
389+
OrderInSection: uint(order + 1),
390+
}
391+
392+
if err := db.Create(&bookSub).Error; err != nil {
393+
return c.Status(500).JSON(utils.ServerErr("Something went wrong"))
394+
}
395+
366396
return c.Status(200).JSON(ResponseMessage("Book added to subsection successfully"))
367397
}
368398

@@ -380,18 +410,43 @@ func (ep Endpoint) AddBookToSubSection(c *fiber.Ctx) error {
380410
// @Security BearerAuth
381411
func (ep Endpoint) RemoveBookFromSubSection(c *fiber.Ctx) error {
382412
db := ep.DB
383-
subsection := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
413+
414+
subsection, _ := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
384415
if subsection == nil {
385416
return c.Status(404).JSON(utils.NotFoundErr("SubSection does not exist"))
386417
}
387418

388-
// Get the book by its slug
389419
book, err := bookManager.GetBySlug(db, c.Params("book_slug"), false)
390420
if err != nil {
391421
return c.Status(404).JSON(err)
392422
}
393-
db.Model(&book).Association("SubSections").Delete(subsection)
394-
return c.Status(200).JSON(ResponseMessage("Book removed from subsection"))
423+
424+
var bookSub models.BookSubSection
425+
if err := db.
426+
Where("book_id = ? AND sub_section_id = ?", book.ID, subsection.ID).
427+
First(&bookSub).Error; err != nil {
428+
return c.Status(404).JSON(utils.NotFoundErr("Book not found in subsection"))
429+
}
430+
431+
tx := db.Begin()
432+
433+
// Delete the record
434+
if err := tx.Delete(&bookSub).Error; err != nil {
435+
tx.Rollback()
436+
return c.Status(500).JSON(utils.ServerErr("Failed to remove book from subsection"))
437+
}
438+
439+
// Shift order up for other books in that subsection
440+
if err := tx.Model(&models.BookSubSection{}).
441+
Where("sub_section_id = ? AND order_in_section > ?", subsection.ID, bookSub.OrderInSection).
442+
Update("order_in_section", gorm.Expr("order_in_section - 1")).Error; err != nil {
443+
tx.Rollback()
444+
return c.Status(500).JSON(utils.ServerErr("Failed to update book order"))
445+
}
446+
447+
tx.Commit()
448+
449+
return c.Status(200).JSON(ResponseMessage("Book removed from subsection successfully"))
395450
}
396451

397452
// @Summary Delete Tag
@@ -447,20 +502,20 @@ func (ep Endpoint) AdminGetSections(c *fiber.Ctx) error {
447502
// @Security BearerAuth
448503
func (ep Endpoint) AdminGetSubSection(c *fiber.Ctx) error {
449504
db := ep.DB
450-
subSection := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
505+
subSection, books := genreManager.GetSubSectionBySlug(db, c.Params("slug"))
451506
if subSection == nil {
452507
return c.Status(404).JSON(utils.NotFoundErr("Sub section does not exist"))
453508
}
454509
// Paginate books
455-
paginatedData, paginatedBooks, err := PaginateQueryset(subSection.Books, c, 200)
510+
paginatedData, paginatedBooks, err := PaginateQueryset(books, c, 200)
456511
if err != nil {
457512
return c.Status(400).JSON(err)
458513
}
459-
books := paginatedBooks.([]models.Book)
514+
castedBooks := paginatedBooks.([]schemas.BookWithOrder)
460515

461516
response := schemas.SubSectionWithBooksResponseSchema{
462517
ResponseSchema: ResponseMessage("Sub section retrieved successfully"),
463-
Data: schemas.SubSectionWithBooksSchema{}.Init(*subSection, books, *paginatedData),
518+
Data: schemas.SubSectionWithBooksSchema{}.Init(*subSection, castedBooks, *paginatedData),
464519
}
465520
return c.Status(200).JSON(response)
466521
}

schemas/admin_books.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ func (s SectionsWithSubSectionsSchema) Init(sections []models.Section) SectionsW
107107
}
108108

109109
type SubSectionBookSchema struct {
110+
OrderInSection uint `json:"order_in_section"`
110111
Title string `json:"title"`
111112
Author UserDataSchema `json:"author"`
112113
}
@@ -116,20 +117,34 @@ type SubSectionBookResponseSchema struct {
116117
Items []SubSectionBookSchema `json:"items"`
117118
}
118119

120+
type BookWithOrder struct {
121+
models.Book
122+
OrderInSection uint `json:"order_in_section"`
123+
AuthorID uuid.UUID `json:"author_id"`
124+
AuthorName string `json:"author_name"`
125+
AuthorUsername string `json:"author_username"`
126+
AuthorAvatar string `json:"author_avatar"`
127+
}
128+
119129
type SubSectionWithBooksSchema struct {
120130
SubSectionSchema
121131
Section string `json:"section"`
122132
Books SubSectionBookResponseSchema `json:"books"`
123133
}
124134

125-
func (s SubSectionWithBooksSchema) Init(subSection models.SubSection, books []models.Book, paginatedData PaginatedResponseDataSchema) SubSectionWithBooksSchema {
126-
s.SubSectionSchema = s.SubSectionSchema.Init(&subSection)
135+
func (s SubSectionWithBooksSchema) Init(subSection models.SubSection, books []BookWithOrder, paginatedData PaginatedResponseDataSchema) SubSectionWithBooksSchema {
136+
s.SubSectionSchema = SubSectionSchema{Name: subSection.Name, Slug: subSection.Slug, BooksCount: len(books)}
127137
s.Section = subSection.Section.Name
128138
bookItems := []SubSectionBookSchema{}
129139
for _, item := range books {
130140
bookItems = append(bookItems, SubSectionBookSchema{
141+
OrderInSection: item.OrderInSection,
131142
Title: item.Title,
132-
Author: UserDataSchema{}.Init(item.Author),
143+
Author: UserDataSchema{
144+
Name: &item.AuthorName,
145+
Username: item.AuthorUsername,
146+
Avatar: item.AuthorAvatar,
147+
},
133148
})
134149
}
135150
s.Books = SubSectionBookResponseSchema{

0 commit comments

Comments
 (0)