Skip to content

Commit

Permalink
added product queries
Browse files Browse the repository at this point in the history
  • Loading branch information
ByteSizedMarius committed Aug 7, 2024
1 parent 496e56c commit 68b16dd
Show file tree
Hide file tree
Showing 12 changed files with 542 additions and 30 deletions.
112 changes: 102 additions & 10 deletions cmd/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,25 +29,40 @@ func main() {
fmt.Println(align("coupons") + "Get coupons")
fmt.Println(align("recalls") + "Get recalls")
fmt.Println(align("discounts -id <market-id> [-raw] [-catGroup]") + "Get discounts")
fmt.Println(align("categories -id <market-id> [-printAll]") + "Get product categories")
fmt.Println(align("products -id <market-id> [-category <category> -search <query>] [-page <page>] [-perPage <productsPerPage>]") + "\n" + align("") + "Get products from a category or by query")
fmt.Println("\nSubcommand-Flags:")
fmt.Println(align("-query <query>") + "Search query. Can be a city, postal code, street, etc.")
fmt.Println(align("-id <market-id>") + "ID of the market or discount. Get it from marketsearch.")
fmt.Println(align("-raw") + "Whether you want raw output format (directly from the API) or parsed.")
fmt.Println(align("-catGroup") + "Group by product category instead of rewe-app-category")
fmt.Println(align("-catGroup") + "Group by product category instead of rewe-app category")
fmt.Println(align("-printAll") + "Print all available product categories (very many)")
fmt.Println(align("-category <category>") + "The slug of the category to fetch the products from")
fmt.Println(align("-search <query>") + "Search query for products. Can be any term or EANs for example")
fmt.Println(align("-page <page>") + "Page number for pagination. Starts at 1, default 1. The amount of available pages is included in the output")
fmt.Println(align("-perPage <productsPerPage>") + "Number of products per page. Default 30")
fmt.Println("\nExamples:")
fmt.Println(" rewerse.exe -cert cert.pem -key p.key marketsearch -query Köln")
fmt.Println(" rewerse.exe marketsearch -query Köln")
fmt.Println(" rewerse.exe marketdetails -id 1763153")
fmt.Println(" rewerse.exe discounts -id 1763153")
fmt.Println(" rewerse.exe -json discounts -id 1763153 -raw")
fmt.Println(" rewerse.exe discounts -id 1763153 -catGroup")
fmt.Println(" rewerse.exe -cert cert.pem -key p.key marketsearch -query Köln")
fmt.Println(" rewerse.exe categories -id 831002 -printAll")
fmt.Println(" rewerse.exe products -id 831002 -category kueche-haushalt -page 2 -perPage 10")
fmt.Println(" rewerse.exe products -id 831002 -search Karotten")
}

certFile := flag.String("cert", "", "Path to the certificate file")
keyFile := flag.String("key", "", "Path to the key file")
jsonOutput := flag.Bool("json", false, "Output in JSON format (default false)")
flag.Parse()

if flag.NArg() == 0 {
flag.Usage()
os.Exit(1)
}

