package api import ( "encoding/csv" "fmt" "io" "net/http" "strconv" "gitea.tecamino.com/paadi/memberDB/models" "github.com/gin-gonic/gin" "github.com/saintfish/chardet" "golang.org/x/text/encoding/charmap" "golang.org/x/text/transform" ) func (a *APIHandler) AddNewMember(c *gin.Context) { if !a.databaseOpened(c) { return } var member models.Member c.BindJSON(&member) var text string if member.FirstName == "" { text = "firstName " } if member.LastName == "" { text += "lastName " } if member.Birthday == "" { text += "birthday " } if text != "" { c.JSON(http.StatusBadRequest, gin.H{ "message": text + "can not be empty", }) return } err := a.DbHandler.AddNewMember(member) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": "member added", }) } func (a *APIHandler) GetMemberById(c *gin.Context) { if !a.databaseOpened(c) { return } var i int var err error id := c.Query("id") if id != "" { i, err = strconv.Atoi(id) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } } members, err := a.DbHandler.GetMember(i) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } c.JSON(http.StatusOK, members) } func (a *APIHandler) EditMember(c *gin.Context) { if !a.databaseOpened(c) { return } var i int var err error id := c.Query("id") if id != "" { i, err = strconv.Atoi(id) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } } else { c.JSON(http.StatusBadRequest, gin.H{ "message": "query parameter 'id' missing", }) return } var member models.Member c.BindJSON(&member) err = a.DbHandler.UpdateMember(i, member) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": "member updated", }) } func (a *APIHandler) DeleteMember(c *gin.Context) { if !a.databaseOpened(c) { return } var err error var request struct { Ids []int `json:"ids"` } err = c.BindJSON(&request) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } err = a.DbHandler.DeleteMember(request.Ids...) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } c.JSON(http.StatusOK, gin.H{ "message": "member deleted", }) } func (a *APIHandler) ImportCSV(c *gin.Context) { if !a.databaseOpened(c) { return } var err error fileHeader, err := c.FormFile("file") if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } rowIndex := c.PostForm("rowIndex") comma := c.PostForm("seperator") firstName := c.PostForm("firstName") lastName := c.PostForm("lastName") birthday := c.PostForm("birthday") address := c.PostForm("address") town := c.PostForm("town") zip := c.PostForm("zip") phone := c.PostForm("phone") email := c.PostForm("email") rowIndexI, err := strconv.Atoi(rowIndex) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "message": err.Error(), }) return } file, err := fileHeader.Open() if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to open uploaded file"}) return } defer file.Close() // Read first N bytes to detect encoding const sniffSize = 1024 * 10 // 10KB for detection buf := make([]byte, sniffSize) n, err := file.Read(buf) if err != nil && err != io.EOF { c.JSON(http.StatusInternalServerError, gin.H{"message": err.Error()}) return } // Detect encoding detector := chardet.NewTextDetector() result, err := detector.DetectBest(buf[:n]) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to detect encoding"}) return } _, err = file.Seek(0, io.SeekStart) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"message": "Failed to rewind file"}) return } // Wrap reader based on encoding var reader io.Reader switch result.Charset { case "UTF-8": reader = file case "windows-1252": reader = transform.NewReader(file, charmap.Windows1252.NewDecoder()) case "ISO-8859-1": reader = transform.NewReader(file, charmap.ISO8859_1.NewDecoder()) default: c.JSON(http.StatusBadRequest, gin.H{"message": "Unsupported encoding: " + result.Charset}) return } csvReader := csv.NewReader(reader) csvReader.Comma = rune(comma[0]) records, err := csvReader.ReadAll() if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Failed to parse CSV"}) return } var firstNameIndex, lastNameIndex, birthdayIndex, addressIndex, townIndex, zipIndex, phoneIndex, emailIndex int var message string for i, row := range records { if i < rowIndexI { continue } else if i == rowIndexI { for c, column := range row { switch column { case firstName: firstNameIndex = c case lastName: lastNameIndex = c case birthday: birthdayIndex = c case address: addressIndex = c case town: townIndex = c case zip: zipIndex = c case phone: phoneIndex = c case email: emailIndex = c } } continue } if row[firstNameIndex] == "" && row[lastNameIndex] == "" { continue } err := a.DbHandler.AddNewMember(models.Member{ FirstName: row[firstNameIndex], LastName: row[lastNameIndex], Birthday: row[birthdayIndex], Address: row[addressIndex], Town: row[townIndex], Zip: row[zipIndex], Phone: row[phoneIndex], Email: row[emailIndex], }) if err != nil { message += "Row: " + fmt.Sprint(i) + " " + row[firstNameIndex] + " " + row[lastNameIndex] + " error: " + err.Error() + "\n" } } if message != "" { c.JSON(http.StatusBadRequest, gin.H{ "message": message, }) return } c.JSON(http.StatusOK, gin.H{ "message": "CSV imported", }) }