GWM sync api changes

This commit is contained in:
Gowtham M 2026-04-02 14:10:45 +05:30
parent 92c962ab95
commit e175e986ce
25 changed files with 292 additions and 51 deletions

331
main.go
View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"crypto/rand" "crypto/rand"
"database/sql"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
@ -2047,6 +2048,139 @@ func main() {
}) })
// // ============================================
// // GET COUNTRY DETAILS (Country + Leaders + All Statistics)
// // ============================================
// e.Router.GET("/api/getCountryDetails", func(c echo.Context) error {
// countryCode := c.QueryParam("country_code")
// language := c.QueryParam("language")
// if countryCode == "" {
// return c.JSON(http.StatusBadRequest, map[string]string{"error": "country_code is required"})
// }
// // Get country
// country := struct {
// ID string `db:"id" json:"id"`
// CountryName string `db:"country_name" json:"country_name"`
// CountryCode string `db:"country_code" json:"country_code"`
// FlagUrl string `db:"flag_url" json:"flag_url"`
// }{}
// countryNameColumn := "country_name_" + language
// query := ` SELECT id,country_code,flag_url,` + countryNameColumn + ` AS country_name FROM countries WHERE country_code = {:country_code}`
// err := app.DB().
// NewQuery(query).
// Bind(dbx.Params{
// "country_code": countryCode,
// }).
// One(&country)
// if err != nil {
// log.Printf("Country not found: %v", err)
// return c.JSON(http.StatusNotFound, map[string]string{"error": "Country not found"})
// }
// // Get leaders
// leaders := []struct {
// ID string `db:"id" json:"id"`
// Name string `db:"name" json:"name"`
// Position string `db:"position" json:"position"`
// Photo string `db:"photo" json:"photo"`
// IsCurrent bool `db:"is_current" json:"is_current"`
// }{}
// nameColumn := "name_" + language
// positionColumn := "position_" + language
// query2 := `SELECT id,` + nameColumn + ` AS name,` + positionColumn + ` AS position,photo,is_current FROM leaders WHERE country = {:country} AND is_current = true ORDER BY position ASC `
// err = app.DB().
// NewQuery(query2).
// Bind(dbx.Params{
// "country": country.ID,
// }).
// All(&leaders)
// if err != nil {
// log.Printf("Failed to fetch leaders: %v", err)
// }
// // Get all statistics
// allStatistics := []struct {
// ID string `db:"id" json:"id"`
// Type string `db:"type" json:"type"`
// Topic string `db:"topic" json:"topic"`
// Value string `db:"value" json:"value"`
// Rank float64 `db:"rank" json:"rank"`
// IsRankPositive bool `db:"is_rank_positive" json:"is_rank_positive"`
// RankHeading string `db:"rank_heading" json:"rank_heading"`
// Icon string `db:"icon" json:"icon"`
// IconURL string `db:"-" json:"icon_url"`
// }{}
// topicColumn := "topic_" + language
// valueColumn := "value_" + language
// rankHeadingColumn := "rank_heading_" + language
// query3 := `SELECT id,type,` + topicColumn + ` AS topic,` + valueColumn + ` AS value,` + rankHeadingColumn + ` AS rank_heading,rank,is_rank_positive,icon FROM country_statistics WHERE country = {:country} ORDER BY type ASC, rank ASC`
// err = app.DB().
// NewQuery(query3).
// Bind(dbx.Params{
// "country": country.ID,
// }).
// All(&allStatistics)
// if err != nil {
// log.Printf("Failed to fetch statistics: %v", err)
// }
// for i := range allStatistics {
// if allStatistics[i].Icon == "" {
// allStatistics[i].IconURL = ""
// continue
// }
// allStatistics[i].IconURL = fmt.Sprintf("%s/api/files/country_statistics/%s/%s",
// baseUrl,
// allStatistics[i].ID,
// allStatistics[i].Icon,
// )
// }
// // Group statistics by type
// statisticsMap := map[string]interface{}{
// "demography": []interface{}{},
// "gdp": []interface{}{},
// "fdi": []interface{}{},
// "trade": []interface{}{},
// "bilateral_trade": []interface{}{},
// }
// for _, stat := range allStatistics {
// // Remove quotes from type field if present
// cleanType := stat.Type
// if len(cleanType) > 2 && cleanType[0] == '"' && cleanType[len(cleanType)-1] == '"' {
// cleanType = cleanType[1 : len(cleanType)-1]
// }
// if _, exists := statisticsMap[cleanType]; exists {
// statisticsMap[cleanType] = append(statisticsMap[cleanType].([]interface{}), stat)
// }
// }
// // Build final response
// result := map[string]interface{}{
// "country": country,
// "leaders": leaders,
// "statistics": statisticsMap,
// }
// return c.JSON(http.StatusOK, result)
// })
// ============================================ // ============================================
// GET COUNTRY DETAILS (Country + Leaders + All Statistics) // GET COUNTRY DETAILS (Country + Leaders + All Statistics)
// ============================================ // ============================================
@ -2059,7 +2193,9 @@ func main() {
return c.JSON(http.StatusBadRequest, map[string]string{"error": "country_code is required"}) return c.JSON(http.StatusBadRequest, map[string]string{"error": "country_code is required"})
} }
// --------------------------------------------
// Get country // Get country
// --------------------------------------------
country := struct { country := struct {
ID string `db:"id" json:"id"` ID string `db:"id" json:"id"`
CountryName string `db:"country_name" json:"country_name"` CountryName string `db:"country_name" json:"country_name"`
@ -2068,7 +2204,13 @@ func main() {
}{} }{}
countryNameColumn := "country_name_" + language countryNameColumn := "country_name_" + language
query := ` SELECT id,country_code,flag_url,` + countryNameColumn + ` AS country_name FROM countries WHERE country_code = {:country_code}`
query := `
SELECT id, country_code, flag_url, ` + countryNameColumn + ` AS country_name
FROM countries
WHERE country_code = {:country_code}
`
err := app.DB(). err := app.DB().
NewQuery(query). NewQuery(query).
Bind(dbx.Params{ Bind(dbx.Params{
@ -2081,7 +2223,9 @@ func main() {
return c.JSON(http.StatusNotFound, map[string]string{"error": "Country not found"}) return c.JSON(http.StatusNotFound, map[string]string{"error": "Country not found"})
} }
// --------------------------------------------
// Get leaders // Get leaders
// --------------------------------------------
leaders := []struct { leaders := []struct {
ID string `db:"id" json:"id"` ID string `db:"id" json:"id"`
Name string `db:"name" json:"name"` Name string `db:"name" json:"name"`
@ -2093,7 +2237,17 @@ func main() {
nameColumn := "name_" + language nameColumn := "name_" + language
positionColumn := "position_" + language positionColumn := "position_" + language
query2 := `SELECT id,` + nameColumn + ` AS name,` + positionColumn + ` AS position,photo,is_current FROM leaders WHERE country = {:country} AND is_current = true ORDER BY position ASC ` query2 := `
SELECT id,
` + nameColumn + ` AS name,
` + positionColumn + ` AS position,
photo,
is_current
FROM leaders
WHERE country = {:country}
AND is_current = true
ORDER BY position ASC
`
err = app.DB(). err = app.DB().
NewQuery(query2). NewQuery(query2).
@ -2106,24 +2260,46 @@ func main() {
log.Printf("Failed to fetch leaders: %v", err) log.Printf("Failed to fetch leaders: %v", err)
} }
// Get all statistics // -----------------------------------
allStatistics := []struct { // STATISTICS
ID string `db:"id" json:"id"` // -----------------------------------
Type string `db:"type" json:"type"`
Topic string `db:"topic" json:"topic"`
Value string `db:"value" json:"value"`
Rank float64 `db:"rank" json:"rank"`
IsRankPositive bool `db:"is_rank_positive" json:"is_rank_positive"`
RankHeading string `db:"rank_heading" json:"rank_heading"`
Icon string `db:"icon" json:"icon"`
IconURL string `db:"-" json:"icon_url"`
}{}
topicColumn := "topic_" + language type Stat struct {
valueColumn := "value_" + language ID string `db:"id" json:"id"`
rankHeadingColumn := "rank_heading_" + language Type string `db:"type" json:"type"`
Topic string `db:"topic" json:"topic"`
Value string `db:"value" json:"value"`
Rank float64 `db:"rank" json:"rank"`
IsRankPositive bool `db:"is_rank_positive" json:"is_rank_positive"`
RankHeading string `db:"rank_heading" json:"rank_heading"`
IconRecordID sql.NullString `db:"icon_record_id"`
IconFile sql.NullString `db:"icon_file"`
IconURL string `json:"icon_url"`
}
query3 := `SELECT id,type,` + topicColumn + ` AS topic,` + valueColumn + ` AS value,` + rankHeadingColumn + ` AS rank_heading,rank,is_rank_positive,icon FROM country_statistics WHERE country = {:country} ORDER BY type ASC, rank ASC` allStatistics := []Stat{}
topicColumn := "cs.topic_" + language
valueColumn := "cs.value_" + language
rankHeadingColumn := "cs.rank_heading_" + language
query3 := `
SELECT
cs.id,
cs.type,
` + topicColumn + ` AS topic,
` + valueColumn + ` AS value,
` + rankHeadingColumn + ` AS rank_heading,
cs.rank,
cs.is_rank_positive,
iconRec.id AS icon_record_id,
iconRec.icon AS icon_file
FROM country_statistics cs
LEFT JOIN country_statistics_icons iconRec
ON iconRec.key = cs.topic_en
WHERE cs.country = {:country}
ORDER BY cs.type ASC, cs.rank ASC
`
err = app.DB(). err = app.DB().
NewQuery(query3). NewQuery(query3).
@ -2136,20 +2312,28 @@ func main() {
log.Printf("Failed to fetch statistics: %v", err) log.Printf("Failed to fetch statistics: %v", err)
} }
// -----------------------------------
// ICON URL BUILD
// -----------------------------------
for i := range allStatistics { for i := range allStatistics {
if allStatistics[i].Icon == "" {
allStatistics[i].IconURL = ""
continue
}
allStatistics[i].IconURL = fmt.Sprintf("%s/api/files/country_statistics/%s/%s", if allStatistics[i].IconFile.Valid {
baseUrl,
allStatistics[i].ID, allStatistics[i].IconURL = fmt.Sprintf(
allStatistics[i].Icon, "%s/api/files/country_statistics_icons/%s/%s",
) baseUrl,
allStatistics[i].IconRecordID.String,
allStatistics[i].IconFile.String,
)
} else {
allStatistics[i].IconURL = ""
}
} }
// Group statistics by type // -----------------------------------
// GROUP STATISTICS
// -----------------------------------
statisticsMap := map[string]interface{}{ statisticsMap := map[string]interface{}{
"demography": []interface{}{}, "demography": []interface{}{},
"gdp": []interface{}{}, "gdp": []interface{}{},
@ -2159,8 +2343,9 @@ func main() {
} }
for _, stat := range allStatistics { for _, stat := range allStatistics {
// Remove quotes from type field if present
cleanType := stat.Type cleanType := stat.Type
if len(cleanType) > 2 && cleanType[0] == '"' && cleanType[len(cleanType)-1] == '"' { if len(cleanType) > 2 && cleanType[0] == '"' && cleanType[len(cleanType)-1] == '"' {
cleanType = cleanType[1 : len(cleanType)-1] cleanType = cleanType[1 : len(cleanType)-1]
} }
@ -2170,7 +2355,9 @@ func main() {
} }
} }
// Build final response // -----------------------------------
// FINAL RESPONSE
// -----------------------------------
result := map[string]interface{}{ result := map[string]interface{}{
"country": country, "country": country,
"leaders": leaders, "leaders": leaders,
@ -2202,7 +2389,7 @@ func main() {
}{} }{}
countryNameColumn := "country_name_" + language countryNameColumn := "country_name_" + language
query := ` SELECT id,country_code,flag_url,logo,` + countryNameColumn + ` AS country_name FROM countries WHERE country_code = {:country_code}` query := ` SELECT id,country_code,flag_url,` + countryNameColumn + ` AS country_name FROM countries WHERE country_code = {:country_code}`
err := app.DB(). err := app.DB().
NewQuery(query). NewQuery(query).
Bind(dbx.Params{ Bind(dbx.Params{
@ -2247,20 +2434,66 @@ func main() {
}) })
} }
for i := range allBilateralTradeData { groupedData := map[string][]map[string]interface{}{
if allBilateralTradeData[i].Icon == "" { "Import": {},
allBilateralTradeData[i].IconURL = "" "Export": {},
continue "Reexport": {},
}
allBilateralTradeData[i].IconURL = fmt.Sprintf("%s/api/files/bilateral_trade_data/%s/%s",
baseUrl,
allBilateralTradeData[i].ID,
allBilateralTradeData[i].Icon,
)
} }
return c.JSON(http.StatusOK, allBilateralTradeData) for _, item := range allBilateralTradeData {
// Generate icon URL first
iconURL := ""
if item.Icon != "" {
iconURL = fmt.Sprintf("%s/api/files/bilateral_trade_data/%s/%s",
baseUrl,
item.ID,
item.Icon,
)
}
topic := item.Topic
category := ""
// English
if strings.HasPrefix(topic, "Imports - ") {
category = "Import"
topic = strings.TrimPrefix(topic, "Imports - ")
} else if strings.HasPrefix(topic, "Exports - ") {
category = "Export"
topic = strings.TrimPrefix(topic, "Exports - ")
} else if strings.HasPrefix(topic, "Re-exports - ") {
category = "Reexport"
topic = strings.TrimPrefix(topic, "Re-exports - ")
}
// Arabic
if strings.HasPrefix(topic, "الواردات - ") {
category = "Import"
topic = strings.TrimPrefix(topic, "الواردات - ")
} else if strings.HasPrefix(topic, "الصادرات - ") {
category = "Export"
topic = strings.TrimPrefix(topic, "الصادرات - ")
} else if strings.HasPrefix(topic, "إعادة التصدير - ") {
category = "Reexport"
topic = strings.TrimPrefix(topic, "إعادة التصدير - ")
}
data := map[string]interface{}{
"id": item.ID,
"topic": topic,
"value": item.Value,
"icon": item.Icon,
"icon_url": iconURL,
}
if category != "" {
groupedData[category] = append(groupedData[category], data)
}
}
return c.JSON(http.StatusOK, groupedData)
}) })
// ============================================ // ============================================
@ -2516,7 +2749,7 @@ func main() {
} }
data, _ := json.Marshal(loginPayload) data, _ := json.Marshal(loginPayload)
loginReq, _ := http.NewRequest("POST", fmt.Sprintf("%s/api/admins/auth-with-password", "http://127.0.0.1:8090"), bytes.NewBuffer(data)) loginReq, _ := http.NewRequest("POST", fmt.Sprintf("%s/api/admins/auth-with-password", "https://pb.venbait.in"), bytes.NewBuffer(data))
loginReq.Header.Set("Content-Type", "application/json") loginReq.Header.Set("Content-Type", "application/json")
loginResp, err := http.DefaultClient.Do(loginReq) loginResp, err := http.DefaultClient.Do(loginReq)
@ -2537,7 +2770,7 @@ func main() {
} }
// 2⃣ Use token to fetch records // 2⃣ Use token to fetch records
url := fmt.Sprintf("%s/api/collections/%s/records?perPage=500", "http://127.0.0.1:8090", reqBody.Collection) url := fmt.Sprintf("%s/api/collections/%s/records?perPage=500", "https://pb.venbait.in", reqBody.Collection)
fmt.Println("Fetching collection from URL:", url) fmt.Println("Fetching collection from URL:", url)
req, _ := http.NewRequest("GET", url, nil) req, _ := http.NewRequest("GET", url, nil)
@ -2586,10 +2819,10 @@ func main() {
"password": reqBody.LivePassword, "password": reqBody.LivePassword,
} }
data, _ := json.Marshal(livePayload) data, _ := json.Marshal(livePayload)
liveReq, _ := http.NewRequest("POST", fmt.Sprintf("%s/api/admins/auth-with-password", "https://pb.venbait.in"), bytes.NewBuffer(data)) liveReq, _ := http.NewRequest("POST", fmt.Sprintf("%s/api/admins/auth-with-password", "https://pocket.fcsc.gov.ae"), bytes.NewBuffer(data))
liveReq.Header.Set("Content-Type", "application/json") liveReq.Header.Set("Content-Type", "application/json")
liveResp, err := http.DefaultClient.Do(liveReq) liveResp, err := http.DefaultClient.Do(liveReq)
fmt.Println("Live url:", "https://pb.venbait.in") fmt.Println("Live url:", "https://pocket.fcsc.gov.ae")
fmt.Println("Live req:", liveReq) fmt.Println("Live req:", liveReq)
if err != nil { if err != nil {
return c.JSON(500, map[string]string{"error": "failed to connect to Live PB"}) return c.JSON(500, map[string]string{"error": "failed to connect to Live PB"})
@ -2612,7 +2845,7 @@ func main() {
data, _ := json.Marshal(rec) data, _ := json.Marshal(rec)
// Try PATCH first // Try PATCH first
patchURL := fmt.Sprintf("%s/api/collections/%s/records/%s", "https://pb.venbait.in", reqBody.Collection, id) patchURL := fmt.Sprintf("%s/api/collections/%s/records/%s", "https://pocket.fcsc.gov.ae", reqBody.Collection, id)
req, _ := http.NewRequest("PATCH", patchURL, bytes.NewBuffer(data)) req, _ := http.NewRequest("PATCH", patchURL, bytes.NewBuffer(data))
req.Header.Set("Authorization", liveLogin.Token) req.Header.Set("Authorization", liveLogin.Token)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
@ -2626,7 +2859,7 @@ func main() {
if resp.StatusCode == 404 { if resp.StatusCode == 404 {
// Create instead // Create instead
postURL := fmt.Sprintf("%s/api/collections/%s/records", "https://pb.venbait.in", reqBody.Collection) postURL := fmt.Sprintf("%s/api/collections/%s/records", "https://pocket.fcsc.gov.ae", reqBody.Collection)
req, _ := http.NewRequest("POST", postURL, bytes.NewBuffer(data)) req, _ := http.NewRequest("POST", postURL, bytes.NewBuffer(data))
req.Header.Set("Authorization", liveLogin.Token) req.Header.Set("Authorization", liveLogin.Token)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":{"original-filename":"Venba Infotech.png"},"md5":"P55jVi+THe+NP1tG4KgsSw=="} {"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":{"original-filename":"IMD.png"},"md5":"8bGx6LhXqxPbgVjRi2Mdgw=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -1 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null,"md5":"EQ0c1eYViGoivgx7b8rwQw=="} {"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null,"md5":"y/a73YxDdhHm9l0Kw6Pi1Q=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":{"original-filename":"IMD.png"},"md5":"8bGx6LhXqxPbgVjRi2Mdgw=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null,"md5":"y/a73YxDdhHm9l0Kw6Pi1Q=="}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":{"original-filename":"Open Data.png"},"md5":"zqS1mfeZDSDnS4lCDYYVFA=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null,"md5":"BoezhRm3qH1p+B0LKtT2MQ=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":{"original-filename":"IMD.png"},"md5":"8bGx6LhXqxPbgVjRi2Mdgw=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null,"md5":"y/a73YxDdhHm9l0Kw6Pi1Q=="}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":{"original-filename":"in.png"},"md5":"biCuWZ+aLfgvhXZm7kBlwg=="}

View File

@ -0,0 +1 @@
{"user.cache_control":"","user.content_disposition":"","user.content_encoding":"","user.content_language":"","user.content_type":"image/png","user.metadata":null,"md5":"2pTxEA7Pl1AULa1DB1HfqQ=="}