removed 'internal' directory
This commit is contained in:
parent
8c200a5a6c
commit
65709049d7
42 changed files with 35 additions and 44 deletions
105
store/cake.go
Normal file
105
store/cake.go
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/Bronku/iroon/models"
|
||||
)
|
||||
|
||||
func (s *Store) cakeCount() int {
|
||||
out := 0
|
||||
rows, err := s.db.Query("select count(*) from cake;")
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
defer rows.Close()
|
||||
_ = rows.Next()
|
||||
_ = rows.Scan(&out)
|
||||
return out
|
||||
}
|
||||
|
||||
func (s *Store) loadCakes() ([]models.Cake, error) {
|
||||
out := make([]models.Cake, 0, s.cakeCount())
|
||||
|
||||
rows, err := s.db.Query("select id, name, price, category, availability from cake order by id;")
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
var cake models.Cake
|
||||
err = rows.Scan(&cake.ID, &cake.Name, &cake.Price, &cake.Category, &cake.Availability)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out = append(out, cake)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) searchCakes(id int) (int, error) {
|
||||
for i, e := range s.cakes {
|
||||
if e.ID != id {
|
||||
continue
|
||||
}
|
||||
return i, nil
|
||||
}
|
||||
return 0, errors.New("cake not found")
|
||||
}
|
||||
|
||||
func (s *Store) GetCake(id int) (models.Cake, error) {
|
||||
if id <= 0 {
|
||||
return models.Cake{}, errors.New("invalid cake id")
|
||||
}
|
||||
|
||||
i, err := s.searchCakes(id)
|
||||
if err != nil {
|
||||
return models.Cake{}, err
|
||||
}
|
||||
return s.cakes[i], err
|
||||
}
|
||||
|
||||
func (s *Store) GetCakes() ([]models.Cake, error) {
|
||||
result := make([]models.Cake, len(s.cakes))
|
||||
copy(result, s.cakes)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) updateCake(newCake models.Cake) error {
|
||||
query := "update cake set name = ? , price = ?, category = ?, availability = ? where id = ?"
|
||||
_, err := s.db.Exec(query, newCake.Name, newCake.Price, newCake.Category, newCake.Availability, newCake.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i, err := s.searchCakes(newCake.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.cakes[i] = newCake
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) SaveCake(newCake models.Cake) (int, error) {
|
||||
if newCake.ID != 0 {
|
||||
return newCake.ID, s.updateCake(newCake)
|
||||
}
|
||||
fmt.Println("adding a new cake", newCake)
|
||||
query := "insert into cake(name, price, category, availability) values (?, ?, ?, ?);"
|
||||
result, err := s.db.Exec(query, newCake.Name, newCake.Price, newCake.Category, newCake.Availability)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
newCake.ID = int(id)
|
||||
|
||||
s.cakes = append(s.cakes, newCake)
|
||||
return newCake.ID, nil
|
||||
}
|
||||
49
store/migrations.go
Normal file
49
store/migrations.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"embed"
|
||||
_ "embed"
|
||||
"log"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//go:embed migrations/*.sql
|
||||
var migrations embed.FS
|
||||
|
||||
func (s *Store) loadFile(file string) {
|
||||
filename := strings.Split(file, ".")
|
||||
version, err := strconv.Atoi(filename[0])
|
||||
if err != nil {
|
||||
log.Fatal("only allowed files in migrations directory are <version>.txt")
|
||||
}
|
||||
if version <= s.version() {
|
||||
return
|
||||
}
|
||||
|
||||
query, _ := migrations.ReadFile("migrations/" + file)
|
||||
_, err = s.db.Exec(string(query))
|
||||
if err != nil {
|
||||
log.Fatal("error executing migration: ", file, err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) loadMigrations() {
|
||||
migrationFiles, _ := migrations.ReadDir("migrations")
|
||||
|
||||
for _, e := range migrationFiles {
|
||||
s.loadFile(e.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) version() int {
|
||||
out := -1
|
||||
row, err := s.db.Query("PRAGMA user_version;")
|
||||
if err != nil {
|
||||
return out
|
||||
}
|
||||
defer row.Close()
|
||||
row.Next()
|
||||
_ = row.Scan(&out)
|
||||
return out
|
||||
}
|
||||
107
store/migrations/1.sql
Normal file
107
store/migrations/1.sql
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
create table cake (
|
||||
id integer primary key autoincrement,
|
||||
name text not null unique,
|
||||
price integer not null,
|
||||
category text,
|
||||
availability text
|
||||
);
|
||||
|
||||
create table customer_order (
|
||||
id integer primary key autoincrement,
|
||||
name text,
|
||||
surname text,
|
||||
phone text,
|
||||
location text,
|
||||
order_date string not null,
|
||||
delivery_date string not null,
|
||||
status text,
|
||||
paid integer
|
||||
);
|
||||
|
||||
create table ordered_cake (
|
||||
customer_order integer references customer_order (id) not null,
|
||||
cake integer references cake (id) not null,
|
||||
amount integer not null,
|
||||
primary key (customer_order, cake)
|
||||
);
|
||||
|
||||
create table user (
|
||||
login text primary key,
|
||||
password text,
|
||||
role text,
|
||||
salt text
|
||||
);
|
||||
|
||||
create table session (
|
||||
token text primary key,
|
||||
user text,
|
||||
expiration text
|
||||
);
|
||||
|
||||
create virtual table order_fts using fts5 (
|
||||
id,
|
||||
name,
|
||||
surname,
|
||||
phone,
|
||||
location,
|
||||
order_date,
|
||||
delivery_date,
|
||||
status,
|
||||
paid,
|
||||
content = 'customer_order'
|
||||
);
|
||||
|
||||
create trigger order_fts_insert after insert on customer_order begin
|
||||
insert into
|
||||
order_fts (
|
||||
id,
|
||||
name,
|
||||
surname,
|
||||
phone,
|
||||
location,
|
||||
order_date,
|
||||
delivery_date,
|
||||
status,
|
||||
paid
|
||||
)
|
||||
values
|
||||
(
|
||||
new.id,
|
||||
new.name,
|
||||
new.surname,
|
||||
new.phone,
|
||||
new.location,
|
||||
new.order_date,
|
||||
new.delivery_date,
|
||||
new.status,
|
||||
new.paid
|
||||
);
|
||||
|
||||
end;
|
||||
|
||||
create trigger order_fts_delete after delete on customer_order begin
|
||||
delete from order_fts
|
||||
where
|
||||
id = old.id;
|
||||
|
||||
end;
|
||||
|
||||
create trigger order_fts_update after
|
||||
update on customer_order begin
|
||||
update customer_order
|
||||
set
|
||||
id = new.id,
|
||||
name = new.name,
|
||||
surname = new.surname,
|
||||
phone = new.phone,
|
||||
location = new.location,
|
||||
order_date = new.order_date,
|
||||
delivery_date = new.delivery_date,
|
||||
status = new.status,
|
||||
paid = new.paid
|
||||
where
|
||||
id = old.id;
|
||||
|
||||
end;
|
||||
|
||||
pragma user_version = 1;
|
||||
176
store/order.go
Normal file
176
store/order.go
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/Bronku/iroon/models"
|
||||
)
|
||||
|
||||
// #todo update labels in templates
|
||||
|
||||
func (s *Store) parseOrderRow(row *sql.Rows) (models.Order, error) {
|
||||
var out models.Order
|
||||
var orderDate, deliveryDate string
|
||||
err := row.Scan(&out.ID, &out.Name, &out.Surname, &out.Phone, &out.Location, &orderDate, &deliveryDate, &out.Status, &out.Paid)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.Accepted, _ = time.Parse("2006-01-02 15:04", orderDate)
|
||||
out.Date, _ = time.Parse("2006-01-02 15:04", deliveryDate)
|
||||
|
||||
out.Cakes = make([]models.Cake, 0)
|
||||
rows, err := s.db.Query("select cake, amount from ordered_cake where customer_order = ?;", out.ID)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var newCake models.Cake
|
||||
err = rows.Scan(&newCake.ID, &newCake.Amount)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
cakeData, err := s.GetCake(newCake.ID)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
newCake.Name = cakeData.Name
|
||||
newCake.Price = cakeData.Price
|
||||
out.Cakes = append(out.Cakes, newCake)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) getOrdersFromQuery(query string, args ...any) ([]models.Order, error) {
|
||||
var out []models.Order
|
||||
rows, err := s.db.Query(query, args...)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
for rows.Next() {
|
||||
order, err := s.parseOrderRow(rows)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
continue
|
||||
}
|
||||
out = append(out, order)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetOrder(id int) (models.Order, error) {
|
||||
query := "select * from customer_order where id = ?;"
|
||||
out, err := s.getOrdersFromQuery(query, id)
|
||||
if err != nil {
|
||||
return models.Order{}, err
|
||||
}
|
||||
if len(out) < 1 {
|
||||
return models.Order{}, errors.New("no output order")
|
||||
}
|
||||
return out[0], nil
|
||||
}
|
||||
|
||||
func (s *Store) GetFilteredOrder(filter string, from, to time.Time) ([]models.Order, error) {
|
||||
start := from.Format("2006-01-02") + " 00:00"
|
||||
end := to.Format("2006-01-02") + " 99:99"
|
||||
if to.IsZero() {
|
||||
end = "9999-99-99 99:99"
|
||||
}
|
||||
if filter == "" {
|
||||
query := "select * from customer_order where status != 'done' and delivery_date >= ? and delivery_date <= ? ;"
|
||||
return s.getOrdersFromQuery(query, start, end)
|
||||
}
|
||||
query := "select id, name, surname, phone, location, order_date, delivery_date, status, paid from order_fts(?) where delivery_date >= ? and delivery_date <= ? order by rank;"
|
||||
return s.getOrdersFromQuery(query, filter, start, end)
|
||||
}
|
||||
|
||||
func (s *Store) UpdateOrderContents(tx *sql.Tx, newOrder models.Order) error {
|
||||
query := "delete from ordered_cake where customer_order = ?;"
|
||||
_, err := tx.Exec(query, newOrder.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = "insert into ordered_cake(customer_order, cake, amount) values (?,?,?);"
|
||||
for _, e := range newOrder.Cakes {
|
||||
_, err := tx.Exec(query, newOrder.ID, e.ID, e.Amount)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) UpdateOrder(newOrder models.Order) error {
|
||||
_, err := s.GetOrder(newOrder.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query := "update customer_order set name = ?, surname = ?, phone = ?, location = ?, order_date = ?, delivery_date = ?, status = ?, paid = ? where id = ?;"
|
||||
|
||||
accepted := newOrder.Accepted.Format("2006-01-02 15:04")
|
||||
date := newOrder.Date.Format("2006-01-02 15:04")
|
||||
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(query, newOrder.Name, newOrder.Surname, newOrder.Phone, newOrder.Location, accepted, date, newOrder.Status, newOrder.Paid, newOrder.ID)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = s.UpdateOrderContents(tx, newOrder)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) SaveOrder(newOrder models.Order) (int, error) {
|
||||
if newOrder.ID != 0 {
|
||||
return newOrder.ID, s.UpdateOrder(newOrder)
|
||||
}
|
||||
query := "insert into customer_order(name, surname, phone, location, order_date, delivery_date, status, paid) values (?, ?, ?, ?, ?, ?, ?, ?);"
|
||||
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
accepted := newOrder.Accepted.Format("2006-01-02 15:04")
|
||||
date := newOrder.Date.Format("2006-01-02 15:04")
|
||||
result, err := tx.Exec(query, newOrder.Name, newOrder.Surname, newOrder.Phone, newOrder.Location, accepted, date, newOrder.Status, newOrder.Paid)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return 0, err
|
||||
}
|
||||
|
||||
id, err := result.LastInsertId()
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return newOrder.ID, err
|
||||
}
|
||||
newOrder.ID = int(id)
|
||||
|
||||
err = s.UpdateOrderContents(tx, newOrder)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return newOrder.ID, err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
return newOrder.ID, err
|
||||
}
|
||||
58
store/session.go
Normal file
58
store/session.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/Bronku/iroon/models"
|
||||
)
|
||||
|
||||
func (s *Store) AddSession(token, userName string, expiration time.Time) error {
|
||||
query := "insert into session (token, user, expiration) values(?, ?, ?)"
|
||||
_, err := s.db.Exec(query, token, userName, expiration.Format("2006-01-02 15:04"))
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) RevokeSession(token string) error {
|
||||
query := "delete from session where token = ?;"
|
||||
_, err := s.db.Exec(query, token)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) CleanSessions() error {
|
||||
now := time.Now().Format("2006-01-02 15:04")
|
||||
query := "delete from session where expiration < ?;"
|
||||
_, err := s.db.Exec(query, now)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) GetSessions() (map[string]models.Token, error) {
|
||||
out := make(map[string]models.Token)
|
||||
err := s.CleanSessions()
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
query := "select token, user, expiration from session;"
|
||||
rows, err := s.db.Query(query)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var current models.Token
|
||||
var token string
|
||||
var expiration string
|
||||
err = rows.Scan(&token, ¤t.User, &expiration)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
current.Expiration, err = time.Parse("2006-01-02 15:04", expiration)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if token == "" {
|
||||
continue
|
||||
}
|
||||
out[token] = current
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
43
store/store.go
Normal file
43
store/store.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/Bronku/iroon/models"
|
||||
_ "github.com/knaka/go-sqlite3-fts5"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type Store struct {
|
||||
db *sql.DB
|
||||
cakes []models.Cake
|
||||
users map[string]models.User
|
||||
}
|
||||
|
||||
func OpenStore(filename string) *Store {
|
||||
var out Store
|
||||
var err error
|
||||
|
||||
out.db, err = sql.Open("sqlite3", filename)
|
||||
if err != nil {
|
||||
log.Fatal("Can't open the database", filename, err)
|
||||
}
|
||||
|
||||
out.loadMigrations()
|
||||
out.cakes, err = out.loadCakes()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
out.users, err = out.loadUsers()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return &out
|
||||
}
|
||||
|
||||
func (s *Store) Close() {
|
||||
if s.db != nil {
|
||||
s.db.Close()
|
||||
}
|
||||
}
|
||||
293
store/store_test.go
Normal file
293
store/store_test.go
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Bronku/iroon/internal/models"
|
||||
)
|
||||
|
||||
func TestStore(t *testing.T) {
|
||||
s := OpenStore("file:memdb1?mode=memory&cache=shared")
|
||||
defer s.Close()
|
||||
|
||||
// ensure db is empty
|
||||
cakes, err := s.GetCakes()
|
||||
if err != nil {
|
||||
t.Errorf("Error getting cakes: %v", err)
|
||||
}
|
||||
if len(cakes) != 0 {
|
||||
t.Errorf("Expected empty cakes list, got: %v", cakes)
|
||||
}
|
||||
orders, err := s.GetFilteredOrder("", time.Now(), time.Now().Add(time.Hour*24))
|
||||
if err != nil {
|
||||
t.Errorf("Error getting orders: %v", err)
|
||||
}
|
||||
if len(orders) != 0 {
|
||||
t.Errorf("Expected empty orders list, got: %v", orders)
|
||||
}
|
||||
|
||||
// create new cake
|
||||
newCake := models.Cake{Name: "Chocolate Cake", Price: 2500}
|
||||
newCake.ID, err = s.SaveCake(newCake)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to save new cake: %v", err)
|
||||
}
|
||||
if newCake.ID <= 0 {
|
||||
t.Errorf("Expected positive cake ID, got: %d", newCake.ID)
|
||||
}
|
||||
|
||||
// create another cake
|
||||
anotherCake := models.Cake{Name: "Another Cake", Price: 3000}
|
||||
anotherCake.ID, err = s.SaveCake(anotherCake)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to save new cake: %v", err)
|
||||
}
|
||||
if anotherCake.ID <= 0 {
|
||||
t.Errorf("Expected positive cake ID, got: %d", anotherCake.ID)
|
||||
}
|
||||
|
||||
// Update Existing Cake
|
||||
newCake.Name = "Updated Cake"
|
||||
newCake.Price = 100
|
||||
newID, err := s.SaveCake(newCake)
|
||||
if newID != newCake.ID {
|
||||
t.Error("wrong id")
|
||||
}
|
||||
if err != nil {
|
||||
t.Error("error updating cake", err)
|
||||
}
|
||||
|
||||
// Update Non-existing Cake
|
||||
var updatedCake models.Cake
|
||||
updatedCake.ID = 10
|
||||
_, err = s.SaveCake(updatedCake)
|
||||
if err == nil {
|
||||
t.Error("did not return an error when attempted to update non existent cake")
|
||||
}
|
||||
|
||||
// get cakes
|
||||
cakes, err = s.GetCakes()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get all cakes after creation: %v", err)
|
||||
}
|
||||
if len(cakes) != 2 {
|
||||
t.Error("Expected two cakes returned, got ", len(cakes))
|
||||
}
|
||||
for i, c := range cakes {
|
||||
if c.ID == newCake.ID {
|
||||
newCake.Amount = i
|
||||
}
|
||||
if c.ID == anotherCake.ID {
|
||||
anotherCake.Amount = i
|
||||
}
|
||||
}
|
||||
if newCake.Amount == -1 {
|
||||
t.Error("not found newCake")
|
||||
}
|
||||
if cakes[newCake.Amount].ID != newCake.ID || cakes[newCake.Amount].Name != newCake.Name || cakes[newCake.Amount].Price != newCake.Price {
|
||||
t.Errorf("Want %v\nGot %v", newCake, cakes[newCake.Amount])
|
||||
}
|
||||
if anotherCake.Amount == -1 {
|
||||
t.Error("not found anotherCake")
|
||||
}
|
||||
if cakes[anotherCake.Amount].ID != anotherCake.ID || cakes[anotherCake.Amount].Name != anotherCake.Name || cakes[anotherCake.Amount].Price != anotherCake.Price {
|
||||
t.Errorf("Want %v\nGot %v", anotherCake, cakes)
|
||||
}
|
||||
|
||||
selectedCake, err := s.GetCake(newCake.ID)
|
||||
if err != nil {
|
||||
t.Error("error getting a cake", err)
|
||||
}
|
||||
if selectedCake.ID != newCake.ID || selectedCake.Name != newCake.Name || selectedCake.Price != newCake.Price {
|
||||
t.Errorf("Want %v\nGot %v", newCake, selectedCake)
|
||||
}
|
||||
|
||||
selectedCake, err = s.GetCake(-1)
|
||||
if err == nil {
|
||||
t.Error("no error getting a non-existent cake")
|
||||
}
|
||||
|
||||
// create new order
|
||||
now := time.Now()
|
||||
newOrder := models.Order{
|
||||
Name: "John",
|
||||
Surname: "Doe",
|
||||
Phone: "123-456-7890",
|
||||
Location: "Some Location",
|
||||
Accepted: now,
|
||||
Date: now.Add(time.Hour * 24),
|
||||
Status: "Pending",
|
||||
Paid: 1000,
|
||||
Cakes: []models.Cake{{ID: newCake.ID, Amount: 2}, {ID: anotherCake.ID, Amount: 10}},
|
||||
}
|
||||
newOrder.ID, err = s.SaveOrder(newOrder)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to save new order: %v", err)
|
||||
}
|
||||
if newOrder.ID <= 0 {
|
||||
t.Errorf("Expected positive order ID, got: %d", newOrder.ID)
|
||||
}
|
||||
|
||||
// create another order
|
||||
anotherOrder := models.Order{
|
||||
Name: "Jane",
|
||||
Surname: "Doe",
|
||||
Phone: "123-456-7890",
|
||||
Location: "New Location",
|
||||
Accepted: now,
|
||||
Date: now.Add(time.Hour * 192),
|
||||
Status: "Accepted",
|
||||
Paid: 1500,
|
||||
Cakes: []models.Cake{{ID: newCake.ID, Amount: 100}},
|
||||
}
|
||||
anotherOrder.ID, err = s.SaveOrder(anotherOrder)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to save new order: %v", err)
|
||||
}
|
||||
if anotherOrder.ID <= 0 {
|
||||
t.Errorf("Expected positive order ID, got: %d", anotherOrder.ID)
|
||||
}
|
||||
|
||||
// update existing order
|
||||
newOrder.Name = "James"
|
||||
newOrder.Status = "Done"
|
||||
newOrder.Cakes = newOrder.Cakes[1:]
|
||||
newID, err = s.SaveOrder(newOrder)
|
||||
if newID != newOrder.ID {
|
||||
t.Error("wrong id")
|
||||
}
|
||||
if err != nil {
|
||||
t.Error("error updating order", err)
|
||||
}
|
||||
|
||||
// update non existing order
|
||||
var updatedOrder models.Order
|
||||
updatedOrder.ID = 10
|
||||
_, err = s.SaveOrder(updatedOrder)
|
||||
if err == nil {
|
||||
t.Error("did not return an error when attempted to update non existent cake")
|
||||
}
|
||||
|
||||
// get orders
|
||||
orders, err = s.GetFilteredOrder("", time.Time{}, time.Time{})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to get all orders after creation: %v", err)
|
||||
}
|
||||
if len(orders) != 2 {
|
||||
t.Error("Expected two orders returned, got ", len(orders))
|
||||
}
|
||||
newOrderPos := -1
|
||||
anotherOrderPos := -1
|
||||
for i, o := range orders {
|
||||
if o.ID == newOrder.ID {
|
||||
newOrderPos = i
|
||||
}
|
||||
if o.ID == anotherOrder.ID {
|
||||
anotherOrderPos = i
|
||||
}
|
||||
}
|
||||
if newOrderPos == -1 {
|
||||
t.Error("not found newOrder")
|
||||
}
|
||||
if newOrder.Name != orders[newOrderPos].Name ||
|
||||
newOrder.Surname != orders[newOrderPos].Surname ||
|
||||
newOrder.Phone != orders[newOrderPos].Phone ||
|
||||
newOrder.Status != orders[newOrderPos].Status ||
|
||||
newOrder.Location != orders[newOrderPos].Location ||
|
||||
newOrder.Accepted.Format("2006-01-02 15:04") != orders[newOrderPos].Accepted.Format("2006-01-02 15:04") ||
|
||||
newOrder.Date.Format("2006-01-02 15:04") != orders[newOrderPos].Date.Format("2006-01-02 15:04") {
|
||||
t.Errorf("Want %v\nGot %v", newOrder, orders[newOrderPos])
|
||||
}
|
||||
if !areCakeSlicesEqual(newOrder.Cakes, orders[newOrderPos].Cakes) {
|
||||
t.Errorf("Want %v\nGot %v", newOrder.Cakes, orders[newOrderPos].Cakes)
|
||||
}
|
||||
|
||||
if anotherOrderPos == -1 {
|
||||
t.Error("not found anotherOrder")
|
||||
}
|
||||
if anotherOrder.Name != orders[anotherOrderPos].Name ||
|
||||
anotherOrder.Surname != orders[anotherOrderPos].Surname ||
|
||||
anotherOrder.Phone != orders[anotherOrderPos].Phone ||
|
||||
anotherOrder.Status != orders[anotherOrderPos].Status ||
|
||||
anotherOrder.Location != orders[anotherOrderPos].Location ||
|
||||
anotherOrder.Accepted.Format("2006-01-02 15:04") != orders[anotherOrderPos].Accepted.Format("2006-01-02 15:04") ||
|
||||
anotherOrder.Date.Format("2006-01-02 15:04") != orders[anotherOrderPos].Date.Format("2006-01-02 15:04") {
|
||||
t.Errorf("Want %v\nGot %v", anotherOrder, orders[anotherOrderPos])
|
||||
}
|
||||
|
||||
if !areCakeSlicesEqual(anotherOrder.Cakes, orders[anotherOrderPos].Cakes) {
|
||||
t.Errorf("Want %v\nGot %v", anotherOrder.Cakes, orders[anotherOrderPos].Cakes)
|
||||
}
|
||||
|
||||
selectedOrder, err := s.GetOrder(newOrder.ID)
|
||||
if err != nil {
|
||||
t.Error("error getting an order by id ", err)
|
||||
}
|
||||
if newOrder.Name != selectedOrder.Name ||
|
||||
newOrder.Surname != selectedOrder.Surname ||
|
||||
newOrder.Phone != selectedOrder.Phone ||
|
||||
newOrder.Status != selectedOrder.Status ||
|
||||
newOrder.Location != selectedOrder.Location ||
|
||||
newOrder.Accepted.Format("2006-01-02 15:04") != selectedOrder.Accepted.Format("2006-01-02 15:04") ||
|
||||
newOrder.Date.Format("2006-01-02 15:04") != selectedOrder.Date.Format("2006-01-02 15:04") {
|
||||
t.Errorf("Want %v\nGot %v", newOrder, selectedOrder)
|
||||
}
|
||||
|
||||
if !areCakeSlicesEqual(newOrder.Cakes, selectedOrder.Cakes) {
|
||||
t.Errorf("Want %v\nGot %v", newOrder.Cakes, selectedOrder.Cakes)
|
||||
}
|
||||
|
||||
_, err = s.GetOrder(-1)
|
||||
if err == nil {
|
||||
t.Error("no error getting invalid order")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSliceComparison(t *testing.T) {
|
||||
a := []models.Cake{
|
||||
{Name: "ok", Price: 100, ID: 12, Amount: 10},
|
||||
{Name: "ok", Price: 11, ID: 13, Amount: 1},
|
||||
{Name: "ok", Price: 100, ID: 10, Amount: 11},
|
||||
}
|
||||
|
||||
b := []models.Cake{
|
||||
{Name: "okas", Price: 110, ID: 12, Amount: 10},
|
||||
{Name: "oksa", Price: 11, ID: 13, Amount: 1},
|
||||
{Name: "oasdk", Price: 101, ID: 10, Amount: 11},
|
||||
}
|
||||
if !areCakeSlicesEqual(a, b) {
|
||||
t.Error("aren't equal")
|
||||
}
|
||||
}
|
||||
|
||||
func areCakesEqual(a, b models.Cake) bool {
|
||||
return a.ID == b.ID && a.Amount == b.Amount
|
||||
}
|
||||
|
||||
func areCakeSlicesEqual(a, b []models.Cake) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
matched := make([]bool, len(a))
|
||||
|
||||
mainLoop:
|
||||
for _, e1 := range a {
|
||||
for i, e2 := range b {
|
||||
if matched[i] {
|
||||
continue
|
||||
}
|
||||
if areCakesEqual(e1, e2) {
|
||||
matched[i] = true
|
||||
continue mainLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, e := range matched {
|
||||
if e == false {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
48
store/user.go
Normal file
48
store/user.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/Bronku/iroon/crypto"
|
||||
"github.com/Bronku/iroon/models"
|
||||
)
|
||||
|
||||
func (s *Store) AddUser(login, password string) error {
|
||||
_, exists := s.GetUser(login)
|
||||
if exists {
|
||||
return errors.New("the user already exists")
|
||||
}
|
||||
query := "insert into user (login, password, salt) values(?, ?, ?)"
|
||||
salt := crypto.GenerateKey()
|
||||
hash := crypto.PasswordHash(password, salt)
|
||||
_, err := s.db.Exec(query, login, hash, salt)
|
||||
if err == nil {
|
||||
s.users[login] = models.User{Password: hash, Salt: salt}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *Store) loadUsers() (map[string]models.User, error) {
|
||||
out := make(map[string]models.User)
|
||||
query := "select login, password, salt from user;"
|
||||
rows, err := s.db.Query(query)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
for rows.Next() {
|
||||
var current models.User
|
||||
var login string
|
||||
err = rows.Scan(&login, ¤t.Password, ¤t.Salt)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
out[login] = current
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetUser(login string) (models.User, bool) {
|
||||
value, ok := s.users[login]
|
||||
return value, ok
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue