go_service/repositories/ParseRepository.go

327 lines
8.0 KiB
Go

package repositories
import (
"db_service/models"
helper "db_service/pkg"
"encoding/json"
"errors"
"net/http"
"reflect"
"regexp"
"strconv"
"strings"
)
type LinkParser struct {
link string
}
func NewLinkParser(link string) LinkParser {
return LinkParser{link: link}
}
func (l LinkParser) ParseLink() (models.TrendyolProductDetailModel, error) {
helper.Info("link: ", l.link)
productId := ""
if isShortLink(l.link) {
productId = getProductIdFromShortLink(l.link)
} else {
productId = getProductIdFromLink(l.link)
}
if len(productId) == 0 {
parseErr := errors.New("can not parse product id")
helper.Error(parseErr)
return models.TrendyolProductDetailModel{}, parseErr
}
helper.Info("productId: ", productId)
return GetProductDetails(productId)
}
func getProductIdFromShortLink(shortLink string) string {
var productId string
client, _ := helper.NewHttpClient()
req, err := http.NewRequest("GET", shortLink, nil)
req.Proto = "HTTP/2.0"
if err != nil {
helper.Error(err)
return ""
}
q := req.URL.Query()
req.URL.RawQuery = q.Encode()
req.Header.Set("Connection", "close")
req = req.WithContext(req.Context())
req.Close = true
client.CloseIdleConnections()
response, err := client.Do(req)
if err != nil {
helper.Error(err)
return productId
}
defer response.Body.Close()
url := response.Request.URL.Path
helper.Info("link url: ", url)
productId = getProductIdFromLink(url)
helper.Info("productId: ", productId)
return productId
}
func getProductIdFromLink(link string) string {
var productId string
if strings.Contains(link, "?") {
link = strings.Split(link, "?")[0]
}
strArr := strings.Split(link, "-")
productId = strArr[len(strArr)-1]
return productId
}
func isShortLink(link string) bool {
return !strings.Contains(link, "trendyol.com")
}
// GetProductDetails return JSON object. Merges color option
func GetProductDetails(productId string) (models.TrendyolProductDetailModel, error) {
var response models.TrendyolProductDetailResponse
productDetailModel := models.TrendyolProductDetailModel{}
// set linearVariants false to get variants
url := "https://public.trendyol.com/discovery-web-productgw-service/api/productDetail/" + productId + "?storefrontId=1&culture=tr-TR&linearVariants=false"
body, err := helper.SendRequest("GET", url, nil, "")
if err != nil {
return productDetailModel, err
}
err = json.Unmarshal(body, &response)
if err != nil {
helper.Error(err)
return productDetailModel, err
}
productDetailModel = response.Result
return productDetailModel, nil
//test
}
// getProductDetailWithOptions returns JSON with variants
func (l LinkParser) GetProductDetailWithOptions(productId, productGroupId int) (models.Product, error) {
primaryProductDetail, err := GetProductDetails(strconv.Itoa(productId))
if err != nil {
return models.Product{}, err
}
productDetailJSON := CreateJSONFromModel(primaryProductDetail)
if productDetailJSON != nil {
colorVariants, err := GetProductColorVariants(productGroupId)
var colorVariantsJson []map[string]interface{}
if err != nil {
return models.Product{}, err
}
// get the color variant products
for _, slicingAttribute := range colorVariants.Result.SlicingAttributes {
for _, attribute := range slicingAttribute.Attributes {
for _, content := range attribute.Contents {
// Don't fetch primary product again.
if content.ID != primaryProductDetail.ID {
productVariantDetail, errGPD := GetProductDetails(strconv.Itoa(content.ID))
if errGPD == nil {
productVariantJSON := CreateJSONFromModel(productVariantDetail)
if productVariantJSON != nil {
colorVariantsJson = append(colorVariantsJson, productVariantJSON)
}
}
}
}
}
// Color variant count
if len(slicingAttribute.Attributes) > 0 {
productDetailJSON["color_variant_count"] = len(slicingAttribute.Attributes)
productDetailJSON["color_variants"] = colorVariantsJson
}
}
}
jsonString, _ := json.Marshal(productDetailJSON)
// convert json to struct
converted := models.Product{}
json.Unmarshal(jsonString, &converted)
return converted, nil
}
// getProductColorVariants returns color options of product
func GetProductColorVariants(productGroupId int) (models.TrendyolProductVariantsResponse, error) {
url := "https://public.trendyol.com/discovery-web-productgw-service/api/productGroup/" + strconv.Itoa(productGroupId) + "?storefrontId=1&culture=tr-TR"
var response models.TrendyolProductVariantsResponse
body, err := helper.SendRequest("GET", url, nil, "")
if err != nil {
return response, err
}
err = json.Unmarshal(body, &response)
if err != nil {
helper.Error(err)
return response, err
}
return response, nil
}
// createJSONFromModel creates json from [trendyol.TrendyolProductDetailModel] and returns
func CreateJSONFromModel(model models.TrendyolProductDetailModel) map[string]interface{} {
json := map[string]interface{}{}
// get weight from categories (Stored in helper array (RAM))
weight := helper.GetCategoryWeight(model.Category.BeautifiedName)
productGroupId := strconv.Itoa(model.ProductGroupID)
json["_id"] = productGroupId
json["product_group_id"] = productGroupId
json["vendor"] = "trendyol"
json["sku"] = "p-" + strconv.Itoa(model.ID)
json["product_number"] = strconv.Itoa(model.ID)
json["product_code"] = model.ProductCode
json["name"] = model.Name
json["sellable"] = model.IsSellable
json["favorite_count"] = model.FavoriteCount
json["weight"] = weight
json["name_with_product_code"] = model.NameWithProductCode
json["url_key"] = "https://www.trendyol.com" + model.URL
json["images"] = model.Images
json["brand"] = model.Brand.Name
json["cinsiyet"] = model.Gender.Name
json["description"] = model.Description
json["descriptions"] = model.ContentDescriptions
json["short_description"] = model.Description
// nested structure
json["price"] = make(map[string]interface{})
json["price"].(map[string]interface{})["originalPrice"] = model.Price.OriginalPrice
json["price"].(map[string]interface{})["sellingPrice"] = model.Price.SellingPrice
json["price"].(map[string]interface{})["discountedPrice"] = model.Price.DiscountedPrice
attrLen := len(model.Attributes)
if attrLen != 0 {
for i := 0; i < attrLen; i++ {
attribute := model.Attributes[i]
if attribute.Key.Name == "Renk" {
json["color"] = attribute.Value.Name
}
}
}
// set categories with value 1
json["categories"] = []int{1}
attributes := make([]map[string]string, 0)
for _, attr := range model.Attributes {
var re = regexp.MustCompile(`/[^A-Z0-9]/ig`)
keyStr := re.ReplaceAllString(attr.Key.Name, `_`)
key := strings.ToLower(keyStr)
attribute := map[string]string{
key: attr.Value.Name,
}
attributes = append(attributes, attribute)
}
json["attributes"] = attributes
var variants []models.Variant
// if show variants, then it is configurable product.
if model.ShowVariants {
for i := 0; i < len(model.Variants); i++ {
variant := model.Variants[i]
if variant.Sellable {
stockType := reflect.TypeOf(variant.Stock)
if stockType == nil {
variants = append(variants, variant)
} else {
// scrape is via link parse
// we need to parse other variants
// convert stock to int
stock, ok := variant.Stock.(float64)
if ok {
if stock > 0 {
variants = append(variants, variant)
}
}
}
}
}
for i := 0; i < len(model.AlternativeVariants); i++ {
alternativeVariant := model.AlternativeVariants[i]
stockType := reflect.TypeOf(alternativeVariant.Stock)
if stockType == nil && len(variants) > 0 {
// get the first variant for attribute info
fv := variants[0]
variant := models.Variant{
AttributeID: fv.AttributeID,
AttributeName: fv.AttributeName,
AttributeType: fv.AttributeType,
AttributeValue: alternativeVariant.AttributeValue,
Price: alternativeVariant.Price,
}
variants = append(variants, variant)
}
}
json["size_variants"] = variants
}
if model.ShowVariants && len(variants) == 0 {
return nil
}
return json
}