summaryrefslogtreecommitdiff
path: root/cmd/importer/import.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/importer/import.go')
-rw-r--r--cmd/importer/import.go182
1 files changed, 182 insertions, 0 deletions
diff --git a/cmd/importer/import.go b/cmd/importer/import.go
new file mode 100644
index 0000000..f08117d
--- /dev/null
+++ b/cmd/importer/import.go
@@ -0,0 +1,182 @@
+package importer
+
+import (
+ "context"
+ "crypto/sha256"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/json"
+ "errors"
+ "io"
+ "net/http"
+ "os"
+ "path/filepath"
+ "strings"
+ "unicode/utf16"
+
+ "git.neonxp.ru/neonxp/guessr/pkg/config"
+ "git.neonxp.ru/neonxp/guessr/pkg/db"
+ "git.neonxp.ru/neonxp/guessr/pkg/model"
+ "github.com/urfave/cli/v3"
+)
+
+var Command = &cli.Command{
+ Name: "import",
+ Usage: "import json with places",
+ Flags: []cli.Flag{
+ &cli.BoolFlag{
+ Name: "download-img",
+ Usage: "download images locally",
+ },
+ },
+ ArgsUsage: "path to json file",
+ Action: func(ctx context.Context, c *cli.Command) error {
+ downloadImg := c.Bool("download-img")
+
+ cfg, err := config.New()
+ if err != nil {
+ return err
+ }
+
+ dbClient := db.New(cfg.DB)
+
+ fp, err := os.Open(c.Args().First())
+ if err != nil {
+ return err
+ }
+ defer fp.Close()
+
+ places := Places{}
+ dec := json.NewDecoder(fp)
+
+ if err := dec.Decode(&places); err != nil {
+ return err
+ }
+
+ for _, p := range places {
+ decodedValue := unescape(p.Name)
+ h := hash(p.Img)
+ prefix := h[0:1]
+ path := filepath.Join(".", "static", "places", prefix)
+
+ file := filepath.Join(path, h+".jpg")
+
+ if downloadImg {
+ //nolint:gomnd
+ if err := os.MkdirAll(path, 0o777); err != nil {
+ return err
+ }
+
+ if err := downloadFile(p.Img, file); err != nil {
+ return err
+ }
+ }
+
+ np := model.Place{
+ GUID: p.GUID,
+ Img: strings.Replace(file, "static", "", 1),
+ Name: strings.ReplaceAll(decodedValue, "�", `"`),
+ Position: &model.Point{
+ Lat: p.Position.Lat,
+ Lon: p.Position.Lng,
+ },
+ }
+
+ if _, err := dbClient.NewInsert().Model(&np).Exec(ctx); err != nil {
+ return err
+ }
+ }
+
+ return nil
+ },
+}
+
+type Place struct {
+ GUID string `json:"guid"`
+ Position PositionEntity `json:"position"`
+ Img string `json:"img"`
+ Name string `json:"name"`
+}
+
+type PositionEntity struct {
+ Lat float64 `json:"lat"`
+ Lng float64 `json:"lng"`
+}
+
+type Places []Place
+
+func hash(in string) string {
+ hasher := sha256.New()
+ if _, err := hasher.Write([]byte(in)); err != nil {
+ return ""
+ }
+
+ return base64.URLEncoding.EncodeToString(hasher.Sum(nil))
+}
+
+func unescape(input string) string {
+ output := make([]rune, 0, len(input))
+ length := len(input)
+
+ for index := 0; index < length; {
+ //nolint:nestif
+ if input[index] == '%' {
+ if index <= length-6 && input[index+1] == 'u' {
+ byte16, err := hex.DecodeString(input[index+2 : index+6])
+ if err == nil {
+ //nolint:gomnd
+ value := uint16(byte16[0])<<8 + uint16(byte16[1])
+ chr := utf16.Decode([]uint16{value})[0]
+ output = append(output, chr)
+ index += 6
+
+ continue
+ }
+ }
+
+ if index <= length-3 {
+ byte8, err := hex.DecodeString(input[index+1 : index+3])
+ if err == nil {
+ value := uint16(byte8[0])
+ chr := utf16.Decode([]uint16{value})[0]
+ output = append(output, chr)
+ index += 3
+
+ continue
+ }
+ }
+ }
+
+ output = append(output, rune(input[index]))
+ index++
+ }
+
+ return string(output)
+}
+
+func downloadFile(fileURL, fileName string) error {
+ //nolint:gosec,noctx
+ response, err := http.Get(fileURL)
+ if err != nil {
+ return err
+ }
+ defer response.Body.Close()
+
+ if response.StatusCode != http.StatusOK {
+ return errors.New("received non 200 response code")
+ }
+ // Create a empty file
+ file, err := os.Create(fileName)
+ if err != nil {
+ return err
+ }
+ defer file.Close()
+
+ // Write the bytes to the fiel
+ _, err = io.Copy(file, response.Body)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}