From d3397d8e4c8c5611fb8908de0da8f81ac537e40f Mon Sep 17 00:00:00 2001 From: Anatoly Prohacky Date: Fri, 28 Apr 2023 09:35:30 +1000 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D0=B4=D0=B3=D0=BE=D1=82=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D0=B0=20=D0=B4=D0=BB=D1=8F=20cli=20+=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{handler/convert.go => file/file.go} | 64 +++++-------------- internal/controller/handler/handler.go | 59 +++++++++++++++++ internal/service/convert.go | 49 ++++++++++++++ 3 files changed, 124 insertions(+), 48 deletions(-) rename internal/controller/{handler/convert.go => file/file.go} (52%) create mode 100644 internal/service/convert.go diff --git a/internal/controller/handler/convert.go b/internal/controller/file/file.go similarity index 52% rename from internal/controller/handler/convert.go rename to internal/controller/file/file.go index b832d6b..55eb610 100644 --- a/internal/controller/handler/convert.go +++ b/internal/controller/file/file.go @@ -1,24 +1,32 @@ -package handler +package file import ( - "bytes" - "encoding/json" "errors" "net/http" - "strconv" "github.com/gin-gonic/gin" "github.com/google/uuid" - "github.com/xuri/excelize/v2" + "github.com/sirupsen/logrus" "gitstore.ru/tolikproh/sirius/internal/model" + "gitstore.ru/tolikproh/sirius/internal/service" ) +type Handler struct { + log *logrus.Logger + cfg *model.Config +} + var ( TEXT_TYPES = map[string]interface{}{ "text/plain; charset=utf-8": nil, } ) +func New(cfg *model.Config, log *logrus.Logger) *Handler { + // HTTP Server + return &Handler{cfg: cfg, log: log} +} + func (s *Handler) GinConvert(c *gin.Context) { sessionId := uuid.New().String() @@ -40,8 +48,6 @@ func (s *Handler) GinConvert(c *gin.Context) { buffer := make([]byte, fileHeader.Size) file.Read(buffer) - buffer = bytes.TrimPrefix(buffer, []byte("\xef\xbb\xbf")) - fileType := http.DetectContentType(buffer) // Validate File Type @@ -53,55 +59,17 @@ func (s *Handler) GinConvert(c *gin.Context) { return } - if !json.Valid(buffer) { - s.log.Errorf("session id: %s. error code: 003. formated data not json", sessionId) - c.JSON(http.StatusBadRequest, gin.H{ - "error": errors.New("formated data not json").Error(), - }) - return - } - - var sirius model.Sirius - - err = json.Unmarshal(buffer, &sirius) + respBuff, err := service.SiriusConv(buffer) if err != nil { s.log.Errorf("session id: %s. error code: 004. %s", sessionId, err.Error()) c.JSON(http.StatusBadRequest, gin.H{ - "error": errors.New("Error unmarshal file").Error(), + "error": err.Error(), }) return } - buff, err := SaveToExel(sirius.NewBolid().ZoneInfo()) - if err != nil { - s.log.Errorf("session id: %s. error code: 005. %s", sessionId, err.Error()) - c.JSON(http.StatusBadRequest, gin.H{ - "error": errors.New("Error create file").Error(), - }) - return - } - - c.Data(200, "application/vnd.ms-excel", buff.Bytes()) + c.Data(200, "application/vnd.ms-excel", respBuff.Bytes()) s.log.Printf("session id: %s.converted: ok. filename: %s; file size: %d bytes", sessionId, fileHeader.Filename, fileHeader.Size) } - -func SaveToExel(data []model.ZoneInfo) (*bytes.Buffer, error) { - f := excelize.NewFile() - defer f.Close() - - // Create a new sheet. - f.SetCellValue("Sheet1", "A2", "№ зоны") - f.SetCellValue("Sheet1", "B2", "Описание зоны") - f.SetCellValue("Sheet1", "C2", "Адреса в зоне") - i := 3 - for _, d := range data { - f.SetCellValue("Sheet1", "A"+strconv.Itoa(i), d.ZoneNum) - f.SetCellValue("Sheet1", "B"+strconv.Itoa(i), d.ZoneName) - f.SetCellValue("Sheet1", "C"+strconv.Itoa(i), d.InputString()) - i++ - } - - return f.WriteToBuffer() -} diff --git a/internal/controller/handler/handler.go b/internal/controller/handler/handler.go index fd5e53c..2bb1a68 100644 --- a/internal/controller/handler/handler.go +++ b/internal/controller/handler/handler.go @@ -1,8 +1,14 @@ package handler import ( + "errors" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" "github.com/sirupsen/logrus" "gitstore.ru/tolikproh/sirius/internal/model" + "gitstore.ru/tolikproh/sirius/internal/service" ) type Handler struct { @@ -10,7 +16,60 @@ type Handler struct { cfg *model.Config } +var ( + TEXT_TYPES = map[string]interface{}{ + "text/plain; charset=utf-8": nil, + } +) + func New(cfg *model.Config, log *logrus.Logger) *Handler { // HTTP Server return &Handler{cfg: cfg, log: log} } + +func (s *Handler) GinConvert(c *gin.Context) { + sessionId := uuid.New().String() + + s.log.Printf("start convert. session id: %s; user agent: %s; remote addr: %s; file size [byte]: %d", + sessionId, c.Request.UserAgent(), c.Request.RemoteAddr, c.Request.ContentLength) + + c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, s.cfg.Srv.MaxSizeFile<<20) + + file, fileHeader, err := c.Request.FormFile("file") + if err != nil { + s.log.Errorf("session id: %s. error code: 001. %s", sessionId, err.Error()) + c.JSON(http.StatusBadRequest, gin.H{ + "error": err.Error(), + }) + return + } + defer file.Close() + + buffer := make([]byte, fileHeader.Size) + file.Read(buffer) + + fileType := http.DetectContentType(buffer) + + // Validate File Type + if _, ex := TEXT_TYPES[fileType]; !ex { + s.log.Errorf("session id: %s. error code: 002. formated data not text/plain", sessionId) + c.JSON(http.StatusBadRequest, gin.H{ + "error": errors.New("formated data not text/plain").Error(), + }) + return + } + + respBuff, err := service.SiriusConv(buffer) + if err != nil { + s.log.Errorf("session id: %s. error code: 004. %s", sessionId, err.Error()) + c.JSON(http.StatusBadRequest, gin.H{ + "error": err.Error(), + }) + return + } + + c.Data(200, "application/vnd.ms-excel", respBuff.Bytes()) + + s.log.Printf("session id: %s.converted: ok. filename: %s; file size: %d bytes", sessionId, fileHeader.Filename, fileHeader.Size) + +} diff --git a/internal/service/convert.go b/internal/service/convert.go new file mode 100644 index 0000000..930c1e5 --- /dev/null +++ b/internal/service/convert.go @@ -0,0 +1,49 @@ +package service + +import ( + "bytes" + "encoding/json" + "errors" + "strconv" + + "github.com/xuri/excelize/v2" + "gitstore.ru/tolikproh/sirius/internal/model" +) + +func SiriusConv(data []byte) (*bytes.Buffer, error) { + + data = bytes.TrimPrefix(data, []byte("\xef\xbb\xbf")) + + if !json.Valid(data) { + return nil, errors.New("formated data not json") + } + + var sirius model.Sirius + + err := json.Unmarshal(data, &sirius) + if err != nil { + return nil, errors.New("Error unmarshal file") + } + + return SaveToExel(sirius.NewBolid().ZoneInfo()) + +} + +func SaveToExel(data []model.ZoneInfo) (*bytes.Buffer, error) { + f := excelize.NewFile() + defer f.Close() + + // Create a new sheet. + f.SetCellValue("Sheet1", "A2", "№ зоны") + f.SetCellValue("Sheet1", "B2", "Описание зоны") + f.SetCellValue("Sheet1", "C2", "Адреса в зоне") + i := 3 + for _, d := range data { + f.SetCellValue("Sheet1", "A"+strconv.Itoa(i), d.ZoneNum) + f.SetCellValue("Sheet1", "B"+strconv.Itoa(i), d.ZoneName) + f.SetCellValue("Sheet1", "C"+strconv.Itoa(i), d.InputString()) + i++ + } + + return f.WriteToBuffer() +}