diff --git a/cmd/server/main.go b/cmd/server/main.go index f8bd9ef..e932f38 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -1,6 +1,8 @@ package main -import "vegan-barcode/internal/application" +import ( + "vegan-barcode/internal/application" +) func main() { application.Start() diff --git a/internal/application/application.go b/internal/application/application.go index 181c872..1df7485 100644 --- a/internal/application/application.go +++ b/internal/application/application.go @@ -3,20 +3,18 @@ package application import ( "vegan-barcode/internal/database" "vegan-barcode/internal/utils" - - "github.com/sirupsen/logrus" ) type Application struct { - db database.Database - log *logrus.Logger + db database.Database + // TODO: possibly include logger? } func Start() { application := Application{ - db: database.InitializeDatabase(), - log: utils.InitializeLogger(), + db: database.InitializeDatabase(), } - + utils.InitializeLogger() application.bindRoutes() + } diff --git a/internal/application/handlers.go b/internal/application/handlers.go index 0d0e490..46b4bf5 100644 --- a/internal/application/handlers.go +++ b/internal/application/handlers.go @@ -1,10 +1,12 @@ package application import ( + "fmt" "net/http" "vegan-barcode/internal/models" "github.com/gin-gonic/gin" + log "github.com/sirupsen/logrus" ) func (a *Application) TestHandler(c *gin.Context) { @@ -17,7 +19,7 @@ func (a *Application) GetClaimsHandler(c *gin.Context) { productClaims, err := a.GetClaims(system, barcode) if err != nil { - c.JSON(http.StatusInternalServerError, nil) + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } c.JSON(http.StatusOK, productClaims) @@ -30,9 +32,10 @@ func (a *Application) PostClaimHandler(c *gin.Context) { var requestBody models.UserClaimForm err := c.BindJSON(&requestBody) if err != nil { - c.JSON(http.StatusBadRequest, nil) + c.JSON(http.StatusBadRequest, fmt.Errorf("improperly formatted request: %w", err)) return } + log.Debugf("requestbody: %v", requestBody) claim, err := a.CreateClaim(system, barcode, requestBody) if err != nil { diff --git a/internal/application/models.go b/internal/application/models.go deleted file mode 100644 index b584a8a..0000000 --- a/internal/application/models.go +++ /dev/null @@ -1 +0,0 @@ -package application diff --git a/internal/application/services.go b/internal/application/services.go index ae26cf7..9120055 100644 --- a/internal/application/services.go +++ b/internal/application/services.go @@ -12,7 +12,7 @@ func (a *Application) GetClaims(system string, barcode string) (*models.ProductC return nil, err } if product == nil { - return nil, errors.New("Product not found") + return nil, errors.New("product not found") } claims, err := a.db.FindClaimsByProductID(product.Id) diff --git a/internal/application/utils/logger.go b/internal/application/utils/logger.go deleted file mode 100644 index a83abc3..0000000 --- a/internal/application/utils/logger.go +++ /dev/null @@ -1,13 +0,0 @@ -package utils - -import ( - "github.com/sirupsen/logrus" -) - -func InitializeLogger() *logrus.Logger { - log := logrus.New() - log.SetFormatter(&logrus.TextFormatter{ - FullTimestamp: true, // Include the full timestamp (with date and time) - }) - return log -} diff --git a/internal/database/claims.go b/internal/database/claims.go index 92a5f1f..033ea4b 100644 --- a/internal/database/claims.go +++ b/internal/database/claims.go @@ -2,6 +2,7 @@ package database import ( "context" + "fmt" "vegan-barcode/internal/models" "github.com/vingarcia/ksql" @@ -10,7 +11,7 @@ import ( func (d *Database) FindClaimsByProductID(product_id int) (claims []models.Claim, err error) { ctx := context.Background() - err = d.db.Query(ctx, claims, ` + err = d.db.Query(ctx, &claims, ` SELECT cluster, id, @@ -35,29 +36,30 @@ func (d *Database) FindClaimsByProductID(product_id int) (claims []models.Claim, ROW_NUMBER() OVER (PARTITION BY category ORDER BY created_at DESC) AS rn FROM ( ( - SELECT "user" as cluster, id, product_id, null as worker_type, evidence_type, evidence, unnest(claim) as category, true as polarity, created_at, created_by FROM user_claims + SELECT 'user' as cluster, id, product_id, null as worker_type, evidence_type, evidence, unnest(claims) as category, true as polarity, created_at, created_by FROM user_claims UNION ALL - SELECT "automated" as cluster, id, product_id, worker_type, null as evidence_type, evidence, unnest(claim) as category, true as polarity, created_at, null as created_by FROM automated_claims + SELECT 'automated' as cluster, id, product_id, worker_type, null as evidence_type, evidence, unnest(claims) as category, true as polarity, created_at, null as created_by FROM automated_claims ) UNION ALL ( - SELECT "user" as cluster, id, product_id, null as worker_type, evidence_type, evidence, unnest(counter_claim) as category, false as polarity, created_at, created_by FROM user_claims + SELECT 'user' as cluster, id, product_id, null as worker_type, evidence_type, evidence, unnest(counterclaims) as category, false as polarity, created_at, created_by FROM user_claims UNION ALL - SELECT "automated" as cluster, id, product_id, worker_type, null as evidence_type, evidence, unnest(counter_claim) as category, false as polarity, created_at, null as created_by FROM automated_claims + SELECT 'automated' as cluster, id, product_id, worker_type, null as evidence_type, evidence, unnest(counterclaims) as category, false as polarity, created_at, null as created_by FROM automated_claims ) - ) + ) AS combined_claims WHERE product_id = $1 - ) + ) AS ranked_claims WHERE rn = 1 ORDER BY created_at; `, product_id) if err != nil { - return claims, err + return nil, fmt.Errorf("query failed: %w", err) } return } +// exists only for testing func (database *Database) FindUserClaimById(claim_id int) (*UserClaim, error) { ctx := context.Background() @@ -79,6 +81,7 @@ func (d *Database) CreateUserClaim(product_id int, form models.UserClaimForm) (* Evidence: form.Evidence, Claims: form.Claims, Counterclaims: form.Counterclaims, + // TODO: Add created by } err := d.db.Insert(ctx, UserClaimsTable, &uc) diff --git a/internal/database/claims_test.go b/internal/database/claims_test.go index 8fcc192..81769a6 100644 --- a/internal/database/claims_test.go +++ b/internal/database/claims_test.go @@ -16,7 +16,7 @@ func TestCreateClaimByProductId(t *testing.T) { Ingredients: "flour,egg,milk,water,salt,butter", }, Claims: []models.ClaimType{ - models.ContainsEggs, + models.ContainsEgg, models.ContainsMilk, }, Counterclaims: []models.ClaimType{ diff --git a/internal/database/database.go b/internal/database/database.go index 1c818a6..71555d8 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -61,10 +61,10 @@ func (database *Database) createTables(ctx context.Context) { CREATE TABLE IF NOT EXISTS user_claims ( id BIGSERIAL PRIMARY KEY, product_id INTEGER, - evidence_type INTEGER, + evidence_type TEXT, evidence JSONB, - claims INTEGER[], - counterclaims INTEGER[], + claims TEXT[], + counterclaims TEXT[], created_at TIMESTAMPTZ, created_by TEXT, @@ -80,10 +80,10 @@ func (database *Database) createTables(ctx context.Context) { CREATE TABLE IF NOT EXISTS automated_claims ( id BIGSERIAL PRIMARY KEY, product_id INTEGER, - worker_type INTEGER, + worker_type TEXT, evidence JSONB, - claims INTEGER[], - counterclaims INTEGER[], + claims TEXT[], + counterclaims TEXT[], created_at TIMESTAMPTZ, CONSTRAINT fk_product_id FOREIGN KEY(product_id) REFERENCES products(id) diff --git a/internal/database/products.go b/internal/database/products.go index 75dc6ab..1eb3e5c 100644 --- a/internal/database/products.go +++ b/internal/database/products.go @@ -2,8 +2,10 @@ package database import ( "context" + "fmt" "time" + log "github.com/sirupsen/logrus" "github.com/vingarcia/ksql" ) @@ -14,6 +16,8 @@ func (d *Database) FindProductByBarcode(system string, barcode string) (*Product var product Product err := d.db.QueryOne(ctx, &product, "FROM products WHERE system = $1 AND barcode = $2", system, barcode) + + // No error because product may just not exist. if err == ksql.ErrRecordNotFound { return nil, nil } @@ -23,6 +27,7 @@ func (d *Database) FindProductByBarcode(system string, barcode string) (*Product return &product, nil } +// Doesnt handle checking if product exists. func (d *Database) CreateProduct(system string, barcode string) (*Product, error) { ctx := context.Background() var product = Product{ @@ -31,8 +36,10 @@ func (d *Database) CreateProduct(system string, barcode string) (*Product, error Created_at: time.Now(), } + log.Debugf("made new product: %v", product) + if err := d.db.Insert(ctx, ProductsTable, &product); err != nil { - return nil, err + return nil, fmt.Errorf("failed to insert new product: %w", err) } return &product, nil diff --git a/internal/models/models.go b/internal/models/models.go index 3b1b77a..a299443 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -4,59 +4,60 @@ import ( "time" ) -type ClaimType int +type ClaimType string const ( - ContainsMeat ClaimType = iota - ContainsFish - ContainsEggs - ContainsMilk - ContainsHoney - ContainsWax - ContainsFur - ContainsLeather - ContainsAnimalFibers - ContainsWool - ContainsFeathers - AnimalTesting - MonkeySlavery + ContainsMeat ClaimType = "meat" + ContainsFish ClaimType = "fish" + ContainsEgg ClaimType = "egg" + ContainsMilk ClaimType = "milk" + ContainsHoney ClaimType = "honey" + ContainsWax ClaimType = "wax" + ContainsFur ClaimType = "fur" + ContainsLeather ClaimType = "leather" + ContainsAnimalFibers ClaimType = "animal_fibers" + ContainsWool ClaimType = "wool" + ContainsFeathers ClaimType = "feathers" + AnimalTesting ClaimType = "animal_testing" + MonkeySlavery ClaimType = "monkey_slavery" ) -type WorkerType int +type WorkerType string const ( - Barnivore WorkerType = iota + Barnivore WorkerType = "barnivore" ) -type EvidenceType int +// Using a string here to make database modification easier. +type EvidenceType string const ( - ManufacturerWebsite EvidenceType = iota - IngredientsList + ManufacturerWebsite EvidenceType = "manufacturer" + IngredientsList EvidenceType = "ingredients" ) type IngredientsListEvidence struct { Ingredients string } -type ClusterType int +type ClusterType string const ( - User ClusterType = iota - Automated + User ClusterType = "user" + Automated ClusterType = "auto" ) // Generic claim type for combining both automated and user claims. type Claim struct { - Id int - Worker_type WorkerType - Evidence_type EvidenceType - Evidence struct{} - Category ClaimType - Polarity bool - Created_at time.Time - Created_by string - Cluster ClusterType + Id int `ksql:"id"` + Worker_type *WorkerType `ksql:"worker_type"` + Evidence_type EvidenceType `ksql:"evidence_type"` + Evidence struct{} `ksql:"evidence"` + Category ClaimType `ksql:"category"` + Polarity bool `ksql:"polarity"` + Created_at time.Time `ksql:"created_at"` + Created_by string `ksql:"created_by"` + Cluster ClusterType `ksql:"cluster"` } type ProductClaims struct { diff --git a/internal/utils/logger.go b/internal/utils/logger.go new file mode 100644 index 0000000..16e3d09 --- /dev/null +++ b/internal/utils/logger.go @@ -0,0 +1,22 @@ +package utils + +import ( + "io" + "os" + + log "github.com/sirupsen/logrus" +) + +func InitializeLogger() { + file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) + if err != nil { + log.Fatal(err) + } + log.SetOutput(io.MultiWriter(os.Stdout, file)) + + log.SetFormatter(&log.TextFormatter{ + FullTimestamp: true, + }) + + log.SetLevel(log.DebugLevel) +}