Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
9.9 kB
1
Indexable
Never
package handler

import (
	"encoding/json"
	"net/http"
	"strconv"

	"github.com/go-chi/chi/v5"
	"github.com/melisource/fury_bootcamp-go-w11-s4-06-04/internal"

	"github.com/bootcamp-go/web/request"
	"github.com/bootcamp-go/web/response"
)

// SectionJSON is the json representation of a section
type SectionJSONData struct {
	ID                 int     `json:"id"`
	SectionNumber      int     `json:"section_number"`
	CurrentTemperature float64 `json:"current_temperature"`
	MinimumTemperature float64 `json:"minimum_temperature"`
	CurrentCapacity    int     `json:"current_capacity"`
	MinimumCapacity    int     `json:"minimum_capacity"`
	MaximumCapacity    int     `json:"maximum_capacity"`
	WarehouseID        int     `json:"warehouse_id"`
	ProductTypeID      int     `json:"product_type_id"`
}

type SectionJSON struct {
	Data []SectionJSONData `json:"data"`
}
type SectionJSONV2 struct {
	Data SectionJSONData `json:"data"`
}

// NewSectionDefault creates a new instance of the section handler
func NewSectionDefault(sv internal.SectionService) *SectionHandler {
	return &SectionHandler{
		sv: sv,
	}
}

// Function to serialize a section to json
func serializeSection(section internal.Section) SectionJSONData {
	return SectionJSONData{
		ID:                 section.ID,
		SectionNumber:      section.SectionNumber,
		CurrentTemperature: section.CurrentTemperature,
		MinimumTemperature: section.MinimumTemperature,
		CurrentCapacity:    section.CurrentCapacity,
		MinimumCapacity:    section.MinimumCapacity,
		MaximumCapacity:    section.MaximumCapacity,
		WarehouseID:        section.WarehouseID,
		ProductTypeID:      section.ProductTypeID,
	}
}

// Function to deserialize a section from json
func deserializeSection(r *http.Request) (SectionJSONData, error) {
	var bodyRequest SectionJSONData
	err := json.NewDecoder(r.Body).Decode(&bodyRequest)
	return bodyRequest, err
}

// SectionHandlerInterface is the interface of the section handler
type SectionHandlerInterface interface {
	// Methods
	// - GetAll returns all sections
	GetAll() http.HandlerFunc
	// - GetByID returns a section
	GetByID() http.HandlerFunc
	// - Create creates a section
	Create() http.HandlerFunc
	// - Update updates a section
	Update() http.HandlerFunc
	// - Delete deletes a section
	Delete() http.HandlerFunc
	// - GetProductsByIDSections returns all the products
	GetProductsByIDSections() http.HandlerFunc
}

// SectionDefault is the default implementation of the section handler
type SectionHandler struct {
	// sv is the service used by the handler
	sv internal.SectionService
}

// GetAll returns all sections
func (h *SectionHandler) GetAll() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Request
		// ...
		// This method dont need request body

		// Process
		// - Use the service to get all sections
		sections, err := h.sv.FindAll()
		if err != nil {
			// - If there is an error, return the error
			response.Error(w, http.StatusInternalServerError, "Error internal server")
			return
		}

		// - Serialize the sections to json
		sectionsJSONData := make([]SectionJSONData, len(sections))
		for i, section := range sections {
			sectionsJSONData[i] = serializeSection(section)
		}

		sectionsJSON := SectionJSON{
			Data: sectionsJSONData,
		}

		// Response
		// - Write the response
		response.JSON(w, http.StatusOK, sectionsJSON)

	}
}

// GetByID returns a section
func (h *SectionHandler) GetByID() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Request
		// - Get the id from the url
		idStr := chi.URLParam(r, "id")
		// - Convert the id to int
		id, err := strconv.Atoi(idStr)
		if err != nil {
			response.Error(w, http.StatusBadRequest, "Error input request")
			return
		}

		// Process
		// - Use the service to get a section
		section, err := h.sv.FindByID(id)
		if err != nil {
			switch err {
			case internal.ErrSectionNotFound:
				response.Error(w, http.StatusNotFound, "Section not found")
			default:
				response.Error(w, http.StatusInternalServerError, "Internal Error")

			}
			return
		}

		// Response

		// - Serialize the section to json
		sectionJSONData := serializeSection(section)
		// - Write the response
		SectionJSON := SectionJSONV2{
			Data: sectionJSONData,
		}

		response.JSON(w, http.StatusOK, SectionJSON)

	}
}

