From 7b9ff49444695b068e396d929ae839be537d8512 Mon Sep 17 00:00:00 2001 From: Victor Lacasse-Beaudoin Date: Tue, 5 Sep 2023 18:03:28 -0400 Subject: [PATCH] Permettre upload par CSV --- data/data.go | 4 ++-- go.mod | 1 + go.sum | 2 ++ handlers/insert.go | 46 ++++++++++++++++++++++++++++++++++++++++------ models/models.go | 14 +++++++------- 5 files changed, 52 insertions(+), 15 deletions(-) diff --git a/data/data.go b/data/data.go index 9a16342..ec603f7 100644 --- a/data/data.go +++ b/data/data.go @@ -87,7 +87,7 @@ func (d *DataClient) InsertMembres(membres []models.Membre) (int64, error) { tx.Rollback() return 0, errors.New("Cannot insert membre with no membre_id") } - result, err := tx.NamedExec("INSERT INTO membres (id, last_name, first_name, prefered_name, programme_id) VALUES (:id, :last_name, :first_name, :prefered_name, :programme_id);", &membre) + result, err := tx.NamedExec("INSERT INTO membres (id, last_name, first_name, prefered_name, programme_id) VALUES (:id, :last_name, :first_name, :prefered_name, :programme_id) ON CONFLICT (id) DO NOTHING;", &membre) if err != nil { tx.Rollback() return 0, err @@ -124,7 +124,7 @@ func (d *DataClient) InsertProgrammes(programmes []models.Programme) (int64, err return 0, errors.New("Cannot insert programme with no programme_id") } - result, err := tx.NamedExec("INSERT INTO programmes (id, titre) VALUES (:id, :titre);", &programme) + result, err := tx.NamedExec("INSERT INTO programmes (id, titre) VALUES (:id, :titre) ON CONFLICT DO NOTHING;", &programme) if err != nil { tx.Rollback() return 0, err diff --git a/go.mod b/go.mod index 708678c..5bd54b0 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module git.agecem.com/agecem/bottin/v5 go 1.20 require ( + github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d github.com/jackc/pgx v3.6.2+incompatible github.com/jmoiron/sqlx v1.3.5 github.com/labstack/echo/v4 v4.10.2 diff --git a/go.sum b/go.sum index 03ed3fe..7fa5e1c 100644 --- a/go.sum +++ b/go.sum @@ -66,6 +66,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d h1:KbPOUXFUDJxwZ04vbmDOc3yuruGvVO+LOa7cVER3yWw= +github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= diff --git a/handlers/insert.go b/handlers/insert.go index 7452659..789beb3 100644 --- a/handlers/insert.go +++ b/handlers/insert.go @@ -1,12 +1,16 @@ package handlers import ( + "encoding/csv" + "io" "net/http" "git.agecem.com/agecem/bottin/v5/data" "git.agecem.com/agecem/bottin/v5/models" "git.agecem.com/agecem/bottin/v5/responses" "github.com/labstack/echo/v4" + + "github.com/gocarina/gocsv" ) func PostMembres(c echo.Context) error { @@ -32,9 +36,21 @@ func PostMembres(c echo.Context) error { return c.JSON(response.StatusCode, response) } case "text/csv": - response.StatusCode = http.StatusNotImplemented - response.Message = "Not Implemented" - return c.JSON(response.StatusCode, response) + body := c.Request().Body + if body == nil { + response.StatusCode = http.StatusBadRequest + response.Message = "Request body is empty" + return c.JSON(response.StatusCode, response) + } + defer body.Close() + + // Parse the CSV data from the request body using gocsv. + if err := gocsv.Unmarshal(body, &membres); err != nil { + response.StatusCode = http.StatusBadRequest + response.Message = "Could not unmarshal into membres" + response.Error = err.Error() + return c.JSON(response.StatusCode, response) + } default: response.StatusCode = http.StatusBadRequest response.Message = "Invalid Content-Type" @@ -85,9 +101,27 @@ func PostProgrammes(c echo.Context) error { return c.JSON(response.StatusCode, response) } case "text/csv": - response.StatusCode = http.StatusNotImplemented - response.Message = "Not Implemented" - return c.JSON(response.StatusCode, response) + body := c.Request().Body + if body == nil { + response.StatusCode = http.StatusBadRequest + response.Message = "Request body is empty" + return c.JSON(response.StatusCode, response) + } + defer body.Close() + + gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader { + r := csv.NewReader(in) + r.Comma = ';' + return r // Allows use ; as delimiter + }) + + // Parse the CSV data from the request body using gocsv. + if err := gocsv.Unmarshal(body, &programmes); err != nil { + response.StatusCode = http.StatusBadRequest + response.Message = "Could not unmarshal into programmes" + response.Error = err.Error() + return c.JSON(response.StatusCode, response) + } default: response.StatusCode = http.StatusBadRequest response.Message = "Invalid Content-Type" diff --git a/models/models.go b/models/models.go index 1589aee..845d28d 100644 --- a/models/models.go +++ b/models/models.go @@ -16,16 +16,16 @@ CREATE TABLE IF NOT EXISTS membres ( ` type Programme struct { - ID string `db:"id" json:"programme_id"` - Titre string `db:"titre" json:"nom_programme"` + ID string `db:"id" json:"programme_id" csv:"programme_id"` + Titre string `db:"titre" json:"nom_programme" csv:"nom_programme"` } type Membre struct { - ID string `db:"id" json:"membre_id"` - LastName string `db:"last_name" json:"last_name"` - FirstName string `db:"first_name" json:"first_name"` - PreferedName string `db:"prefered_name" json:"prefered_name"` - ProgrammeID string `db:"programme_id" json:"programme_id"` + ID string `db:"id" json:"membre_id" csv:"membre_id"` + LastName string `db:"last_name" json:"last_name" csv:"last_name"` + FirstName string `db:"first_name" json:"first_name" csv:"first_name"` + PreferedName string `db:"prefered_name" json:"prefered_name" csv:"prefered_name"` + ProgrammeID string `db:"programme_id" json:"programme_id" csv:"programme_id"` } type Entry interface {