Skip to content

Commit

Permalink
feat: auto lookup images for extension images sync, fixes shopware#317
Browse files Browse the repository at this point in the history
  • Loading branch information
shyim committed Mar 24, 2024
1 parent b5bd280 commit 7768a0c
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 44 deletions.
103 changes: 82 additions & 21 deletions cmd/account/account_producer_extension_info_pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import (
"io"
"net/http"
"os"
"path"
"path/filepath"
"strings"

"github.com/spf13/cobra"
"gopkg.in/yaml.v3"

account_api "github.com/FriendsOfShopware/shopware-cli/account-api"
"github.com/FriendsOfShopware/shopware-cli/extension"
"github.com/FriendsOfShopware/shopware-cli/logging"
)
Expand All @@ -21,12 +23,12 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
Short: "Generates local store configuration from account data",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
path, err := filepath.Abs(args[0])
absolutePath, err := filepath.Abs(args[0])
if err != nil {
return fmt.Errorf("cannot open file: %w", err)
}

zipExt, err := extension.GetExtensionByFolder(path)
zipExt, err := extension.GetExtensionByFolder(absolutePath)
if err != nil {
return fmt.Errorf("cannot open extension: %w", err)
}
Expand All @@ -46,7 +48,7 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
return fmt.Errorf("cannot get store extension: %w", err)
}

resourcesFolder := fmt.Sprintf("%s/src/Resources/store/", zipExt.GetPath())
resourcesFolder := path.Join(zipExt.GetPath(), "src/Resources/store/")
categoryList := make([]string, 0)
availabilities := make([]string, 0)
localizations := make([]string, 0)
Expand All @@ -60,7 +62,6 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
featuresEN := make([]string, 0)
faqDE := make([]extension.ConfigStoreFaq, 0)
faqEN := make([]extension.ConfigStoreFaq, 0)
images := make([]extension.ConfigStoreImage, 0)

