Adding initial code for adding a new poll on the backend

This commit is contained in:
2025-11-04 16:39:10 -05:00
parent 3e2efae4ce
commit 5e8b4e2b61
8 changed files with 147 additions and 51 deletions

2
go.mod
View File

@@ -1,4 +1,4 @@
module go-sjles-pta-vote/server
module go-sjles-pta-vote
go 1.24.4

View File

@@ -14,6 +14,7 @@ type Config struct {
}
var conf *Config
var conf_path string = ".env"
func GetConfig() *Config {
if conf != nil {
@@ -23,7 +24,7 @@ func GetConfig() *Config {
conf = &Config{}
// TODO: Make this into a ini or toml file
confgContent, err := os.ReadFile(".env")
configContent, err := os.ReadFile(conf_path)
if err != nil {
fmt.Println("Error reading .env file: ", err)
@@ -37,10 +38,15 @@ func GetConfig() *Config {
for _, variable := range envVariables {
if strings.Contains(variable, "=") {
splitVariable := strings.Split(variable, "=")
envMap[splitVariable[0]] = splitVAriable[1]
envMap[splitVariable[0]] = splitVariable[1]
}
}
if err := json.Unmarshal([]byte(configContent), conf); err != nil {
fmt.Println("Error unmarshalling config file: ", err)
os.Exit(1)
}
// TODO: Better mapping of key to json values
// TODO: Better error checking if values are missing
// TODO: Default values
@@ -59,6 +65,6 @@ func GetConfig() *Config {
return conf
}
func init() {
conf = GetConfig()
func SetConfig(init_conf *Config) {
conf = init_conf
}

View File

@@ -2,30 +2,53 @@ package db
import (
"database/sql"
"os"
"go-sjles-pta-vote/server/config"
_ "github.com/glebarez/go-sqlite"
)
var build_db_query string = `
CREATE TABLE IF NOT EXISTS polls (
id INTEGER PRIMARY KEY,
question TEXT NOT NULL,
member_yes_votes UNSIGNED INT NOT NULL DEFAULT 0,
member_no_votes UNSIGNED INT NOT NULL DEFAULT 0,
non_member_yes_votes UNSIGNED INT NOT NULL DEFAULT 0,
non_member_no_votes UNSIGNED INT NOT NULL DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
expires_at DATETIME
);
CREATE TABLE IF NOT EXISTS voters (
poll_id UNSIGNED INT NOT NULL,
voter_email TEXT NOT NULL,
FOREIGN KEY (poll_id) REFERENCES polls(id),
PRIMARY KEY (poll_id, voter_email)
);
CREATE TABLE IF NOT EXISTS members (
email TEXT NOT NULL,
member_name TEXT,
PRIMARY KEY (email)
);
`
var db *sql.DB
func Connect(db_path string) error {
var err error
db, err = sql.Open("sqlite", db_path)
func Connect() (*sql.DB, error) {
db_config := config.GetConfig()
db, err := sql.Open("sqlite", db_config.DBPath)
if err != nil {
return err
return nil, err
}
sql_create, err := os.ReadFile("./db_format.sql")
_, err = db.Exec(build_db_query)
if err != nil {
return err
}
_, err = db.Exec(string(sql_create))
return err
return db, err
}
func Close() {

View File

@@ -1,24 +0,0 @@
CREATE TABLE IF NOT EXISTS polls (
id INTEGER PRIMARY KEY,
question TEXT NOT NULL,
member_yes_votes UNSIGNED INT NOT NULL,
member_no_votes UNSIGNED INT NOT NULL,
non_member_yes_votes UNSIGNED INT NOT NULL,
non_member_no_votes UNSIGNED INT NOT NULL,
created_at DATETIME,
updated_at DATETIME,
expires_at DATETIME
);
CREATE TABLE IF NOT EXISTS voters (
poll_id UNSIGNED INT NOT NULL,
voter_email TEXT NOT NULL,
FOREIGN KEY (poll_id) REFERENCES polls(id),
PRIMARY KEY (poll_id, voter_email)
);
CREATE TABLE IF NOT EXISTS members (
email TEXT NOT NULL,
member_name TEXT,
PRIMARY KEY (email)
);

View File

@@ -3,21 +3,26 @@ package db
import (
"os"
"testing"
"go-sjles-pta-vote/server/config"
)
func TestConnect(t *testing.T) {
tmp_db, err := os.CreateTemp("", "vote_test.*.db")
tmp_db_name := tmp_db.Name()
tmp_db.Close()
defer os.Remove(tmp_db_name)
if err != nil {
t.Errorf(`Failed to create temporary db: %v`, err)
t.Errorf(`Failed to create temporary db file: %v`, err)
}
if err := Connect(tmp_db_name); err != nil {
t.Errorf(`Failed to create the database at %s: %v`, tmp_db_name, err)
init_conf := &config.Config{
DBPath: string(tmp_db.Name()),
}
config.SetConfig(init_conf)
defer os.Remove(tmp_db.Name())
tmp_db.Close()
if _, err := Connect(); err != nil {
t.Errorf(`Failed to create the database: %v`, err)
}
defer Close()

View File

@@ -1,7 +1,7 @@
package models
type Poll struct {
ID int `json:"id"`
ID int64 `json:"id"`
Question string `json:"question"`
TotalVotes int `json:"total_votes"`
WhoVoted []string `json:"who_voted"`

41
server/services/poll.go Normal file
View File

@@ -0,0 +1,41 @@
package services
import (
"go-sjles-pta-vote/server/db"
"go-sjles-pta-vote/server/models"
)
func CreatePoll(poll *models.Poll) (*models.Poll, error) {
new_poll := models.Poll{}
db_conn, err := db.Connect()
if err != nil {
return nil, err
}
defer db.Close()
stmt, err := db_conn.Prepare(`
INSERT INTO polls (
question,
expires_at
) VALUES (
$1,
$2
) RETURNING ID;
`)
if err != nil {
return nil, err
}
defer stmt.Close()
res, err := stmt.Exec(poll.Question, poll.ExpiresAt)
if err != nil {
return nil, err
}
new_poll.ID, err = res.LastInsertId()
return &new_poll, err
}

View File

@@ -0,0 +1,45 @@
package services
import (
"os"
"testing"
"time"
"go-sjles-pta-vote/server/config"
"go-sjles-pta-vote/server/db"
"go-sjles-pta-vote/server/models"
)
func TestCreatePoll(t *testing.T) {
tmp_db, err := os.CreateTemp("", "vote_test.*.db")
if err != nil {
t.Errorf(`Failed to create temporary db file: %v`, err)
}
init_conf := &config.Config{
DBPath: string(tmp_db.Name()),
}
config.SetConfig(init_conf)
defer os.Remove(tmp_db.Name())
tmp_db.Close()
if _, err := db.Connect(); err != nil {
t.Errorf(`Failed to create the database: %v`, err)
}
create_poll := &models.Poll{
Question: "TestQuestion",
ExpiresAt: time.Now().Add(time.Hour * 10).Format("2006-01-02 15:04:05"),
}
new_poll, err := CreatePoll(create_poll)
if err != nil {
t.Errorf(`Failed to insert into table: %v`, err)
}
if new_poll.ID != 1 {
t.Errorf(`Failed to insert into table: Index %d: error %v`, new_poll.ID, err)
}
}