// Create creates a new section
func (h *SectionHandler) Create() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Request

		// - Deserialize to know if some input data is wrong
		section, err := deserializeSection(r)
		if err != nil {
			response.Error(w, http.StatusUnprocessableEntity, "Unprocessable entity")
			return
		}

		// Process
		// - Use the service to create a section
		// Convert sectionJSONData to internal.Section
		sectionInternal := internal.Section{
			ID:                 section.ID,
			SectionNumber:      section.SectionNumber,
			CurrentTemperature: section.CurrentTemperature,
			MinimumTemperature: section.MinimumTemperature,
			CurrentCapacity:    section.CurrentCapacity,
			MinimumCapacity:    section.MinimumCapacity,
			MaximumCapacity:    section.MaximumCapacity,
			WarehouseID:        section.WarehouseID,
			ProductTypeID:      section.ProductTypeID,
		}

		if err := h.sv.Save(&sectionInternal); err != nil {
			switch err {
			case internal.ErrSectionRepositoryNotFound:
				response.Error(w, http.StatusUnprocessableEntity, "Unprocessable entity")
			case internal.ErrSectionRepositoryDuplicated:
				response.Error(w, http.StatusConflict, "Conflict")
			case internal.ErrFieldEmpty:
				response.Error(w, http.StatusUnprocessableEntity, "Bad Request")
			default:
				response.Error(w, http.StatusInternalServerError, "Internal Error")
			}
			return
		}
		// Response
		// return a sectionJSONV2
		sectionSerialized := serializeSection(sectionInternal)
		sectionJSONData := SectionJSONV2{
			Data: sectionSerialized,
		}

		response.JSON(w, http.StatusCreated, sectionJSONData)

	}
}

// Update updates a section
func (h *SectionHandler) Update() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Request
		// - Get the id from the url
		id, err := strconv.Atoi(chi.URLParam(r, "id"))
		if err != nil {
			response.Error(w, http.StatusBadRequest, "Invalid id")
			return
		}
		// -Get the sections from the service

		section, err := h.sv.FindByID(id)
		if err != nil {
			switch err {
			case internal.ErrSectionNotFound:
				response.Error(w, http.StatusNotFound, "Section not found")
			default:
				response.Error(w, http.StatusInternalServerError, "Internal Error")

			}
			return
		}
		// Process
		// Get the current section and the body to update and update the section according with the body parameters
		// - Serialize the internal.Section to SectionJSONData
		reqBody := serializeSection(section)
		// - Get the body
		if err := request.JSON(r, &reqBody); err != nil {
			response.Error(w, http.StatusBadRequest, "Invalid body")
			return
		}

		// -Serialize the SectionJSONData to internal.Section
		toUpdate := internal.Section{
			ID:                 reqBody.ID,
			SectionNumber:      reqBody.SectionNumber,
			CurrentTemperature: reqBody.CurrentTemperature,
			MinimumTemperature: reqBody.MinimumTemperature,
			CurrentCapacity:    reqBody.CurrentCapacity,
			MinimumCapacity:    reqBody.MinimumCapacity,
			MaximumCapacity:    reqBody.MaximumCapacity,
			WarehouseID:        reqBody.WarehouseID,
			ProductTypeID:      reqBody.ProductTypeID,
		}
		// - Update the section
		if err := h.sv.Update(&toUpdate); err != nil {
			switch err {
			case internal.ErrSectionRepositoryNotFound:
				response.Error(w, http.StatusUnprocessableEntity, "Unprocessable entity")
			default:
				response.Error(w, http.StatusInternalServerError, "Internal Error")
			}
			return
		}
		// return a sectionJSONV2
		sectionSerialized := serializeSection(toUpdate)
		sectionJSONData := SectionJSONV2{
			Data: sectionSerialized,
		}

		response.JSON(w, http.StatusOK, sectionJSONData)

	}
}

// Delete deletes a section
func (h *SectionHandler) Delete() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {

		// Request
		// - Get the id from the url
		id, err := strconv.Atoi(chi.URLParam(r, "id"))
		if err != nil {
			response.Error(w, http.StatusBadRequest, "Invalid id")
			return
		}

		// Process
		err = h.sv.Delete(id)

		// Response
		if err != nil {
			switch err {
			case internal.ErrSectionNotFound:
				response.Error(w, http.StatusNotFound, "Section not found")
			default:
				response.Error(w, http.StatusInternalServerError, "Internal Error")

			}
			return
		}
		response.JSON(w, http.StatusNoContent, map[string]string{"message": "Section was deleted"})
	}
}

// GetProductsByIDSections returns a report of products by section
func (h *SectionHandler) GetProductsByIDSections() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {

		// Request
		// - Get the id from the url
		idParam := r.URL.Query().Get("id")
		id := -1
		if idParam != "" { // Case 1: Get a specific section with a report of products
			var err error
			id, err = strconv.Atoi(idParam)
			if err != nil {
				response.Error(w, http.StatusBadRequest, "Invalid id")
				return
			}
		}
		// Process
		// - Use the service to get a report of products by section
		products, err := h.sv.GetAllProducts(id)
		if err != nil {
			switch err {
			case internal.ErrSectionNotFound:
				response.Error(w, http.StatusNotFound, "Section not found")
			case internal.ErrSectionRepositoryNotFound:
				response.Error(w, http.StatusNotFound, "Section not found entity")
			default:
				response.Error(w, http.StatusInternalServerError, "Internal Error")
			}
			return
		}
		// Wrap the result in a data object
		responseObj := map[string]interface{}{
			"data": products,
		}
		// Response
		// Send the id as a
		response.JSON(w, http.StatusOK, responseObj)
	}
}
Leave a Comment