if _, err := os.Stat(resourcesFolder); os.IsNotExist(err) {
err = os.MkdirAll(resourcesFolder, os.ModePerm)
Expand All @@ -75,7 +76,7 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
if len(storeExt.IconURL) > 0 {
icon := "src/Resources/store/icon.png"
iconConfigPath = &icon
err := downloadFileTo(cmd.Context(), storeExt.IconURL, fmt.Sprintf("%s/icon.png", resourcesFolder))
err := downloadFileTo(cmd.Context(), storeExt.IconURL, path.Join(resourcesFolder, "icon.png"))
if err != nil {
return fmt.Errorf("cannot download file: %w", err)
}
Expand Down Expand Up @@ -103,19 +104,16 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
return fmt.Errorf("cannot get extension images: %w", err)
}

for i, image := range storeImages {
imagePath := fmt.Sprintf("src/Resources/store/img-%d.png", i)
err := downloadFileTo(cmd.Context(), image.RemoteLink, fmt.Sprintf("%s/%s", zipExt.GetPath(), imagePath))
if err != nil {
return fmt.Errorf("cannot download file: %w", err)
if len(storeImages) > 0 {
imagesDir := path.Join(zipExt.GetPath(), "src/Resources/store/images/")

if err := writeImages(cmd.Context(), imagesDir, 0, storeImages); err != nil {
return fmt.Errorf("cannot write images: %w", err)
}

images = append(images, extension.ConfigStoreImage{
File: imagePath,
Preview: extension.ConfigStoreImagePreview{German: image.Details[0].Preview, English: image.Details[1].Preview},
Activate: extension.ConfigStoreImageActivate{German: image.Details[0].Activated, English: image.Details[1].Activated},
Priority: image.Priority,
})
if err := writeImages(cmd.Context(), imagesDir, 1, storeImages); err != nil {
return fmt.Errorf("cannot write images: %w", err)
}
}

germanDescription := ""
Expand All @@ -127,8 +125,16 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
language := info.Locale.Name[0:2]

if language == "de" {
germanDescription = info.Description
germanInstallationManual = info.InstallationManual
germanDescription = "file:src/Resources/store/description.de.html"
germanInstallationManual = "file:src/Resources/store/installation_manual.de.html"

if err := os.WriteFile(path.Join(zipExt.GetPath(), germanDescription[5:]), []byte(info.Description), os.ModePerm); err != nil {
return fmt.Errorf("cannot write file: %w", err)
}

if err := os.WriteFile(path.Join(zipExt.GetPath(), germanInstallationManual[5:]), []byte(info.InstallationManual), os.ModePerm); err != nil {
return fmt.Errorf("cannot write file: %w", err)
}

for _, element := range info.Tags {
tagsDE = append(tagsDE, element.Name)
Expand All @@ -149,8 +155,16 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
faqDE = append(faqDE, extension.ConfigStoreFaq{Question: element.Question, Answer: element.Answer})
}
} else {
englishDescription = info.Description
englishInstallationManual = info.InstallationManual
englishDescription = "file:src/Resources/store/description.en.html"
englishInstallationManual = "file:src/Resources/store/installation_manual.en.html"

if err := os.WriteFile(path.Join(zipExt.GetPath(), englishDescription[5:]), []byte(info.Description), os.ModePerm); err != nil {
return fmt.Errorf("cannot write file: %w", err)
}

if err := os.WriteFile(path.Join(zipExt.GetPath(), englishInstallationManual[5:]), []byte(info.InstallationManual), os.ModePerm); err != nil {
return fmt.Errorf("cannot write file: %w", err)
}

for _, element := range info.Tags {
tagsEN = append(tagsEN, element.Name)
Expand Down Expand Up @@ -196,7 +210,12 @@ var accountCompanyProducerExtensionInfoPullCmd = &cobra.Command{
newCfg.Store.Highlights = extension.ConfigTranslated[[]string]{German: &highlightsDE, English: &highlightsEN}
newCfg.Store.Features = extension.ConfigTranslated[[]string]{German: &featuresDE, English: &featuresEN}
newCfg.Store.Faq = extension.ConfigTranslated[[]extension.ConfigStoreFaq]{German: &faqDE, English: &faqEN}
newCfg.Store.Images = &images
newCfg.Store.Images = nil

if len(storeImages) > 0 {
imageDir := "src/Resources/store/images"
newCfg.Store.ImageDirectory = &imageDir
}

content, err := yaml.Marshal(newCfg)
if err != nil {
Expand Down Expand Up @@ -249,3 +268,45 @@ func downloadFileTo(ctx context.Context, url string, target string) error {

return nil
}

func writeImages(ctx context.Context, imagePath string, index int, storeImages []*account_api.ExtensionImage) error {
imageMap := make(map[int]string)

for _, image := range storeImages {
if image.Details[index].Activated {
priority := image.Priority

if _, ok := imageMap[priority]; !ok {
imageMap[priority] = image.RemoteLink
} else {
for {
priority++
if _, ok := imageMap[priority]; !ok {
imageMap[priority] = image.RemoteLink
break
}
}
}
}
}

if index == 0 {
imagePath = path.Join(imagePath, "de")
} else {
imagePath = path.Join(imagePath, "en")
}

if _, err := os.Stat(imagePath); os.IsNotExist(err) {
if err := os.MkdirAll(imagePath, os.ModePerm); err != nil {
return err
}
}

for priority, link := range imageMap {
if err := downloadFileTo(ctx, link, path.Join(imagePath, fmt.Sprintf("%d.png", priority))); err != nil {
return err
}
}

return nil
}
118 changes: 96 additions & 22 deletions cmd/account/account_producer_extension_info_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package account

import (
"bytes"
"context"
"fmt"
"os"
"path"
"path/filepath"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand All @@ -19,22 +22,22 @@ var accountCompanyProducerExtensionInfoPushCmd = &cobra.Command{
Short: "Update store information of extension",
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
path, err := filepath.Abs(args[0])
absolutePath, err := filepath.Abs(args[0])
if err != nil {
return fmt.Errorf("cannot open file: %w", err)
}

stat, err := os.Stat(path)
stat, err := os.Stat(absolutePath)
if err != nil {
return fmt.Errorf("cannot open file: %w", err)
}

var zipExt extension.Extension

if stat.IsDir() {
zipExt, err = extension.GetExtensionByFolder(path)
zipExt, err = extension.GetExtensionByFolder(absolutePath)
} else {
zipExt, err = extension.GetExtensionByZip(path)
zipExt, err = extension.GetExtensionByZip(absolutePath)
}

if err != nil {
Expand Down Expand Up @@ -85,7 +88,7 @@ var accountCompanyProducerExtensionInfoPushCmd = &cobra.Command{
}
}

if extCfg.Store.Images != nil {
if extCfg.Store.Images != nil || extCfg.Store.ImageDirectory != nil {
images, err := p.GetExtensionImages(cmd.Context(), storeExt.Id)
if err != nil {
return fmt.Errorf("cannot get images from remote server: %w", err)
Expand All @@ -98,23 +101,34 @@ var accountCompanyProducerExtensionInfoPushCmd = &cobra.Command{
}
}

for _, configImage := range *extCfg.Store.Images {
apiImage, err := p.AddExtensionImage(cmd.Context(), storeExt.Id, fmt.Sprintf("%s/%s", zipExt.GetPath(), configImage.File))
if err != nil {
return fmt.Errorf("cannot upload image %s to extension: %w", configImage.File, err)
if extCfg.Store.ImageDirectory != nil {
if err := uploadImagesByDirectory(cmd.Context(), storeExt.Id, path.Join(zipExt.GetPath(), *extCfg.Store.ImageDirectory), 0, p); err != nil {
return err
}

apiImage.Priority = configImage.Priority
apiImage.Details[0].Activated = configImage.Activate.German
apiImage.Details[0].Preview = configImage.Preview.German

apiImage.Details[1].Activated = configImage.Activate.English
apiImage.Details[1].Preview = configImage.Preview.English

err = p.UpdateExtensionImage(cmd.Context(), storeExt.Id, apiImage)

if err != nil {
return fmt.Errorf("cannot update image information of extension: %w", err)
if err := uploadImagesByDirectory(cmd.Context(), storeExt.Id, path.Join(zipExt.GetPath(), *extCfg.Store.ImageDirectory), 1, p); err != nil {
return err
}
} else {
// manually specified images
for _, configImage := range *extCfg.Store.Images {
apiImage, err := p.AddExtensionImage(cmd.Context(), storeExt.Id, fmt.Sprintf("%s/%s", zipExt.GetPath(), configImage.File))
if err != nil {
return fmt.Errorf("cannot upload image %s to extension: %w", configImage.File, err)
}

apiImage.Priority = configImage.Priority
apiImage.Details[0].Activated = configImage.Activate.German
apiImage.Details[0].Preview = configImage.Preview.German

apiImage.Details[1].Activated = configImage.Activate.English
apiImage.Details[1].Preview = configImage.Preview.English

err = p.UpdateExtensionImage(cmd.Context(), storeExt.Id, apiImage)

if err != nil {
return fmt.Errorf("cannot update image information of extension: %w", err)
}
}
}
}
Expand Down Expand Up @@ -287,7 +301,7 @@ func parseInlineablePath(path, extensionDir string) (string, error) {

content, err := os.ReadFile(filePath)
if err != nil {
return "", fmt.Errorf("Error reading file at path %s with error: %v", filePath, err)
return "", fmt.Errorf("error reading file at path %s with error: %v", filePath, err)
}

if filepath.Ext(filePath) != ".md" {
Expand All @@ -300,8 +314,68 @@ func parseInlineablePath(path, extensionDir string) (string, error) {
err = md.Convert(content, &buf)

if err != nil {
return "", fmt.Errorf("Cannot convert file at path %s from markdown to html with error: %v", filePath, err)
return "", fmt.Errorf("cannot convert file at path %s from markdown to html with error: %v", filePath, err)
}

return buf.String(), nil
}

func uploadImagesByDirectory(ctx context.Context, extensionId int, directory string, index int, p *accountApi.ProducerEndpoint) error {
// index 0 is for german, 1 for english defined by account api
if index == 0 {
directory = path.Join(directory, "de")
} else {
directory = path.Join(directory, "en")
}

images, err := os.ReadDir(directory)

// When folder does not exists, skip
if err != nil {
return nil //nolint:nilerr
}

imagesLen := len(images) - 1

for i, image := range images {
if image.IsDir() {
continue
}

fileName := image.Name()
fileName = strings.TrimSuffix(fileName, filepath.Ext(fileName))

apiImage, err := p.AddExtensionImage(ctx, extensionId, path.Join(directory, image.Name()))

if err != nil {
return fmt.Errorf("cannot upload image %s to extension: %w", image.Name(), err)
}

priority, err := strconv.Atoi(fileName)

if err != nil {
logging.FromContext(ctx).Warnf("Invalid image name %s, skipping", image.Name())
continue
}

apiImage.Priority = priority
apiImage.Details[0].Activated = false
apiImage.Details[0].Preview = false
apiImage.Details[1].Activated = false
apiImage.Details[1].Preview = false

if index == 0 {
apiImage.Details[0].Activated = true
apiImage.Details[0].Preview = imagesLen-i == 0
} else {
apiImage.Details[1].Activated = true
apiImage.Details[1].Preview = imagesLen-i == 0
}

if err := p.UpdateExtensionImage(ctx, extensionId, apiImage); err != nil {
return fmt.Errorf("cannot update image information of extension: %w", err)
}
}

return nil
}
3 changes: 2 additions & 1 deletion extension/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ type ConfigStore struct {
Highlights ConfigTranslated[[]string] `yaml:"highlights"`
Features ConfigTranslated[[]string] `yaml:"features"`
Faq ConfigTranslated[[]ConfigStoreFaq] `yaml:"faq"`
Images *[]ConfigStoreImage `yaml:"images"`
Images *[]ConfigStoreImage `yaml:"images,omitempty"`
ImageDirectory *string `yaml:"image_directory,omitempty"`
}

type Translatable interface {
Expand Down
4 changes: 4 additions & 0 deletions extension/shopware-extension-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,10 @@
}
}
},
"image_directory": {
"type": "string",
"description": "Specifies the directory where the images are located."
},
"images": {
"type": "array",
"description": "Specifies images for the extension in the store.",
Expand Down

0 comments on commit 7768a0c

Please sign in to comment.