implement dbhandler package and new test file

This commit is contained in:
Adrian Zürcher
2025-10-31 08:11:07 +01:00
parent 1568ee2482
commit 80675ed328
17 changed files with 674 additions and 572 deletions

View File

@@ -1,10 +1,8 @@
package handlers
import (
"database/sql"
"errors"
"fmt"
"strings"
"time"
"gitea.tecamino.com/paadi/memberDB/crypto"
@@ -12,37 +10,12 @@ import (
"gitea.tecamino.com/paadi/memberDB/utils"
)
// CreateNewMemberTable creates a new member table.
func (dh *DatabaseHandler) CreateNewMemberTable() error {
createTableSQL := `
CREATE TABLE IF NOT EXISTS members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
first_name TEXT NOT NULL,
first_name_hash TEXT NOT NULL,
last_name TEXT NOT NULL,
last_name_hash TEXT NOT NULL,
birthday TEXT NOT NULL,
birthday_hash TEXT NOT NULL,
address TEXT NOT NULL,
zip_code TEXT NOT NULL,
town TEXT NOT NULL,
phone TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
first_visit TEXT NOT NULL,
last_visit TEXT NOT NULL,
member_group TEXT NOT NULL,
responsible_person TEXT NOT NULL
);`
_, err := dh.database.Exec(createTableSQL)
if err != nil {
return fmt.Errorf("failed to create table: %w", err)
}
return nil
}
// AddNewMember adds a new member to memeber table at least fist, las name and birthday has to be entered
func (dh *DatabaseHandler) AddNewMember(members ...models.Member) error {
if !dh.DatabaseOpened() {
return errors.New("database not opened")
}
for _, member := range members {
exists, err := dh.memberExists(member)
@@ -123,7 +96,23 @@ func (dh *DatabaseHandler) AddNewMember(members ...models.Member) error {
return err
}
_, err = dh.database.Exec("INSERT INTO members (first_name, first_name_hash, last_name, last_name_hash, birthday, birthday_hash, address, zip_code, town, phone, email, first_visit, last_visit, member_group, responsible_person) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", encFirstName, dh.hashField(member.FirstName), encLastName, dh.hashField(member.LastName), encBirthday, dh.hashField(member.Birthday), encAddress, encZip, encTown, encPhone, encEmail, encFirstVisit, encLastVisit, encGroup, encResponsiblePerson)
member.FirstNameHash = dh.hashField(member.FirstName)
member.FirstName = encFirstName
member.LastNameHash = dh.hashField(member.LastName)
member.LastName = encLastName
member.BirthdayHash = dh.hashField(member.Birthday)
member.Birthday = encBirthday
member.Address = encAddress
member.Zip = encZip
member.Town = encTown
member.Phone = encPhone
member.Email = encEmail
member.FirstVisit = encFirstVisit
member.LastVisit = encLastVisit
member.Group = encGroup
member.ResponsiblePerson = encResponsiblePerson
err = dh.database.AddNewColum(&member)
if err != nil {
return err
}
@@ -132,290 +121,203 @@ func (dh *DatabaseHandler) AddNewMember(members ...models.Member) error {
}
// DeleteMember removes members by given ids
func (dh *DatabaseHandler) DeleteMember(ids ...int) error {
func (dh *DatabaseHandler) DeleteMember(ids ...uint) error {
if !dh.DatabaseOpened() {
return errors.New("database not opened")
}
if len(ids) == 0 {
return errors.New("no ids given to be deleted")
}
placeholders := make([]string, len(ids))
args := make([]any, len(ids))
for i, id := range ids {
placeholders[i] = "?"
args[i] = id
}
query := fmt.Sprintf("DELETE FROM members WHERE id IN (%s)", strings.Join(placeholders, ","))
_, err := dh.database.Exec(query, args...)
return err
return dh.database.DeleteById(&models.Member{}, ids...)
}
// GetMember returns one member by given id
func (dh *DatabaseHandler) GetMember(id int) (members []models.Member, err error) {
var args any
query := `SELECT id, first_name, last_name, birthday, address, zip_code, town, phone, email, first_visit, last_visit, member_group, responsible_person FROM members`
if id > 0 {
query = ` WHERE id = ?`
args = id
func (dh *DatabaseHandler) GetMember(id uint) (members []models.Member, err error) {
if !dh.DatabaseOpened() {
return members, errors.New("database not opened")
}
rows, err := dh.database.Query(query, args)
err = dh.database.GetById(&members, id)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
var id int
var encFirstName, encLastName, encBirthday, encAddress, encZip, encTown, encPhone, encEmail, encFirstVisit, encLastVisit, encGroup, encResponsiblePerson string
if err = rows.Scan(&id, &encFirstName, &encLastName, &encBirthday, &encAddress, &encZip, &encTown, &encPhone, &encEmail, &encFirstVisit, &encLastVisit, &encGroup, &encResponsiblePerson); err != nil {
for i := range members {
members[i].FirstName, err = crypto.Decrypt(members[i].FirstName, dh.token)
if err != nil {
return
}
firstName, err := crypto.Decrypt(encFirstName, dh.token)
members[i].LastName, err = crypto.Decrypt(members[i].LastName, dh.token)
if err != nil {
return members, err
return
}
lastName, err := crypto.Decrypt(encLastName, dh.token)
members[i].Birthday, err = crypto.Decrypt(members[i].Birthday, dh.token)
if err != nil {
return members, err
return
}
birthday, err := crypto.Decrypt(encBirthday, dh.token)
members[i].Address, err = crypto.Decrypt(members[i].Address, dh.token)
if err != nil {
return members, err
return
}
address, err := crypto.Decrypt(encAddress, dh.token)
members[i].Zip, err = crypto.Decrypt(members[i].Zip, dh.token)
if err != nil {
return members, err
return
}
zip, err := crypto.Decrypt(encZip, dh.token)
members[i].Town, err = crypto.Decrypt(members[i].Town, dh.token)
if err != nil {
return members, err
return
}
town, err := crypto.Decrypt(encTown, dh.token)
members[i].Phone, err = crypto.Decrypt(members[i].Phone, dh.token)
if err != nil {
return members, err
return
}
phone, err := crypto.Decrypt(encPhone, dh.token)
members[i].Email, err = crypto.Decrypt(members[i].Email, dh.token)
if err != nil {
return members, err
return
}
email, err := crypto.Decrypt(encEmail, dh.token)
members[i].FirstVisit, err = crypto.Decrypt(members[i].FirstVisit, dh.token)
if err != nil {
return members, err
return
}
firstVisit, err := crypto.Decrypt(encFirstVisit, dh.token)
members[i].LastVisit, err = crypto.Decrypt(members[i].LastVisit, dh.token)
if err != nil {
return members, err
return
}
lastVisit, err := crypto.Decrypt(encLastVisit, dh.token)
members[i].Group, err = crypto.Decrypt(members[i].Group, dh.token)
if err != nil {
return members, err
return
}
group, err := crypto.Decrypt(encGroup, dh.token)
members[i].ResponsiblePerson, err = crypto.Decrypt(members[i].ResponsiblePerson, dh.token)
if err != nil {
return members, err
return
}
responsiblePerson, err := crypto.Decrypt(encResponsiblePerson, dh.token)
if err != nil {
return members, err
}
members = append(members, models.Member{
Id: id,
FirstName: firstName,
LastName: lastName,
Birthday: birthday,
Address: address,
Zip: zip,
Town: town,
Phone: phone,
Email: email,
FirstVisit: firstVisit,
LastVisit: lastVisit,
Group: group,
ResponsiblePerson: responsiblePerson,
})
}
return members, nil
return
}
// UpdateMember updates/overrides all information given meber id
func (dh *DatabaseHandler) UpdateMember(id int, member models.Member) (err error) {
var queryParameters []string
var args []any
if !dh.DatabaseOpened() {
return errors.New("database not opened")
}
if member.FirstName != "" {
encFirstName, err := crypto.Encrypt(member.FirstName, dh.token)
member.FirstNameHash = dh.hashField(member.FirstName)
member.FirstName, err = crypto.Encrypt(member.FirstName, dh.token)
if err != nil {
return err
return
}
queryParameters = append(queryParameters, "first_name = ?")
queryParameters = append(queryParameters, "first_name_hash = ?")
args = append(args, encFirstName)
args = append(args, dh.hashField(member.FirstName))
}
if member.LastName != "" {
encLastName, err := crypto.Encrypt(member.LastName, dh.token)
member.LastNameHash = dh.hashField(member.LastName)
member.LastName, err = crypto.Encrypt(member.LastName, dh.token)
if err != nil {
return err
return
}
queryParameters = append(queryParameters, "last_name = ?")
queryParameters = append(queryParameters, "last_name_hash = ?")
args = append(args, encLastName)
args = append(args, dh.hashField(member.LastName))
}
//check correct birtday format
if member.Birthday != "" && utils.IsValidBirthday(member.Birthday) {
encBirthday, err := crypto.Encrypt(member.Birthday, dh.token)
member.BirthdayHash = dh.hashField(member.BirthdayHash)
member.Birthday, err = crypto.Encrypt(member.Birthday, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "birthday = ?")
queryParameters = append(queryParameters, "birthday_hash = ?")
args = append(args, encBirthday)
args = append(args, dh.hashField(member.Birthday))
} else if member.Birthday != "" {
return errors.New("incorrect birthday format")
}
if member.Address != "" {
encAddress, err := crypto.Encrypt(member.Address, dh.token)
member.Address, err = crypto.Encrypt(member.Address, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "address = ?")
args = append(args, encAddress)
}
if member.Zip != "" {
encZip, err := crypto.Encrypt(member.Zip, dh.token)
member.Zip, err = crypto.Encrypt(member.Zip, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "zip_code = ?")
args = append(args, encZip)
}
if member.Town != "" {
encTown, err := crypto.Encrypt(member.Town, dh.token)
member.Town, err = crypto.Encrypt(member.Town, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "town = ?")
args = append(args, encTown)
}
if member.Phone != "" {
encPhone, err := crypto.Encrypt(member.Phone, dh.token)
member.Phone, err = crypto.Encrypt(member.Phone, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "phone = ?")
args = append(args, encPhone)
}
//check correct email format
if member.Email != "" && utils.IsValidEmail(member.Email) {
encEmail, err := crypto.Encrypt(member.Email, dh.token)
member.Email, err = crypto.Encrypt(member.Email, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "email = ?")
args = append(args, encEmail)
} else if member.Email != "" {
return errors.New("incorrect email format")
}
if member.FirstVisit != "" {
encFirstVisit, err := crypto.Encrypt(member.FirstVisit, dh.token)
member.FirstVisit, err = crypto.Encrypt(member.FirstVisit, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "first_visit = ?")
args = append(args, encFirstVisit)
}
if member.LastVisit != "" {
encLastVisit, err := crypto.Encrypt(member.LastVisit, dh.token)
member.LastVisit, err = crypto.Encrypt(member.LastVisit, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "last_visit = ?")
args = append(args, encLastVisit)
}
if member.Group != "" {
encFirstVisit, err := crypto.Encrypt(member.Group, dh.token)
member.Group, err = crypto.Encrypt(member.Group, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "member_group = ?")
args = append(args, encFirstVisit)
}
if member.ResponsiblePerson != "" {
encResponsiblePerson, err := crypto.Encrypt(member.ResponsiblePerson, dh.token)
member.ResponsiblePerson, err = crypto.Encrypt(member.ResponsiblePerson, dh.token)
if err != nil {
return err
}
queryParameters = append(queryParameters, "responsible_person = ?")
args = append(args, encResponsiblePerson)
}
query := `UPDATE members SET `
query += strings.Join(queryParameters, ", ")
query += ` WHERE id = ?`
args = append(args, id)
_, err = dh.database.Exec(query, args...)
return err
return dh.database.UpdateValuesById(&member, uint(member.Id))
}
// memberExists helper to check wheter member already exists
func (dh *DatabaseHandler) memberExists(member models.Member) (bool, error) {
query := `
SELECT 1 FROM members
WHERE first_name_hash = ? AND last_name_hash = ? AND birthday_hash = ?
LIMIT 1
`
var exists int
err := dh.database.QueryRow(query, dh.hashField(member.FirstName), dh.hashField(member.LastName), dh.hashField(member.Birthday)).Scan(&exists)
if err == sql.ErrNoRows {
return false, nil // no match
} else if err != nil {
return false, err // db error
func (dh *DatabaseHandler) memberExists(checkMember models.Member) (bool, error) {
if !dh.DatabaseOpened() {
return false, errors.New("database not opened")
}
return true, nil // match found
var member models.Member
err := dh.database.Exists(&member, "birthdayHash", dh.hashField(checkMember.Birthday), false)
if err != nil {
return false, nil
}
return dh.hashField(checkMember.FirstName) == member.FirstNameHash && dh.hashField(checkMember.LastName) == member.LastNameHash && dh.hashField(checkMember.Birthday) == member.BirthdayHash, nil
}