var crt, key string
if *certFile == "" {
crt = "certificate.pem"
Expand All @@ -63,16 +78,11 @@ func main() {
var err error
err = rewerse.SetCertificate(crt, key)
if err != nil && *certFile == "" && *keyFile == "" {
flag.Usage()
fmt.Println("Please provide the paths to the certificate and key files.\n\nrewerse.exe -cert cert.pem -key p.key [...]")
os.Exit(1)
}
hdl(err)

if flag.NArg() == 0 {
flag.Usage()
os.Exit(1)
}

marketSearchCmd := flag.NewFlagSet("marketsearch", flag.ExitOnError)
marketSearchQuery := marketSearchCmd.String("query", "", "Search query")

Expand All @@ -84,6 +94,17 @@ func main() {
rawOutput := discountsCmd.Bool("raw", false, "Whether to return raw API Data")
groupProduct := discountsCmd.Bool("catGroup", false, "Group by product category instead of app-category")

pcategories := flag.NewFlagSet("categories", flag.ExitOnError)
pcategoriesMarketID := pcategories.String("id", "", "Market-ID")
all := pcategories.Bool("printAll", false, "Print all available product categories")

products := flag.NewFlagSet("products", flag.ExitOnError)
productsMarketID := products.String("id", "", "Market-ID")
productsCategory := products.String("category", "", "Category slug")
productsSearch := products.String("search", "", "Search query")
productsPage := products.Int("page", 0, "Page number")
productsPerPage := products.Int("perPage", 0, "Products per page")

var data any
switch flag.Arg(0) {
case "marketsearch":
Expand Down Expand Up @@ -118,9 +139,73 @@ func main() {
if *groupProduct {
data = data.(rewerse.Discounts).GroupByProductCategory()
}
case "categories":
hdl(pcategories.Parse(flag.Args()[1:]))
if *pcategoriesMarketID == "" {
fmt.Println("Expected market ID")
os.Exit(1)
}

var so rewerse.ShopOverview
so, err = rewerse.GetShopOverview(*pcategoriesMarketID)
hdl(err)

if *all && *jsonOutput {
fmt.Println("Cannot print all and output in JSON format (json is all by default)")
return
}

if *all {
fmt.Println(so.StringAll())
return
} else if !*jsonOutput {
fmt.Println(so.String())
return
} else {
data = so.ProductCategories
}
case "products":
hdl(products.Parse(flag.Args()[1:]))
if *productsMarketID == "" {
fmt.Println("Expected market ID")
os.Exit(1)
}

if *productsCategory == "" && *productsSearch == "" {
fmt.Println("Expected category or search query")
os.Exit(1)
}

if *productsCategory != "" && *productsSearch != "" {
fmt.Println("Expected either category or search query, not both")
os.Exit(1)
}

var opts *rewerse.ProductOpts
if *productsPage != 0 {
opts = &rewerse.ProductOpts{
Page: *productsPage,
}
}

if *productsPerPage != 0 {
if opts == nil {
opts = &rewerse.ProductOpts{
ObjectsPerPage: *productsPerPage,
}
} else {
opts.ObjectsPerPage = *productsPerPage
}
}

if *productsCategory != "" {
data, err = rewerse.GetCategoryProducts(*productsMarketID, *productsCategory, opts)
} else {
data, err = rewerse.GetProducts(*productsMarketID, *productsSearch, opts)
}

default:
fmt.Println("Expected 'marketsearch', 'marketdetails', 'coupons', 'recalls' or 'discounts' subcommands")
fmt.Println("Expected one of the following subcommands:\n- marketsearch\n- marketdetails\n- coupons\n- recalls\n- discounts\n- categories\n- products")
os.Exit(1)
}

Expand All @@ -135,5 +220,12 @@ func main() {
}

func align(s string) string {
return " " + s + strings.Repeat(" ", 50-len(s))
al := 50
if len(s) > al {
al = 0
} else {
al -= len(s)
}

return " " + s + strings.Repeat(" ", al)
}
78 changes: 78 additions & 0 deletions pkg/category_structs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package rewerse

import (
"fmt"
"strings"
)

type ProductSearchResults struct {
Data struct {
Products struct {
Pagination struct {
ObjectsPerPage int `json:"objectsPerPage"`
CurrentPage int `json:"currentPage"`
PageCount int `json:"pageCount"`
ObjectCount int `json:"objectCount"`
} `json:"pagination"`
Search struct {
Term struct {
Original string `json:"original"`
Corrected any `json:"corrected"`
} `json:"term"`
} `json:"search"`
Products []Product `json:"products"`
} `json:"products"`
} `json:"data"`
Extensions struct {
HTTP []struct {
Path []string `json:"path"`
Message string `json:"message"`
StatusCode int `json:"statusCode"`
ResponseBody any `json:"responseBody"`
} `json:"http"`
} `json:"extensions"`
}

func (psr ProductSearchResults) String() string {
var s strings.Builder
s.WriteString("Products for query " + psr.Data.Products.Search.Term.Original + "\n")
s.WriteString(fmt.Sprintf("Page %d of %d\n", psr.Data.Products.Pagination.CurrentPage, psr.Data.Products.Pagination.PageCount))
s.WriteString(sep("") + "\n")
for _, product := range psr.Data.Products.Products {
s.WriteString(product.Title + "\n")
}
return s.String()
}

type Product struct {
ProductID string `json:"productId"`
Title string `json:"title"`
DepositLabel any `json:"depositLabel"`
ImageURL string `json:"imageURL"`
Attributes struct {
IsBulkyGood bool `json:"isBulkyGood"`
IsOrganic bool `json:"isOrganic"`
IsVegan bool `json:"isVegan"`
IsVegetarian bool `json:"isVegetarian"`
IsDairyFree bool `json:"isDairyFree"`
IsGlutenFree bool `json:"isGlutenFree"`
IsBiocide bool `json:"isBiocide"`
IsAgeRestricted any `json:"isAgeRestricted"`
IsRegional bool `json:"isRegional"`
IsNew bool `json:"isNew"`
} `json:"attributes"`
OrderLimit int `json:"orderLimit"`
Categories []string `json:"categories"`
DetailsViewRequired bool `json:"detailsViewRequired"`
ArticleID string `json:"articleId"`
Listing struct {
ListingID string `json:"listingId"`
ListingVersion int `json:"listingVersion"`
CurrentRetailPrice int `json:"currentRetailPrice"`
TotalRefundPrice any `json:"totalRefundPrice"`
Grammage string `json:"grammage"`
Discount any `json:"discount"`
LoyaltyBonus any `json:"loyaltyBonus"`
} `json:"listing"`
Advertisement any `json:"advertisement"`
}
4 changes: 2 additions & 2 deletions pkg/coupons.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type OneScanCoupons struct {
}

func (o OneScanCoupons) String() string {
coupons := fmt.Sprintf("%d OneScan-Coupons\n\n", len(o.Coupons))
coupons := fmt.Sprintf("Got %d OneScan-Coupons\n\n", len(o.Coupons))
for _, c := range o.Coupons {
coupons += c.Title + "\n"
coupons += strings.ReplaceAll(c.Description, "\n", " ")
Expand Down Expand Up @@ -83,7 +83,7 @@ type Coupons struct {
}

func (cs Coupons) String() string {
coupons := fmt.Sprintf("%d Coupons\n\n", len(cs.Data.GetCoupons.Coupons))
coupons := fmt.Sprintf("Got %d Coupons\n\n", len(cs.Data.GetCoupons.Coupons))
for _, c := range cs.Data.GetCoupons.Coupons {
coupons += c.Title + " // " + c.OfferTitle + "\n"
coupons += c.Subtitle + "\n"
Expand Down
6 changes: 3 additions & 3 deletions pkg/discounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ const (
// It contains the discount categories, which in turn contain the actual discounts.
// I removed various parameters I deemed unnecessary and parsed into different datatypes where it made sense to me.
// The struct Discounts also provides some helper methods.
func GetDiscounts(marketID string) (d Discounts, err error) {
func GetDiscounts(marketID string) (ds Discounts, err error) {
rd, err := GetDiscountsRaw(marketID)
if err != nil {
return
}

d.ValidUntil = time.Unix(int64(rd.Data.Offers.UntilDate)/1000, 0)
ds.ValidUntil = time.Unix(int64(rd.Data.Offers.UntilDate)/1000, 0)
var foundAnyManuf bool // detect if the manufacturer format changed
for _, rawCat := range rd.Data.Offers.Categories {
cat := DiscountCategory{
Expand Down Expand Up @@ -101,7 +101,7 @@ func GetDiscounts(marketID string) (d Discounts, err error) {
cat.Offers = append(cat.Offers, discount)
}

d.Categories = append(d.Categories, cat)
ds.Categories = append(ds.Categories, cat)
}

if !foundAnyManuf {
Expand Down
15 changes: 13 additions & 2 deletions pkg/market_structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
type Markets []Market

func (ms Markets) String() string {
s := "ID Standort\n"
s := "ID Location\n"
for _, m := range ms {
s += m.String() + "\n"
}
Expand Down Expand Up @@ -140,5 +140,16 @@ func sep(base string) string {
}

func align(s string) string {
return " " + s + ":" + strings.Repeat(" ", 22-len(s))
al := 22
if len(s) > al {
al = 0
} else {
al -= len(s)
}

return " " + s + ":" + strings.Repeat(" ", al)
}

func alignL(s string, n int) string {
return strings.Repeat(" ", n*3) + s
}
10 changes: 5 additions & 5 deletions pkg/misc.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ type Recalls []Recall

func (rs Recalls) String() string {
if len(rs) == 0 {
return "Aktuell keine Produktrückrufe"
return "Currently no recalls"
}

recalls := "Produktrückrufe:\n"
recalls := "Recalls:\n"
for _, r := range rs {
recalls += r.String() + "\n"
}
Expand Down Expand Up @@ -57,14 +57,14 @@ type RecipeHub struct {

func (rh RecipeHub) String() string {
recipeHub := "Recipe Hub\n\n"
recipeHub += "Rezept des Tages\n--------------------\n" + rh.RecipeOfTheDay.String() + "\n"
recipeHub += "Recipe of the Day\n--------------------\n" + rh.RecipeOfTheDay.String() + "\n"

recipeHub += "Beliebte Rezepte\n--------------------\n"
recipeHub += "Popular Recipes\n--------------------\n"
for _, r := range rh.PopularRecipes {
recipeHub += r.String() + "\n"
}

recipeHub += "Verfügbare Rezept-Kategorien\n--------------------\n"
recipeHub += "Available Categories\n--------------------\n"
for _, c := range rh.Categories {
recipeHub += c.Title + "\n"
}
Expand Down
Loading

0 comments on commit 68b16dd

Please sign in to comment.