Files
memberDB/api/membersHandler.go
2025-10-08 15:06:08 +02:00

298 lines
6.1 KiB
Go

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",
})
}