make get and post endpoints work, update enums to be strings, add log file output
This commit is contained in:
parent
79977f1a18
commit
e762fc2abd
|
@ -1,6 +1,8 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "vegan-barcode/internal/application"
|
import (
|
||||||
|
"vegan-barcode/internal/application"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
application.Start()
|
application.Start()
|
||||||
|
|
|
@ -3,20 +3,18 @@ package application
|
||||||
import (
|
import (
|
||||||
"vegan-barcode/internal/database"
|
"vegan-barcode/internal/database"
|
||||||
"vegan-barcode/internal/utils"
|
"vegan-barcode/internal/utils"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Application struct {
|
type Application struct {
|
||||||
db database.Database
|
db database.Database
|
||||||
log *logrus.Logger
|
// TODO: possibly include logger?
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start() {
|
func Start() {
|
||||||
application := Application{
|
application := Application{
|
||||||
db: database.InitializeDatabase(),
|
db: database.InitializeDatabase(),
|
||||||
log: utils.InitializeLogger(),
|
|
||||||
}
|
}
|
||||||
|
utils.InitializeLogger()
|
||||||
application.bindRoutes()
|
application.bindRoutes()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package application
|
package application
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"vegan-barcode/internal/models"
|
"vegan-barcode/internal/models"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (a *Application) TestHandler(c *gin.Context) {
|
func (a *Application) TestHandler(c *gin.Context) {
|
||||||
|
@ -17,7 +19,7 @@ func (a *Application) GetClaimsHandler(c *gin.Context) {
|
||||||
|
|
||||||
productClaims, err := a.GetClaims(system, barcode)
|
productClaims, err := a.GetClaims(system, barcode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, nil)
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, productClaims)
|
c.JSON(http.StatusOK, productClaims)
|
||||||
|
@ -30,9 +32,10 @@ func (a *Application) PostClaimHandler(c *gin.Context) {
|
||||||
var requestBody models.UserClaimForm
|
var requestBody models.UserClaimForm
|
||||||
err := c.BindJSON(&requestBody)
|
err := c.BindJSON(&requestBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusBadRequest, nil)
|
c.JSON(http.StatusBadRequest, fmt.Errorf("improperly formatted request: %w", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Debugf("requestbody: %v", requestBody)
|
||||||
|
|
||||||
claim, err := a.CreateClaim(system, barcode, requestBody)
|
claim, err := a.CreateClaim(system, barcode, requestBody)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package application
|
|
|
@ -12,7 +12,7 @@ func (a *Application) GetClaims(system string, barcode string) (*models.ProductC
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if product == nil {
|
if product == nil {
|
||||||
return nil, errors.New("Product not found")
|
return nil, errors.New("product not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
claims, err := a.db.FindClaimsByProductID(product.Id)
|
claims, err := a.db.FindClaimsByProductID(product.Id)
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -2,6 +2,7 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"vegan-barcode/internal/models"
|
"vegan-barcode/internal/models"
|
||||||
|
|
||||||
"github.com/vingarcia/ksql"
|
"github.com/vingarcia/ksql"
|
||||||
|
@ -10,7 +11,7 @@ import (
|
||||||
func (d *Database) FindClaimsByProductID(product_id int) (claims []models.Claim, err error) {
|
func (d *Database) FindClaimsByProductID(product_id int) (claims []models.Claim, err error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
err = d.db.Query(ctx, claims, `
|
err = d.db.Query(ctx, &claims, `
|
||||||
SELECT
|
SELECT
|
||||||
cluster,
|
cluster,
|
||||||
id,
|
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
|
ROW_NUMBER() OVER (PARTITION BY category ORDER BY created_at DESC) AS rn
|
||||||
FROM (
|
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
|
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
|
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
|
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
|
WHERE product_id = $1
|
||||||
)
|
) AS ranked_claims
|
||||||
WHERE rn = 1
|
WHERE rn = 1
|
||||||
ORDER BY created_at;
|
ORDER BY created_at;
|
||||||
`, product_id)
|
`, product_id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return claims, err
|
return nil, fmt.Errorf("query failed: %w", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exists only for testing
|
||||||
func (database *Database) FindUserClaimById(claim_id int) (*UserClaim, error) {
|
func (database *Database) FindUserClaimById(claim_id int) (*UserClaim, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
@ -79,6 +81,7 @@ func (d *Database) CreateUserClaim(product_id int, form models.UserClaimForm) (*
|
||||||
Evidence: form.Evidence,
|
Evidence: form.Evidence,
|
||||||
Claims: form.Claims,
|
Claims: form.Claims,
|
||||||
Counterclaims: form.Counterclaims,
|
Counterclaims: form.Counterclaims,
|
||||||
|
// TODO: Add created by
|
||||||
}
|
}
|
||||||
|
|
||||||
err := d.db.Insert(ctx, UserClaimsTable, &uc)
|
err := d.db.Insert(ctx, UserClaimsTable, &uc)
|
||||||
|
|
|
@ -16,7 +16,7 @@ func TestCreateClaimByProductId(t *testing.T) {
|
||||||
Ingredients: "flour,egg,milk,water,salt,butter",
|
Ingredients: "flour,egg,milk,water,salt,butter",
|
||||||
},
|
},
|
||||||
Claims: []models.ClaimType{
|
Claims: []models.ClaimType{
|
||||||
models.ContainsEggs,
|
models.ContainsEgg,
|
||||||
models.ContainsMilk,
|
models.ContainsMilk,
|
||||||
},
|
},
|
||||||
Counterclaims: []models.ClaimType{
|
Counterclaims: []models.ClaimType{
|
||||||
|
|
|
@ -61,10 +61,10 @@ func (database *Database) createTables(ctx context.Context) {
|
||||||
CREATE TABLE IF NOT EXISTS user_claims (
|
CREATE TABLE IF NOT EXISTS user_claims (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
product_id INTEGER,
|
product_id INTEGER,
|
||||||
evidence_type INTEGER,
|
evidence_type TEXT,
|
||||||
evidence JSONB,
|
evidence JSONB,
|
||||||
claims INTEGER[],
|
claims TEXT[],
|
||||||
counterclaims INTEGER[],
|
counterclaims TEXT[],
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
created_by TEXT,
|
created_by TEXT,
|
||||||
|
|
||||||
|
@ -80,10 +80,10 @@ func (database *Database) createTables(ctx context.Context) {
|
||||||
CREATE TABLE IF NOT EXISTS automated_claims (
|
CREATE TABLE IF NOT EXISTS automated_claims (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
product_id INTEGER,
|
product_id INTEGER,
|
||||||
worker_type INTEGER,
|
worker_type TEXT,
|
||||||
evidence JSONB,
|
evidence JSONB,
|
||||||
claims INTEGER[],
|
claims TEXT[],
|
||||||
counterclaims INTEGER[],
|
counterclaims TEXT[],
|
||||||
created_at TIMESTAMPTZ,
|
created_at TIMESTAMPTZ,
|
||||||
|
|
||||||
CONSTRAINT fk_product_id FOREIGN KEY(product_id) REFERENCES products(id)
|
CONSTRAINT fk_product_id FOREIGN KEY(product_id) REFERENCES products(id)
|
||||||
|
|
|
@ -2,8 +2,10 @@ package database
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/vingarcia/ksql"
|
"github.com/vingarcia/ksql"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,6 +16,8 @@ func (d *Database) FindProductByBarcode(system string, barcode string) (*Product
|
||||||
|
|
||||||
var product Product
|
var product Product
|
||||||
err := d.db.QueryOne(ctx, &product, "FROM products WHERE system = $1 AND barcode = $2", system, barcode)
|
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 {
|
if err == ksql.ErrRecordNotFound {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -23,6 +27,7 @@ func (d *Database) FindProductByBarcode(system string, barcode string) (*Product
|
||||||
return &product, nil
|
return &product, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Doesnt handle checking if product exists.
|
||||||
func (d *Database) CreateProduct(system string, barcode string) (*Product, error) {
|
func (d *Database) CreateProduct(system string, barcode string) (*Product, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
var product = Product{
|
var product = Product{
|
||||||
|
@ -31,8 +36,10 @@ func (d *Database) CreateProduct(system string, barcode string) (*Product, error
|
||||||
Created_at: time.Now(),
|
Created_at: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("made new product: %v", product)
|
||||||
|
|
||||||
if err := d.db.Insert(ctx, ProductsTable, &product); err != nil {
|
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
|
return &product, nil
|
||||||
|
|
|
@ -4,59 +4,60 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ClaimType int
|
type ClaimType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ContainsMeat ClaimType = iota
|
ContainsMeat ClaimType = "meat"
|
||||||
ContainsFish
|
ContainsFish ClaimType = "fish"
|
||||||
ContainsEggs
|
ContainsEgg ClaimType = "egg"
|
||||||
ContainsMilk
|
ContainsMilk ClaimType = "milk"
|
||||||
ContainsHoney
|
ContainsHoney ClaimType = "honey"
|
||||||
ContainsWax
|
ContainsWax ClaimType = "wax"
|
||||||
ContainsFur
|
ContainsFur ClaimType = "fur"
|
||||||
ContainsLeather
|
ContainsLeather ClaimType = "leather"
|
||||||
ContainsAnimalFibers
|
ContainsAnimalFibers ClaimType = "animal_fibers"
|
||||||
ContainsWool
|
ContainsWool ClaimType = "wool"
|
||||||
ContainsFeathers
|
ContainsFeathers ClaimType = "feathers"
|
||||||
AnimalTesting
|
AnimalTesting ClaimType = "animal_testing"
|
||||||
MonkeySlavery
|
MonkeySlavery ClaimType = "monkey_slavery"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WorkerType int
|
type WorkerType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Barnivore WorkerType = iota
|
Barnivore WorkerType = "barnivore"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EvidenceType int
|
// Using a string here to make database modification easier.
|
||||||
|
type EvidenceType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ManufacturerWebsite EvidenceType = iota
|
ManufacturerWebsite EvidenceType = "manufacturer"
|
||||||
IngredientsList
|
IngredientsList EvidenceType = "ingredients"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IngredientsListEvidence struct {
|
type IngredientsListEvidence struct {
|
||||||
Ingredients string
|
Ingredients string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClusterType int
|
type ClusterType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
User ClusterType = iota
|
User ClusterType = "user"
|
||||||
Automated
|
Automated ClusterType = "auto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Generic claim type for combining both automated and user claims.
|
// Generic claim type for combining both automated and user claims.
|
||||||
type Claim struct {
|
type Claim struct {
|
||||||
Id int
|
Id int `ksql:"id"`
|
||||||
Worker_type WorkerType
|
Worker_type *WorkerType `ksql:"worker_type"`
|
||||||
Evidence_type EvidenceType
|
Evidence_type EvidenceType `ksql:"evidence_type"`
|
||||||
Evidence struct{}
|
Evidence struct{} `ksql:"evidence"`
|
||||||
Category ClaimType
|
Category ClaimType `ksql:"category"`
|
||||||
Polarity bool
|
Polarity bool `ksql:"polarity"`
|
||||||
Created_at time.Time
|
Created_at time.Time `ksql:"created_at"`
|
||||||
Created_by string
|
Created_by string `ksql:"created_by"`
|
||||||
Cluster ClusterType
|
Cluster ClusterType `ksql:"cluster"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductClaims struct {
|
type ProductClaims struct {
|
||||||
|
|
22
internal/utils/logger.go
Normal file
22
internal/utils/logger.go
Normal file
|
@ -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)
|
||||||
|
}
|
Loading…
Reference in a new issue