github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/internal/web/api/spend.go (about)

     1  package api
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net/http"
     7  
     8  	"github.com/ShoshinNikita/budget-manager/internal/db"
     9  	"github.com/ShoshinNikita/budget-manager/internal/logger"
    10  	"github.com/ShoshinNikita/budget-manager/internal/pkg/money"
    11  	"github.com/ShoshinNikita/budget-manager/internal/pkg/reqid"
    12  	"github.com/ShoshinNikita/budget-manager/internal/web/api/models"
    13  	"github.com/ShoshinNikita/budget-manager/internal/web/utils"
    14  )
    15  
    16  type SpendsHandlers struct {
    17  	db  SpendsDB
    18  	log logger.Logger
    19  }
    20  
    21  type SpendsDB interface {
    22  	AddSpend(ctx context.Context, args db.AddSpendArgs) (id uint, err error)
    23  	EditSpend(ctx context.Context, args db.EditSpendArgs) error
    24  	RemoveSpend(ctx context.Context, id uint) error
    25  }
    26  
    27  // @Summary Create Spend
    28  // @Tags Spends
    29  // @Router /api/spends [post]
    30  // @Accept json
    31  // @Param body body models.AddSpendReq true "New Spend"
    32  // @Produce json
    33  // @Success 201 {object} models.AddSpendResp
    34  // @Failure 400 {object} models.Response "Invalid request"
    35  // @Failure 404 {object} models.Response "Day doesn't exist"
    36  // @Failure 500 {object} models.Response "Internal error"
    37  //
    38  func (h SpendsHandlers) AddSpend(w http.ResponseWriter, r *http.Request) {
    39  	ctx := r.Context()
    40  	log := reqid.FromContextToLogger(ctx, h.log)
    41  
    42  	// Decode
    43  	req := &models.AddSpendReq{}
    44  	if ok := utils.DecodeRequest(w, r, log, req); !ok {
    45  		return
    46  	}
    47  	log = log.WithRequest(req)
    48  
    49  	// Process
    50  	args := db.AddSpendArgs{
    51  		DayID:  req.DayID,
    52  		Title:  req.Title,
    53  		TypeID: req.TypeID,
    54  		Notes:  req.Notes,
    55  		Cost:   money.FromFloat(req.Cost),
    56  	}
    57  	id, err := h.db.AddSpend(ctx, args)
    58  	if err != nil {
    59  		switch {
    60  		case errors.Is(err, db.ErrDayNotExist):
    61  			utils.EncodeError(ctx, w, log, err, http.StatusNotFound)
    62  		case errors.Is(err, db.ErrSpendTypeNotExist):
    63  			utils.EncodeError(ctx, w, log, err, http.StatusBadRequest)
    64  		default:
    65  			utils.EncodeInternalError(ctx, w, log, "couldn't add Spend", err)
    66  		}
    67  		return
    68  	}
    69  	log = log.WithField("id", id)
    70  	log.Debug("Spend was successfully added")
    71  
    72  	resp := &models.AddSpendResp{
    73  		ID: id,
    74  	}
    75  	utils.Encode(ctx, w, log, utils.EncodeResponse(resp), utils.EncodeStatusCode(http.StatusCreated))
    76  }
    77  
    78  // @Summary Edit Spend
    79  // @Tags Spends
    80  // @Router /api/spends [put]
    81  // @Accept json
    82  // @Param body body models.EditSpendReq true "Updated Spend"
    83  // @Produce json
    84  // @Success 200 {object} models.Response
    85  // @Failure 400 {object} models.Response "Invalid request"
    86  // @Failure 404 {object} models.Response "Spend doesn't exist"
    87  // @Failure 500 {object} models.Response "Internal error"
    88  //
    89  func (h SpendsHandlers) EditSpend(w http.ResponseWriter, r *http.Request) {
    90  	ctx := r.Context()
    91  	log := reqid.FromContextToLogger(ctx, h.log)
    92  
    93  	// Decode
    94  	req := &models.EditSpendReq{}
    95  	if ok := utils.DecodeRequest(w, r, log, req); !ok {
    96  		return
    97  	}
    98  	log = log.WithRequest(req)
    99  
   100  	// Process
   101  	args := db.EditSpendArgs{
   102  		ID:     req.ID,
   103  		Title:  req.Title,
   104  		Notes:  req.Notes,
   105  		TypeID: req.TypeID,
   106  	}
   107  	if req.Cost != nil {
   108  		cost := money.FromFloat(*req.Cost)
   109  		args.Cost = &cost
   110  	}
   111  	err := h.db.EditSpend(ctx, args)
   112  	if err != nil {
   113  		switch {
   114  		case errors.Is(err, db.ErrSpendNotExist):
   115  			utils.EncodeError(ctx, w, log, err, http.StatusNotFound)
   116  		case errors.Is(err, db.ErrSpendTypeNotExist):
   117  			utils.EncodeError(ctx, w, log, err, http.StatusBadRequest)
   118  		default:
   119  			utils.EncodeInternalError(ctx, w, log, "couldn't edit Spend", err)
   120  		}
   121  		return
   122  	}
   123  	log.Debug("Spend was successfully edited")
   124  
   125  	utils.Encode(ctx, w, log)
   126  }
   127  
   128  // @Summary Remove Spend
   129  // @Tags Spends
   130  // @Router /api/spends [delete]
   131  // @Accept json
   132  // @Param body body models.RemoveSpendReq true "Updated Spend"
   133  // @Produce json
   134  // @Success 200 {object} models.Response
   135  // @Failure 400 {object} models.Response "Invalid request"
   136  // @Failure 404 {object} models.Response "Spend doesn't exist"
   137  // @Failure 500 {object} models.Response "Internal error"
   138  //
   139  func (h SpendsHandlers) RemoveSpend(w http.ResponseWriter, r *http.Request) {
   140  	ctx := r.Context()
   141  	log := reqid.FromContextToLogger(ctx, h.log)
   142  
   143  	// Decode
   144  	req := &models.RemoveSpendReq{}
   145  	if ok := utils.DecodeRequest(w, r, log, req); !ok {
   146  		return
   147  	}
   148  	log = log.WithRequest(req)
   149  
   150  	// Process
   151  	err := h.db.RemoveSpend(ctx, req.ID)
   152  	if err != nil {
   153  		switch {
   154  		case errors.Is(err, db.ErrSpendNotExist):
   155  			utils.EncodeError(ctx, w, log, err, http.StatusNotFound)
   156  		default:
   157  			utils.EncodeInternalError(ctx, w, log, "couldn't remove Spend", err)
   158  		}
   159  		return
   160  	}
   161  	log.Debug("Spend was successfully removed")
   162  
   163  	utils.Encode(ctx, w, log)
   164  }