github.com/shoshinnikita/budget-manager@v0.7.1-0.20220131195411-8c46ff1c6778/internal/web/api/income.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 IncomesHandlers struct {
    17  	db  IncomesDB
    18  	log logger.Logger
    19  }
    20  
    21  type IncomesDB interface {
    22  	AddIncome(ctx context.Context, args db.AddIncomeArgs) (id uint, err error)
    23  	EditIncome(ctx context.Context, args db.EditIncomeArgs) error
    24  	RemoveIncome(ctx context.Context, id uint) error
    25  }
    26  
    27  // @Summary Create Income
    28  // @Tags Incomes
    29  // @Router /api/incomes [post]
    30  // @Accept json
    31  // @Param body body models.AddIncomeReq true "New Income"
    32  // @Produce json
    33  // @Success 201 {object} models.AddIncomeResp
    34  // @Failure 400 {object} models.Response "Invalid request"
    35  // @Failure 404 {object} models.Response "Month doesn't exist"
    36  // @Failure 500 {object} models.Response "Internal error"
    37  //
    38  func (h IncomesHandlers) AddIncome(w http.ResponseWriter, r *http.Request) {
    39  	ctx := r.Context()
    40  	log := reqid.FromContextToLogger(ctx, h.log)
    41  
    42  	// Decode
    43  	req := &models.AddIncomeReq{}
    44  	if ok := utils.DecodeRequest(w, r, log, req); !ok {
    45  		return
    46  	}
    47  	log = log.WithRequest(req)
    48  
    49  	// Process
    50  	args := db.AddIncomeArgs{
    51  		MonthID: req.MonthID,
    52  		Title:   req.Title,
    53  		Notes:   req.Notes,
    54  		Income:  money.FromFloat(req.Income),
    55  	}
    56  	id, err := h.db.AddIncome(ctx, args)
    57  	if err != nil {
    58  		switch {
    59  		case errors.Is(err, db.ErrMonthNotExist):
    60  			utils.EncodeError(ctx, w, log, err, http.StatusNotFound)
    61  		default:
    62  			utils.EncodeInternalError(ctx, w, log, "couldn't add Income", err)
    63  		}
    64  		return
    65  	}
    66  	log = log.WithField("id", id)
    67  	log.Debug("Income was successfully added")
    68  
    69  	resp := &models.AddIncomeResp{
    70  		ID: id,
    71  	}
    72  	utils.Encode(ctx, w, log, utils.EncodeResponse(resp), utils.EncodeStatusCode(http.StatusCreated))
    73  }
    74  
    75  // @Summary Edit Income
    76  // @Tags Incomes
    77  // @Router /api/incomes [put]
    78  // @Accept json
    79  // @Param body body models.EditIncomeReq true "Updated Income"
    80  // @Produce json
    81  // @Success 200 {object} models.Response
    82  // @Failure 400 {object} models.Response "Invalid request"
    83  // @Failure 404 {object} models.Response "Income doesn't exist"
    84  // @Failure 500 {object} models.Response "Internal error"
    85  //
    86  func (h IncomesHandlers) EditIncome(w http.ResponseWriter, r *http.Request) {
    87  	ctx := r.Context()
    88  	log := reqid.FromContextToLogger(ctx, h.log)
    89  
    90  	// Decode
    91  	req := &models.EditIncomeReq{}
    92  	if ok := utils.DecodeRequest(w, r, log, req); !ok {
    93  		return
    94  	}
    95  	log = log.WithRequest(req)
    96  
    97  	// Process
    98  	args := db.EditIncomeArgs{
    99  		ID:    req.ID,
   100  		Title: req.Title,
   101  		Notes: req.Notes,
   102  	}
   103  	if req.Income != nil {
   104  		income := money.FromFloat(*req.Income)
   105  		args.Income = &income
   106  	}
   107  	err := h.db.EditIncome(ctx, args)
   108  	if err != nil {
   109  		switch {
   110  		case errors.Is(err, db.ErrIncomeNotExist):
   111  			utils.EncodeError(ctx, w, log, err, http.StatusNotFound)
   112  		default:
   113  			utils.EncodeInternalError(ctx, w, log, "couldn't edit Income", err)
   114  		}
   115  		return
   116  	}
   117  	log.Debug("Income was successfully edited")
   118  
   119  	utils.Encode(ctx, w, log)
   120  }
   121  
   122  // @Summary Remove Income
   123  // @Tags Incomes
   124  // @Router /api/incomes [delete]
   125  // @Accept json
   126  // @Param body body models.RemoveIncomeReq true "Income id"
   127  // @Produce json
   128  // @Success 200 {object} models.Response
   129  // @Failure 400 {object} models.Response "Invalid request"
   130  // @Failure 404 {object} models.Response "Income doesn't exist"
   131  // @Failure 500 {object} models.Response "Internal error"
   132  //
   133  func (h IncomesHandlers) RemoveIncome(w http.ResponseWriter, r *http.Request) {
   134  	ctx := r.Context()
   135  	log := reqid.FromContextToLogger(ctx, h.log)
   136  
   137  	// Decode
   138  	req := &models.RemoveIncomeReq{}
   139  	if ok := utils.DecodeRequest(w, r, log, req); !ok {
   140  		return
   141  	}
   142  	log = log.WithRequest(req)
   143  
   144  	// Process
   145  	err := h.db.RemoveIncome(ctx, req.ID)
   146  	if err != nil {
   147  		switch {
   148  		case errors.Is(err, db.ErrIncomeNotExist):
   149  			utils.EncodeError(ctx, w, log, err, http.StatusNotFound)
   150  		default:
   151  			utils.EncodeInternalError(ctx, w, log, "couldn't remove Income", err)
   152  		}
   153  		return
   154  	}
   155  	log.Debug("Income was successfully removed")
   156  
   157  	utils.Encode(ctx, w, log)
   158  }