diff --git a/cmd/http-server/main.go b/cmd/http-server/main.go index dd8e912..6ee205b 100644 --- a/cmd/http-server/main.go +++ b/cmd/http-server/main.go @@ -99,6 +99,7 @@ func main() { expensesRoutes := api.Group("/expense", middleware.AuthMiddleware()) { expensesRoutes.POST("/add", handlers.ExpenseAdd) + expensesRoutes.POST("/bulk_create", handlers.ExpenseBulkCreate) expensesRoutes.GET("/:id", handlers.ExpenseGetId) expensesRoutes.GET("/all", handlers.ExpenseGetAll) expensesRoutes.PUT("/edit/:id", handlers.ExpensePutId) diff --git a/db/expense.go b/db/expense.go index a68c08c..7f1372e 100644 --- a/db/expense.go +++ b/db/expense.go @@ -20,6 +20,66 @@ type Expense struct { Type *Type } +type Helper_ExpenseBulk struct { + PropagateCardID bool + CardID uint + PropagateTypeID bool + TypeID uint + PropagateValue bool + Value uint64 + PropagateComment bool + Comment string + PropagateDate bool + Date time.Time + UserID uint +} + +func (he *Helper_ExpenseBulk) CreateExpenseFromChild(c Expense) *Expense { + var cardID uint + var typeID uint + var value uint64 + var comment string + var date time.Time + if he.PropagateCardID { + cardID = he.CardID + } else { + cardID = c.CardID + } + if he.PropagateTypeID { + typeID = he.TypeID + } else { + typeID = c.TypeID + } + if he.PropagateValue { + value = he.Value + } else { + value = c.Value + } + if he.PropagateComment { + comment = he.Comment + } else { + comment = c.Comment + } + if he.PropagateValue { + value = he.Value + } else { + value = c.Value + } + if he.PropagateDate { + date = he.Date + } else { + date = c.Date + } + return &Expense{ + CardID: cardID, + TypeID: typeID, + Value: value, + Comment: comment, + Date: date, + UserID: he.UserID, + } +} + // Implements db.UserIdentifiable:1 func (e Expense) GetID() uint { return e.ID diff --git a/handlers/expense.go b/handlers/expense.go index e700390..dd5805d 100644 --- a/handlers/expense.go +++ b/handlers/expense.go @@ -2,6 +2,7 @@ package handlers import ( "fmt" + "log" "git.qowevisa.me/Qowevisa/fin-check-api/db" "git.qowevisa.me/Qowevisa/fin-check-api/types" @@ -103,6 +104,85 @@ func ExpenseAdd(c *gin.Context) { })(c) } +// @Summary Add many expenses +// @Description Add expense by propagating main struct to every child in children field +// @Tags expense +// @Accept json +// @Produce json +// @Param Authorization header string true "Bearer token" +// @Param expense body types.DbExpenseBulk true "Expense" +// @Success 200 {object} types.Message +// @Failure 400 {object} types.ErrorResponse +// @Failure 500 {object} types.ErrorResponse +// @Security ApiKeyAuth +// @Router /expense/add [post] +func ExpenseBulkCreate(c *gin.Context) { + userID, err := GetUserID(c) + if err != nil { + c.JSON(500, types.ErrorResponse{Message: err.Error()}) + return + } + + var u types.DbExpenseBulk + if err := c.ShouldBindJSON(&u); err != nil { + log.Printf("err is %v\n", err) + c.JSON(400, types.ErrorResponse{Message: "Invalid request"}) + return + } + if u.IsEveryFieldPropagated() { + c.JSON(400, types.ErrorResponse{Message: "You can't just try to propagate every field for children."}) + return + } + he := &db.Helper_ExpenseBulk{ + PropagateCardID: u.PropagateCardID, + CardID: u.CardID, + PropagateTypeID: u.PropagateTypeID, + TypeID: u.TypeID, + PropagateValue: u.PropagateValue, + Value: u.Value, + PropagateComment: u.PropagateComment, + Comment: u.Comment, + PropagateDate: u.PropagateDate, + Date: u.Date, + UserID: userID, + } + + var expenses []*db.Expense + for _, child := range u.Children { + c := db.Expense{ + CardID: child.CardID, + TypeID: child.TypeID, + Value: child.Value, + Comment: child.Comment, + Date: child.Date, + } + expenses = append(expenses, he.CreateExpenseFromChild(c)) + } + + dbc := db.Connect() + var whatToRollback []*db.Expense + shouldRollback := false + defer func() { + if shouldRollback { + for _, e := range whatToRollback { + if err := dbc.Delete(e).Error; err != nil { + log.Printf("dbc.Delete ERROR: %v\n", err) + } + } + } + }() + for _, entity := range expenses { + if err := dbc.Create(entity).Error; err != nil { + shouldRollback = true + c.JSON(500, types.ErrorResponse{Message: err.Error()}) + return + } + whatToRollback = append(whatToRollback, entity) + } + + c.JSON(200, types.Message{Info: fmt.Sprintf("%d entities were created successfully!", len(expenses))}) +} + // @Summary Edit expense by id // @Description Edit expense by id // @Tags expense diff --git a/types/types.go b/types/types.go index 9f02e09..c4cbb84 100644 --- a/types/types.go +++ b/types/types.go @@ -87,6 +87,24 @@ type DbExpense struct { ShowValue string `json:"show_value" example:"10.35$"` } +type DbExpenseBulk struct { + PropagateCardID bool `json:"propagate_card_id" example:"false"` + CardID uint `json:"card_id" example:"1"` + PropagateTypeID bool `json:"propagate_type_id" example:"false"` + TypeID uint `json:"type_id" example:"1"` + PropagateValue bool `json:"propagate_value" example:"false"` + Value uint64 `json:"value" example:"1025"` + PropagateComment bool `json:"propagate_comment" example:"false"` + Comment string `json:"comment" example:"some comment"` + PropagateDate bool `json:"propagate_date" example:"false"` + Date time.Time `json:"date" example:"29/11/2001 12:00"` + Children []DbExpense `json:"children"` +} + +func (e DbExpenseBulk) IsEveryFieldPropagated() bool { + return e.PropagateCardID && e.PropagateTypeID && e.PropagateValue && e.PropagateComment && e.PropagateDate +} + type DbTransfer struct { ID uint `json:"id" example:"1"` FromCardID uint `json:"from_card_id" example:"1"`