diff --git a/docs/docs.go b/docs/docs.go index fb5a5d6..dfc2807 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -238,6 +238,53 @@ const docTemplate = `{ } } } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a genre.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin | Books" + ], + "summary": "Delete Genre", + "parameters": [ + { + "type": "string", + "description": "Genre slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Genre Deleted Successfully", + "schema": { + "$ref": "#/definitions/schemas.ResponseSchema" + } + }, + "400": { + "description": "Invalid request data", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + } + } } }, "/admin/books/tags": { @@ -257,7 +304,7 @@ const docTemplate = `{ "tags": [ "Admin | Books" ], - "summary": "Add Tags", + "summary": "Add Tag", "parameters": [ { "description": "Tag", @@ -308,7 +355,7 @@ const docTemplate = `{ "tags": [ "Admin | Books" ], - "summary": "Update Tags", + "summary": "Update Tag", "parameters": [ { "type": "string", @@ -347,6 +394,53 @@ const docTemplate = `{ } } } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a tag from the app.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin | Books" + ], + "summary": "Delete Tag", + "parameters": [ + { + "type": "string", + "description": "Tag slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Tag delete successfully", + "schema": { + "$ref": "#/definitions/schemas.ResponseSchema" + } + }, + "400": { + "description": "Invalid request data", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + } + } } }, "/admin/payments/transactions": { diff --git a/docs/swagger.json b/docs/swagger.json index 5d5f3be..974f6bd 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -231,6 +231,53 @@ } } } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a genre.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin | Books" + ], + "summary": "Delete Genre", + "parameters": [ + { + "type": "string", + "description": "Genre slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Genre Deleted Successfully", + "schema": { + "$ref": "#/definitions/schemas.ResponseSchema" + } + }, + "400": { + "description": "Invalid request data", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + } + } } }, "/admin/books/tags": { @@ -250,7 +297,7 @@ "tags": [ "Admin | Books" ], - "summary": "Add Tags", + "summary": "Add Tag", "parameters": [ { "description": "Tag", @@ -301,7 +348,7 @@ "tags": [ "Admin | Books" ], - "summary": "Update Tags", + "summary": "Update Tag", "parameters": [ { "type": "string", @@ -340,6 +387,53 @@ } } } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "Delete a tag from the app.", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Admin | Books" + ], + "summary": "Delete Tag", + "parameters": [ + { + "type": "string", + "description": "Tag slug", + "name": "slug", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Tag delete successfully", + "schema": { + "$ref": "#/definitions/schemas.ResponseSchema" + } + }, + "400": { + "description": "Invalid request data", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + }, + "500": { + "description": "Internal server error", + "schema": { + "$ref": "#/definitions/utils.ErrorResponse" + } + } + } } }, "/admin/payments/transactions": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index dad0304..e1bd5ba 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -1457,6 +1457,36 @@ paths: tags: - Admin | Books /admin/books/genres/{slug}: + delete: + consumes: + - application/json + description: Delete a genre. + parameters: + - description: Genre slug + in: path + name: slug + required: true + type: string + produces: + - application/json + responses: + "200": + description: Genre Deleted Successfully + schema: + $ref: '#/definitions/schemas.ResponseSchema' + "400": + description: Invalid request data + schema: + $ref: '#/definitions/utils.ErrorResponse' + "500": + description: Internal server error + schema: + $ref: '#/definitions/utils.ErrorResponse' + security: + - BearerAuth: [] + summary: Delete Genre + tags: + - Admin | Books put: consumes: - application/json @@ -1522,10 +1552,40 @@ paths: $ref: '#/definitions/utils.ErrorResponse' security: - BearerAuth: [] - summary: Add Tags + summary: Add Tag tags: - Admin | Books /admin/books/tags/{slug}: + delete: + consumes: + - application/json + description: Delete a tag from the app. + parameters: + - description: Tag slug + in: path + name: slug + required: true + type: string + produces: + - application/json + responses: + "200": + description: Tag delete successfully + schema: + $ref: '#/definitions/schemas.ResponseSchema' + "400": + description: Invalid request data + schema: + $ref: '#/definitions/utils.ErrorResponse' + "500": + description: Internal server error + schema: + $ref: '#/definitions/utils.ErrorResponse' + security: + - BearerAuth: [] + summary: Delete Tag + tags: + - Admin | Books put: consumes: - application/json @@ -1559,7 +1619,7 @@ paths: $ref: '#/definitions/utils.ErrorResponse' security: - BearerAuth: [] - summary: Update Tags + summary: Update Tag tags: - Admin | Books /admin/payments/transactions: diff --git a/models/book.go b/models/book.go index 954b722..c092497 100644 --- a/models/book.go +++ b/models/book.go @@ -12,8 +12,9 @@ import ( type Tag struct { BaseModel - Name string `gorm:"unique"` - Slug string `gorm:"unique"` + Name string `gorm:"unique"` + Slug string `gorm:"unique"` + Genres []Genre `gorm:"many2many:genre_tags;"` } func (tag *Tag) BeforeSave(tx *gorm.DB) (err error) { @@ -25,7 +26,7 @@ type Genre struct { BaseModel Name string `gorm:"unique"` Slug string `gorm:"unique"` - Tags []Tag `json:"tags" gorm:"many2many:genre_tags;"` + Tags []Tag `gorm:"many2many:genre_tags;"` } func (genre *Genre) BeforeSave(tx *gorm.DB) (err error) { @@ -36,14 +37,14 @@ func (genre *Genre) BeforeSave(tx *gorm.DB) (err error) { type Book struct { BaseModel AuthorID uuid.UUID - Author User `gorm:"foreignKey:AuthorID;constraint:OnDelete:CASCADE;<-:false"` + Author User `gorm:"foreignKey:AuthorID;constraint:OnDelete:SET NULL;<-:false"` Title string `gorm:"type: varchar(255)"` Slug string `gorm:"unique"` Blurb string `gorm:"type: varchar(255)"` AgeDiscretion choices.AgeType GenreID uuid.UUID `json:"genre_id"` - Genre Genre `gorm:"foreignKey:GenreID;constraint:OnDelete:CASCADE;<-:false"` + Genre Genre `gorm:"foreignKey:GenreID;constraint:OnDelete:SET NULL;<-:false"` Tags []Tag `gorm:"many2many:book_tags;<-:false"` Chapters []Chapter `gorm:"<-:false"` CoverImage string `gorm:"type:varchar(10000)"` diff --git a/routes/admin_books.go b/routes/admin_books.go index 5cce861..59fa78b 100644 --- a/routes/admin_books.go +++ b/routes/admin_books.go @@ -20,7 +20,7 @@ import ( // @Failure 500 {object} utils.ErrorResponse "Internal server error" // @Router /admin/books/genres [post] // @Security BearerAuth -func (ep Endpoint) AdminAddBookGenres(c *fiber.Ctx) error { +func (ep Endpoint) AdminAddBookGenre(c *fiber.Ctx) error { db := ep.DB data := schemas.GenreAddSchema{} errCode, errData := ValidateRequest(c, &data); @@ -44,7 +44,7 @@ func (ep Endpoint) AdminAddBookGenres(c *fiber.Ctx) error { return c.Status(201).JSON(ResponseMessage("Genre added successfully")) } -// @Summary Add Tags +// @Summary Add Tag // @Description Add a new tag to the app. // @Tags Admin | Books // @Accept json @@ -55,7 +55,7 @@ func (ep Endpoint) AdminAddBookGenres(c *fiber.Ctx) error { // @Failure 500 {object} utils.ErrorResponse "Internal server error" // @Router /admin/books/tags [post] // @Security BearerAuth -func (ep Endpoint) AdminAddBookTags(c *fiber.Ctx) error { +func (ep Endpoint) AdminAddBookTag(c *fiber.Ctx) error { db := ep.DB data := schemas.TagsAddSchema{} errCode, errData := ValidateRequest(c, &data); @@ -116,7 +116,7 @@ func (ep Endpoint) AdminUpdateBookGenre(c *fiber.Ctx) error { return c.Status(200).JSON(ResponseMessage("Genre updated successfully")) } -// @Summary Update Tags +// @Summary Update Tag // @Description Update a tag to the app. // @Tags Admin | Books // @Accept json @@ -128,7 +128,7 @@ func (ep Endpoint) AdminUpdateBookGenre(c *fiber.Ctx) error { // @Failure 500 {object} utils.ErrorResponse "Internal server error" // @Router /admin/books/tags/{slug} [put] // @Security BearerAuth -func (ep Endpoint) AdminUpdateBookTags(c *fiber.Ctx) error { +func (ep Endpoint) AdminUpdateBookTag(c *fiber.Ctx) error { db := ep.DB tag := tagManager.GetBySlug(db, c.Params("slug")) @@ -152,6 +152,51 @@ func (ep Endpoint) AdminUpdateBookTags(c *fiber.Ctx) error { return c.Status(200).JSON(ResponseMessage("Tag updated successfully")) } +// @Summary Delete Genre +// @Description Delete a genre. +// @Tags Admin | Books +// @Accept json +// @Produce json +// @Param slug path string true "Genre slug" +// @Success 200 {object} schemas.ResponseSchema "Genre Deleted Successfully" +// @Failure 400 {object} utils.ErrorResponse "Invalid request data" +// @Failure 500 {object} utils.ErrorResponse "Internal server error" +// @Router /admin/books/genres/{slug} [delete] +// @Security BearerAuth +func (ep Endpoint) AdminDeleteBookGenre(c *fiber.Ctx) error { + db := ep.DB + genre := genreManager.GetBySlug(db, c.Params("slug")) + if genre == nil { + return c.Status(404).JSON(utils.NotFoundErr("Genre does not exist")) + } + db.Model(&genre).Association("Tags").Clear() + db.Delete(&genre) + return c.Status(200).JSON(ResponseMessage("Genre deleted successfully")) +} + +// @Summary Delete Tag +// @Description Delete a tag from the app. +// @Tags Admin | Books +// @Accept json +// @Produce json +// @Param slug path string true "Tag slug" +// @Success 200 {object} schemas.ResponseSchema "Tag delete successfully" +// @Failure 400 {object} utils.ErrorResponse "Invalid request data" +// @Failure 500 {object} utils.ErrorResponse "Internal server error" +// @Router /admin/books/tags/{slug} [delete] +// @Security BearerAuth +func (ep Endpoint) AdminDeleteBookTag(c *fiber.Ctx) error { + db := ep.DB + + tag := tagManager.GetBySlug(db, c.Params("slug")) + if tag == nil { + return c.Status(404).JSON(utils.NotFoundErr("Tag does not exist")) + } + db.Model(&tag).Association("Genres").Clear() + db.Delete(&tag) + return c.Status(200).JSON(ResponseMessage("Tag deleted successfully")) +} + // @Summary List Books with Pagination // @Description Retrieves a list of books with support for pagination and optional filtering based on book title. // @Tags Admin | Books diff --git a/routes/routers.go b/routes/routers.go index f0dd976..34c566d 100644 --- a/routes/routers.go +++ b/routes/routers.go @@ -118,10 +118,12 @@ func SetupRoutes(app *fiber.App, db *gorm.DB, ws *internetcomputer.WalletService // Admin Books (2) adminRouter.Get("/books", endpoint.AdminMiddleware, endpoint.AdminGetBooks) adminRouter.Get("/books/contracts", endpoint.AdminMiddleware, endpoint.AdminGetBookContracts) - adminRouter.Post("/books/genres", endpoint.AdminMiddleware, endpoint.AdminAddBookGenres) - adminRouter.Post("/books/tags", endpoint.AdminMiddleware, endpoint.AdminAddBookTags) + adminRouter.Post("/books/genres", endpoint.AdminMiddleware, endpoint.AdminAddBookGenre) + adminRouter.Post("/books/tags", endpoint.AdminMiddleware, endpoint.AdminAddBookTag) adminRouter.Put("/books/genres/:slug", endpoint.AdminMiddleware, endpoint.AdminUpdateBookGenre) - adminRouter.Put("/books/tags/:slug", endpoint.AdminMiddleware, endpoint.AdminUpdateBookTags) + adminRouter.Put("/books/tags/:slug", endpoint.AdminMiddleware, endpoint.AdminUpdateBookTag) + adminRouter.Delete("/books/genres/:slug", endpoint.AdminMiddleware, endpoint.AdminDeleteBookGenre) + adminRouter.Delete("/books/tags/:slug", endpoint.AdminMiddleware, endpoint.AdminDeleteBookTag) // Admin Waitlist (1) adminRouter.Get("/waitlist", endpoint.AdminMiddleware, endpoint.AdminGetWaitlist)