Cloudinary_Cloudinary - Version 2.7.0

Version Notes

Release 2.7.0 notes:
- Support free transform chained transformations
- Set format and quality defaults to auto

Download this release

Release Info

Developer Cloudinary
Extension Cloudinary_Cloudinary
Version 2.7.0
Comparing to
See all releases


Code changes from version 2.6.0 to 2.7.0

app/code/community/Cloudinary/Cloudinary/Helper/Config.php ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudinary_Cloudinary_Helper_Config extends Mage_Core_Helper_Abstract
4
+ {
5
+ /**
6
+ * @param string $key
7
+ * @param array $value
8
+ * @return array
9
+ */
10
+ public function flatten($key, $value)
11
+ {
12
+ $output = [];
13
+
14
+ $this->doFlatten($key, $value, $output);
15
+
16
+ return $output;
17
+ }
18
+
19
+ /**
20
+ * @param string $key
21
+ * @param array|string $value
22
+ * @param array $output
23
+ */
24
+ private function doFlatten($key, $value, array &$output)
25
+ {
26
+ if (is_array($value)) {
27
+ foreach ($value as $childKey => $childValue) {
28
+ $this->doFlatten(sprintf('%s/%s', $key, $childKey), $childValue, $output);
29
+ }
30
+ } else {
31
+ $output[substr($key, 0, -6)] = $value;
32
+ }
33
+ }
34
+ }
app/code/community/Cloudinary/Cloudinary/Model/Cms/Uploader.php CHANGED
@@ -5,6 +5,8 @@ use CloudinaryExtension\Image;
5
 
6
  class Cloudinary_Cloudinary_Model_Cms_Uploader extends Mage_Core_Model_File_Uploader
7
  {
 
 
8
  protected function _afterSave($result)
9
  {
10
  parent::_afterSave($result);
@@ -20,6 +22,8 @@ class Cloudinary_Cloudinary_Model_Cms_Uploader extends Mage_Core_Model_File_Uplo
20
  $image = Image::fromPath($fullPath, $relativePath);
21
  $imageProvider->upload($image);
22
 
 
 
23
  $this->_trackSynchronisation((string)$image);
24
  }
25
 
5
 
6
  class Cloudinary_Cloudinary_Model_Cms_Uploader extends Mage_Core_Model_File_Uploader
7
  {
8
+ const UPLOAD_MESSAGE = 'Uploaded cms image: %s';
9
+
10
  protected function _afterSave($result)
11
  {
12
  parent::_afterSave($result);
22
  $image = Image::fromPath($fullPath, $relativePath);
23
  $imageProvider->upload($image);
24
 
25
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(sprintf(self::UPLOAD_MESSAGE, $relativePath));
26
+
27
  $this->_trackSynchronisation((string)$image);
28
  }
29
 
app/code/community/Cloudinary/Cloudinary/Model/Image.php CHANGED
@@ -6,6 +6,8 @@ use Cloudinary_Cloudinary_Model_Exception_BadFilePathException as BadFilePathExc
6
 
7
  class Cloudinary_Cloudinary_Model_Image extends Mage_Core_Model_Abstract
8
  {
 
 
9
  /**
10
  * @param array $imageDetails
11
  */
@@ -19,6 +21,8 @@ class Cloudinary_Cloudinary_Model_Image extends Mage_Core_Model_Abstract
19
 
20
  $imageProvider->upload(Image::fromPath($fullPath, $relativePath));
21
 
 
 
22
  Mage::getModel('cloudinary_cloudinary/synchronisation')
23
  ->setValueId($imageDetails['value_id'])
24
  ->setValue($imageDetails['file'])
6
 
7
  class Cloudinary_Cloudinary_Model_Image extends Mage_Core_Model_Abstract
8
  {
9
+ const UPLOAD_MESSAGE = 'uploaded product image to Cloudinary: %s';
10
+
11
  /**
12
  * @param array $imageDetails
13
  */
21
 
22
  $imageProvider->upload(Image::fromPath($fullPath, $relativePath));
23
 
24
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(sprintf(self::UPLOAD_MESSAGE, $relativePath));
25
+
26
  Mage::getModel('cloudinary_cloudinary/synchronisation')
27
  ->setValueId($imageDetails['value_id'])
28
  ->setValue($imageDetails['file'])
app/code/community/Cloudinary/Cloudinary/Model/Logger.php CHANGED
@@ -5,6 +5,7 @@ class Cloudinary_Cloudinary_Model_Logger extends Mage_Core_Model_Abstract implem
5
  const SIGNATURE_TEMPLATE = "%s::%s ";
6
  const ALPHANUM_REGEX = '/[^A-Za-z0-9]/';
7
  const IGNORE_GLOBAL_LOG_FLAG = true;
 
8
 
9
  /**
10
  * @param string $message
@@ -50,7 +51,12 @@ class Cloudinary_Cloudinary_Model_Logger extends Mage_Core_Model_Abstract implem
50
  private function log($message, $type)
51
  {
52
  if ($this->isActive()) {
53
- Mage::log($message, $type, $this->filename(), self::IGNORE_GLOBAL_LOG_FLAG);
 
 
 
 
 
54
  }
55
  }
56
 
5
  const SIGNATURE_TEMPLATE = "%s::%s ";
6
  const ALPHANUM_REGEX = '/[^A-Za-z0-9]/';
7
  const IGNORE_GLOBAL_LOG_FLAG = true;
8
+ const MESSAGE_FORMAT = 'Cloudinary: %s';
9
 
10
  /**
11
  * @param string $message
51
  private function log($message, $type)
52
  {
53
  if ($this->isActive()) {
54
+ Mage::log(
55
+ sprintf(self::MESSAGE_FORMAT, $message),
56
+ $type,
57
+ $this->filename(),
58
+ self::IGNORE_GLOBAL_LOG_FLAG
59
+ );
60
  }
61
  }
62
 
app/code/community/Cloudinary/Cloudinary/Model/Observer.php DELETED
@@ -1,154 +0,0 @@
1
- <?php
2
-
3
- use CloudinaryExtension\CloudinaryImageProvider;
4
- use CloudinaryExtension\CredentialValidator;
5
- use CloudinaryExtension\Image;
6
- use CloudinaryExtension\Security\CloudinaryEnvironmentVariable;
7
- use CloudinaryExtension\AutoUploadMapping\RequestProcessor;
8
- use CloudinaryExtension\AutoUploadMapping\ApiClient;
9
- use Mage_Adminhtml_Model_Config_Data as ConfigData;
10
- use Mage_Catalog_Model_Product as Product;
11
- use Varien_Event_Observer as EventObserver;
12
-
13
- class Cloudinary_Cloudinary_Model_Observer extends Mage_Core_Model_Abstract
14
- {
15
- const CLOUDINARY_CONFIG_SECTION = 'cloudinary';
16
- const ERROR_WRONG_CREDENTIALS = 'There was a problem validating your Cloudinary credentials.';
17
- const AUTO_UPLOAD_SETUP_FAIL_MESSAGE = 'Error. Unable to setup auto upload mapping.';
18
-
19
- /**
20
- * @param EventObserver $event
21
- *
22
- * @return EventObserver
23
- */
24
- public function loadCustomAutoloaders(EventObserver $event)
25
- {
26
- Mage::helper('cloudinary_cloudinary/autoloader')->register();
27
-
28
- return $event;
29
- }
30
-
31
- /**
32
- * @param EventObserver $event
33
- */
34
- public function uploadImagesToCloudinary(EventObserver $event)
35
- {
36
- if (Mage::getModel('cloudinary_cloudinary/configuration')->isEnabled()) {
37
- $cloudinaryImage = Mage::getModel('cloudinary_cloudinary/image');
38
-
39
- foreach ($this->getImagesToUpload($event->getProduct()) as $image) {
40
- $cloudinaryImage->upload($image);
41
- }
42
- }
43
- }
44
-
45
- /**
46
- * @param EventObserver $event
47
- */
48
- public function deleteImagesFromCloudinary(EventObserver $event)
49
- {
50
- /** @var ConfigurationInterface $configuration */
51
- $configuration = Mage::getModel('cloudinary_cloudinary/configuration');
52
-
53
- if (!$configuration->isEnabled()) {
54
- return;
55
- }
56
-
57
- $imageProvider = CloudinaryImageProvider::fromConfiguration($configuration);
58
-
59
- foreach ($this->getImagesToDelete($event->getProduct()) as $image) {
60
- $migratedPath = $configuration->isFolderedMigration() ? $configuration->getMigratedPath($image['file']) : '';
61
- $imageProvider->delete(Image::fromPath($image['file'], ltrim($migratedPath, '/')));
62
- }
63
- }
64
-
65
- /**
66
- * @param EventObserver $observer
67
- */
68
- public function validateCloudinaryCredentials(EventObserver $observer)
69
- {
70
- $configObject = $observer->getEvent()->getObject();
71
- if ($configObject->getSection() != self::CLOUDINARY_CONFIG_SECTION) {
72
- return;
73
- }
74
-
75
- $configData = $this->flattenConfigData($configObject);
76
- if ($configData['cloudinary_enabled'] != '1') {
77
- return;
78
- }
79
-
80
- $credentialValidator = new CredentialValidator();
81
- $environmentVariable = CloudinaryEnvironmentVariable::fromString($configData['cloudinary_environment_variable']);
82
-
83
- if (!$credentialValidator->validate($environmentVariable->getCredentials())) {
84
- throw new Mage_Core_Exception(self::ERROR_WRONG_CREDENTIALS);
85
- }
86
- }
87
-
88
- /**
89
- * @param Varien_Event_Observer $observer
90
- */
91
- public function cloudinaryConfigChanged(EventObserver $observer)
92
- {
93
- if (!Mage::getModel('cloudinary_cloudinary/configuration')->isEnabled()) {
94
- return;
95
- }
96
-
97
- if (!$this->autoUploadRequestProcessor()->handle('media', Mage::getBaseUrl('media'))) {
98
- Mage::getSingleton('adminhtml/session')->addError(self::AUTO_UPLOAD_SETUP_FAIL_MESSAGE);
99
- }
100
- }
101
-
102
- /**
103
- * @return RequestProcessor
104
- */
105
- private function autoUploadRequestProcessor()
106
- {
107
- return new RequestProcessor(
108
- Mage::getModel('cloudinary_cloudinary/autoUploadMapping_configuration'),
109
- ApiClient::fromConfiguration(Mage::getModel('cloudinary_cloudinary/configuration'))
110
- );
111
- }
112
-
113
- /**
114
- * @param Product $product
115
- *
116
- * @return array
117
- */
118
- private function getImagesToUpload(Product $product)
119
- {
120
- return Mage::getModel('cloudinary_cloudinary/catalog_product_media')->newImagesForProduct($product);
121
- }
122
-
123
- /**
124
- * @param Product $product
125
- *
126
- * @return array
127
- */
128
- private function getImagesToDelete(Product $product)
129
- {
130
- $productMedia = Mage::getModel('cloudinary_cloudinary/catalog_product_media');
131
- return $productMedia->removedImagesForProduct($product);
132
- }
133
-
134
- /**
135
- * @param ConfigData $configObject
136
- *
137
- * @return array
138
- */
139
- private function flattenConfigData(ConfigData $configObject)
140
- {
141
- $configData = array();
142
- $groups = $configObject->getGroups();
143
-
144
- if (array_key_exists('setup', $groups)) {
145
- $configData = array_map(
146
- function($field) {
147
- return $field['value'];
148
- },
149
- $groups['setup']['fields']
150
- );
151
- }
152
- return $configData;
153
- }
154
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/code/community/Cloudinary/Cloudinary/Model/Observer/Config.php ADDED
@@ -0,0 +1,107 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use CloudinaryExtension\CredentialValidator;
4
+ use CloudinaryExtension\Security\CloudinaryEnvironmentVariable;
5
+ use CloudinaryExtension\AutoUploadMapping\RequestProcessor;
6
+ use CloudinaryExtension\AutoUploadMapping\ApiClient;
7
+
8
+ class Cloudinary_Cloudinary_Model_Observer_Config extends Mage_Core_Model_Abstract
9
+ {
10
+ const CLOUDINARY_CONFIG_SECTION = 'cloudinary';
11
+ const ERROR_WRONG_CREDENTIALS = 'There was a problem validating your Cloudinary credentials.';
12
+ const ENABLED_FIELD = 'cloudinary/setup/fields/cloudinary_enabled';
13
+ const ENVIRONMENT_FIELD = 'cloudinary/setup/fields/cloudinary_environment_variable';
14
+ const CONFIG_CHANGE_MESSAGE = 'config saved: [%s]';
15
+ const AUTO_UPLOAD_SETUP_FAIL_MESSAGE = 'error. Unable to setup auto upload mapping.';
16
+ const AUTO_UPLOAD_SETUP_SUCCESS_MESSAGE = 'auto upload mapping configured: %s';
17
+
18
+ /**
19
+ * @param Varien_Event_Observer $observer
20
+ */
21
+ public function configSave(Varien_Event_Observer $observer)
22
+ {
23
+ $config = $observer->getEvent()->getObject();
24
+ if ($config->getSection() != self::CLOUDINARY_CONFIG_SECTION) {
25
+ return;
26
+ }
27
+
28
+ $data = Mage::helper('cloudinary_cloudinary/config')->flatten('cloudinary', $config->getGroups());
29
+ if ($data[self::ENABLED_FIELD] == '1') {
30
+ $this->validateEnvironmentVariable($data);
31
+ $this->logConfigChange($data);
32
+ }
33
+ }
34
+
35
+ /**
36
+ * @param Varien_Event_Observer $observer
37
+ */
38
+ public function cloudinaryConfigChanged(Varien_Event_Observer $observer)
39
+ {
40
+ if (!Mage::getModel('cloudinary_cloudinary/configuration')->isEnabled()) {
41
+ return;
42
+ }
43
+
44
+ if (!$this->autoUploadRequestProcessor()->handle('media', Mage::getBaseUrl('media'))) {
45
+ Mage::getSingleton('adminhtml/session')->addError(self::AUTO_UPLOAD_SETUP_FAIL_MESSAGE);
46
+ Mage::getModel('cloudinary_cloudinary/logger')->error(self::AUTO_UPLOAD_SETUP_FAIL_MESSAGE);
47
+ } else {
48
+ $isActive = Mage::getModel('cloudinary_cloudinary/autoUploadMapping_configuration')->isActive();
49
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(
50
+ sprintf(self::AUTO_UPLOAD_SETUP_SUCCESS_MESSAGE, $isActive ? 'On' : 'Off')
51
+ );
52
+ }
53
+ }
54
+
55
+ /**
56
+ * @param array $data
57
+ */
58
+ private function validateEnvironmentVariable(array $data)
59
+ {
60
+ $credentialValidator = new CredentialValidator();
61
+ $environmentVariable = CloudinaryEnvironmentVariable::fromString($data[self::ENVIRONMENT_FIELD]);
62
+
63
+ if (!$credentialValidator->validate($environmentVariable->getCredentials())) {
64
+ throw new Mage_Core_Exception(self::ERROR_WRONG_CREDENTIALS);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * @param array $data
70
+ */
71
+ private function logConfigChange(array $data)
72
+ {
73
+ $data[self::ENVIRONMENT_FIELD] = md5($data[self::ENVIRONMENT_FIELD]);
74
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(
75
+ sprintf(self::CONFIG_CHANGE_MESSAGE, $this->formatConfigData($data))
76
+ );
77
+ }
78
+
79
+ /**
80
+ * @param array $data
81
+ * @return string
82
+ */
83
+ private function formatConfigData(array $data)
84
+ {
85
+ return implode(
86
+ ', ',
87
+ array_map(
88
+ function($key, $value) {
89
+ return sprintf('(%s: %s)', $key, $value);
90
+ },
91
+ array_keys($data),
92
+ array_values($data)
93
+ )
94
+ );
95
+ }
96
+
97
+ /**
98
+ * @return RequestProcessor
99
+ */
100
+ private function autoUploadRequestProcessor()
101
+ {
102
+ return new RequestProcessor(
103
+ Mage::getModel('cloudinary_cloudinary/autoUploadMapping_configuration'),
104
+ ApiClient::fromConfiguration(Mage::getModel('cloudinary_cloudinary/configuration'))
105
+ );
106
+ }
107
+ }
app/code/community/Cloudinary/Cloudinary/Model/Observer/Product.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use CloudinaryExtension\CloudinaryImageProvider;
4
+ use CloudinaryExtension\Image;
5
+ use Mage_Catalog_Model_Product as Product;
6
+
7
+ class Cloudinary_Cloudinary_Model_Observer_Product extends Mage_Core_Model_Abstract
8
+ {
9
+ const DELETE_MESSAGE = 'deleted product image from Cloudinary: %s';
10
+
11
+ /**
12
+ * @param Varien_Event_Observer $event
13
+ */
14
+ public function uploadImagesToCloudinary(Varien_Event_Observer $event)
15
+ {
16
+ if (Mage::getModel('cloudinary_cloudinary/configuration')->isEnabled()) {
17
+ $cloudinaryImage = Mage::getModel('cloudinary_cloudinary/image');
18
+
19
+ foreach ($this->getImagesToUpload($event->getProduct()) as $image) {
20
+ $cloudinaryImage->upload($image);
21
+ }
22
+ }
23
+ }
24
+
25
+ /**
26
+ * @param Varien_Event_Observer $event
27
+ */
28
+ public function deleteImagesFromCloudinary(Varien_Event_Observer $event)
29
+ {
30
+ /** @var ConfigurationInterface $configuration */
31
+ $configuration = Mage::getModel('cloudinary_cloudinary/configuration');
32
+
33
+ if (!$configuration->isEnabled()) {
34
+ return;
35
+ }
36
+
37
+ $imageProvider = CloudinaryImageProvider::fromConfiguration($configuration);
38
+
39
+ foreach ($this->getImagesToDelete($event->getProduct()) as $image) {
40
+ $migratedPath = $configuration->isFolderedMigration() ? $configuration->getMigratedPath($image['file']) : '';
41
+ $imageProvider->delete(Image::fromPath($image['file'], ltrim($migratedPath, '/')));
42
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(sprintf(self::DELETE_MESSAGE, $image['file']));
43
+ }
44
+ }
45
+
46
+ /**
47
+ * @param Product $product
48
+ * @return array
49
+ */
50
+ private function getImagesToUpload(Product $product)
51
+ {
52
+ return Mage::getModel('cloudinary_cloudinary/catalog_product_media')->newImagesForProduct($product);
53
+ }
54
+
55
+ /**
56
+ * @param Product $product
57
+ * @return array
58
+ */
59
+ private function getImagesToDelete(Product $product)
60
+ {
61
+ $productMedia = Mage::getModel('cloudinary_cloudinary/catalog_product_media');
62
+ return $productMedia->removedImagesForProduct($product);
63
+ }
64
+ }
app/code/community/Cloudinary/Cloudinary/Model/Observer/System.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudinary_Cloudinary_Model_Observer_System extends Mage_Core_Model_Abstract
4
+ {
5
+ /**
6
+ * @param Varien_Event_Observer $event
7
+ * @return Varien_Event_Observer
8
+ */
9
+ public function loadCustomAutoloaders(Varien_Event_Observer $event)
10
+ {
11
+ Mage::helper('cloudinary_cloudinary/autoloader')->register();
12
+
13
+ return $event;
14
+ }
15
+ }
app/code/community/Cloudinary/Cloudinary/controllers/Adminhtml/CloudinaryController.php CHANGED
@@ -3,6 +3,9 @@
3
  class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtml_Controller_Action
4
  {
5
  const CRON_INTERVAL = 300;
 
 
 
6
 
7
  /**
8
  * @var Cloudinary_Cloudinary_Model_Migration
@@ -66,7 +69,9 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
66
  );
67
 
68
  foreach ($combinedMediaRepository->findOrphanedSynchronisedImages() as $orphanImage) {
69
- Mage::getModel('cloudinary_cloudinary/migrationError')->orphanRemoved($orphanImage)->save();
 
 
70
  $orphanImage->delete();
71
  }
72
  }
@@ -80,6 +85,8 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
80
  {
81
  $this->_migrationTask->start();
82
 
 
 
83
  $this->_redirectToManageCloudinary();
84
  }
85
 
@@ -87,6 +94,8 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
87
  {
88
  $this->_migrationTask->stop();
89
 
 
 
90
  $this->_redirectToManageCloudinary();
91
  }
92
 
@@ -138,6 +147,8 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtm
138
  'https://support.cloudinary.com/hc/en-us/articles/203188781-Why-is-the-migration-process-stuck-on-zero-'
139
  )
140
  );
 
 
141
  }
142
 
143
  private function _displayValidationFailureMessage()
3
  class Cloudinary_Cloudinary_Adminhtml_CloudinaryController extends Mage_Adminhtml_Controller_Action
4
  {
5
  const CRON_INTERVAL = 300;
6
+ const MIGRATION_START_MESSAGE = 'migration start requested.';
7
+ const MIGRATION_STOP_MESSAGE = 'migration stop requested.';
8
+ const MIGRATION_CRON_WARNING = 'cron is not running, so no migration will occur.';
9
 
10
  /**
11
  * @var Cloudinary_Cloudinary_Model_Migration
69
  );
70
 
71
  foreach ($combinedMediaRepository->findOrphanedSynchronisedImages() as $orphanImage) {
72
+ $error = Mage::getModel('cloudinary_cloudinary/migrationError')->orphanRemoved($orphanImage);
73
+ Mage::getModel('cloudinary_cloudinary/logger')->notice($error->getMessage());
74
+ $error->save();
75
  $orphanImage->delete();
76
  }
77
  }
85
  {
86
  $this->_migrationTask->start();
87
 
88
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(self::MIGRATION_START_MESSAGE);
89
+
90
  $this->_redirectToManageCloudinary();
91
  }
92
 
94
  {
95
  $this->_migrationTask->stop();
96
 
97
+ Mage::getModel('cloudinary_cloudinary/logger')->notice(self::MIGRATION_STOP_MESSAGE);
98
+
99
  $this->_redirectToManageCloudinary();
100
  }
101
 
147
  'https://support.cloudinary.com/hc/en-us/articles/203188781-Why-is-the-migration-process-stuck-on-zero-'
148
  )
149
  );
150
+
151
+ Mage::getModel('cloudinary_cloudinary/logger')->error(self::MIGRATION_CRON_WARNING);
152
  }
153
 
154
  private function _displayValidationFailureMessage()
app/code/community/Cloudinary/Cloudinary/controllers/Adminhtml/CloudinaryajaxController.php CHANGED
@@ -8,16 +8,20 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryajaxController extends Mage_Admi
8
  public function sampleAction()
9
  {
10
  try {
 
 
 
 
11
  $freeTransform = $this->getRequest()->getParam('free');
12
  $freeModel = Mage::getModel('cloudinary_cloudinary/system_config_free');
13
  $url = $freeModel->sampleImageUrl($this->defaultTransform($freeTransform));
14
  $this->validate($freeModel, $url);
15
- $this->jsonReponse(
16
  200,
17
  ['url' => $url]
18
  );
19
  } catch (\Exception $e) {
20
- $this->jsonReponse(401, ['error' => $e->getMessage()]);
21
  }
22
  }
23
 
@@ -25,7 +29,7 @@ class Cloudinary_Cloudinary_Adminhtml_CloudinaryajaxController extends Mage_Admi
25
  * @param int $code
26
  * @param array $payload
27
  */
28
- private function jsonReponse($code, array $payload)
29
  {
30
  $this->getResponse()
31
  ->clearHeaders()
8
  public function sampleAction()
9
  {
10
  try {
11
+ if (!$this->_validateSecretKey()) {
12
+ throw new Exception('Incorrect security key');
13
+ }
14
+
15
  $freeTransform = $this->getRequest()->getParam('free');
16
  $freeModel = Mage::getModel('cloudinary_cloudinary/system_config_free');
17
  $url = $freeModel->sampleImageUrl($this->defaultTransform($freeTransform));
18
  $this->validate($freeModel, $url);
19
+ $this->jsonResponse(
20
  200,
21
  ['url' => $url]
22
  );
23
  } catch (\Exception $e) {
24
+ $this->jsonResponse(401, ['error' => $e->getMessage()]);
25
  }
26
  }
27
 
29
  * @param int $code
30
  * @param array $payload
31
  */
32
+ private function jsonResponse($code, array $payload)
33
  {
34
  $this->getResponse()
35
  ->clearHeaders()
app/code/community/Cloudinary/Cloudinary/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Cloudinary_Cloudinary>
5
- <version>2.6.0</version>
6
  </Cloudinary_Cloudinary>
7
  </modules>
8
  <global>
@@ -84,7 +84,7 @@
84
  <observers>
85
  <upload_images_to_cloudinary>
86
  <type>singleton</type>
87
- <class>cloudinary_cloudinary/observer</class>
88
  <method>uploadImagesToCloudinary</method>
89
  </upload_images_to_cloudinary>
90
  </observers>
@@ -93,7 +93,7 @@
93
  <observers>
94
  <delete_images_from_cloudinary>
95
  <type>singleton</type>
96
- <class>cloudinary_cloudinary/observer</class>
97
  <method>deleteImagesFromCloudinary</method>
98
  </delete_images_from_cloudinary>
99
  </observers>
@@ -102,7 +102,7 @@
102
  <observers>
103
  <load_custom_autoloaders>
104
  <type>singleton</type>
105
- <class>cloudinary_cloudinary/observer</class>
106
  <method>loadCustomAutoloaders</method>
107
  </load_custom_autoloaders>
108
  </observers>
@@ -129,18 +129,18 @@
129
  <events>
130
  <model_config_data_save_before>
131
  <observers>
132
- <validate_cloudinary_credentials>
133
- <class>cloudinary_cloudinary/observer</class>
134
- <method>validateCloudinaryCredentials</method>
135
- </validate_cloudinary_credentials>
136
  </observers>
137
  </model_config_data_save_before>
138
  <admin_system_config_changed_section_cloudinary>
139
  <observers>
140
- <validate_cloudinary_credentials>
141
- <class>cloudinary_cloudinary/observer</class>
142
  <method>cloudinaryConfigChanged</method>
143
- </validate_cloudinary_credentials>
144
  </observers>
145
  </admin_system_config_changed_section_cloudinary>
146
  </events>
@@ -160,7 +160,7 @@
160
  <cloudinary>
161
  <transformations>
162
  <cloudinary_fetch_format>1</cloudinary_fetch_format>
163
- <cloudinary_image_quality>80</cloudinary_image_quality>
164
  <cloudinary_image_dpr>1.0</cloudinary_image_dpr>
165
  </transformations>
166
  <configuration>
2
  <config>
3
  <modules>
4
  <Cloudinary_Cloudinary>
5
+ <version>2.7.0</version>
6
  </Cloudinary_Cloudinary>
7
  </modules>
8
  <global>
84
  <observers>
85
  <upload_images_to_cloudinary>
86
  <type>singleton</type>
87
+ <class>cloudinary_cloudinary/observer_product</class>
88
  <method>uploadImagesToCloudinary</method>
89
  </upload_images_to_cloudinary>
90
  </observers>
93
  <observers>
94
  <delete_images_from_cloudinary>
95
  <type>singleton</type>
96
+ <class>cloudinary_cloudinary/observer_product</class>
97
  <method>deleteImagesFromCloudinary</method>
98
  </delete_images_from_cloudinary>
99
  </observers>
102
  <observers>
103
  <load_custom_autoloaders>
104
  <type>singleton</type>
105
+ <class>cloudinary_cloudinary/observer_system</class>
106
  <method>loadCustomAutoloaders</method>
107
  </load_custom_autoloaders>
108
  </observers>
129
  <events>
130
  <model_config_data_save_before>
131
  <observers>
132
+ <config_save>
133
+ <class>cloudinary_cloudinary/observer_config</class>
134
+ <method>configSave</method>
135
+ </config_save>
136
  </observers>
137
  </model_config_data_save_before>
138
  <admin_system_config_changed_section_cloudinary>
139
  <observers>
140
+ <cloudinary_config_changed>
141
+ <class>cloudinary_cloudinary/observer_config</class>
142
  <method>cloudinaryConfigChanged</method>
143
+ </cloudinary_config_changed>
144
  </observers>
145
  </admin_system_config_changed_section_cloudinary>
146
  </events>
160
  <cloudinary>
161
  <transformations>
162
  <cloudinary_fetch_format>1</cloudinary_fetch_format>
163
+ <cloudinary_image_quality>auto</cloudinary_image_quality>
164
  <cloudinary_image_dpr>1.0</cloudinary_image_dpr>
165
  </transformations>
166
  <configuration>
app/design/adminhtml/default/default/template/cloudinary/system/config/free.phtml CHANGED
@@ -27,7 +27,7 @@
27
  },
28
 
29
  getSampleImageUrl: function() {
30
- return '/admin/cloudinaryajax/sample/free/' + this.getTransformText() + '/key/' + this.secret;
31
  },
32
 
33
  getImageHtml: function(src) {
@@ -62,6 +62,8 @@
62
  self.setPreviewActiveState(false);
63
 
64
  new Ajax.Request(this.getSampleImageUrl(), {
 
 
65
  onSuccess: function(response) {
66
  self.updatePreviewImage(response.responseJSON.url);
67
  },
27
  },
28
 
29
  getSampleImageUrl: function() {
30
+ return '/admin/cloudinaryajax/sample/key/' + this.secret;
31
  },
32
 
33
  getImageHtml: function(src) {
62
  self.setPreviewActiveState(false);
63
 
64
  new Ajax.Request(this.getSampleImageUrl(), {
65
+ method: 'post',
66
+ parameters: { free: this.getTransformText() },
67
  onSuccess: function(response) {
68
  self.updatePreviewImage(response.responseJSON.url);
69
  },
lib/Cloudinary/Api.php CHANGED
@@ -320,7 +320,16 @@ class Api {
320
 
321
  if ($method != "get")
322
  {
323
- $post_params = array();
 
 
 
 
 
 
 
 
 
324
  foreach ($params as $key => $value) {
325
  if (is_array($value)) {
326
  $i = 0;
@@ -332,8 +341,8 @@ class Api {
332
  $post_params[$key] = $value;
333
  }
334
  }
335
- curl_setopt($ch, CURLOPT_POSTFIELDS, $post_params);
336
-
337
  }
338
  curl_setopt($ch, CURLOPT_HEADER, 1);
339
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
320
 
321
  if ($method != "get")
322
  {
323
+ $post_params = array();
324
+ if (array_key_exists("content_type", $options) && $options["content_type"] == 'application/json')
325
+ {
326
+ $headers = array(
327
+ "Content-type: application/json",
328
+ "Accept: application/json",
329
+ );
330
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
331
+ $post_params = json_encode($params);
332
+ } else {
333
  foreach ($params as $key => $value) {
334
  if (is_array($value)) {
335
  $i = 0;
341
  $post_params[$key] = $value;
342
  }
343
  }
344
+ }
345
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $post_params);
346
  }
347
  curl_setopt($ch, CURLOPT_HEADER, 1);
348
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
lib/Cloudinary/Cloudinary.php CHANGED
@@ -11,9 +11,9 @@ class Cloudinary {
11
  const RANGE_VALUE_RE = '/^(?P<value>(\d+\.)?\d+)(?P<modifier>[%pP])?$/';
12
  const RANGE_RE = '/^(\d+\.)?\d+[%pP]?\.\.(\d+\.)?\d+[%pP]?$/';
13
 
14
- const VERSION = "1.6.2";
15
  /** @internal Do not change this value */
16
- const USER_AGENT = "CloudinaryPHP/1.6.2";
17
 
18
  /**
19
  * Additional information to be passed with the USER_AGENT, e.g. "CloudinaryMagento/1.0.1". This value is set in platform-specific
@@ -224,29 +224,44 @@ class Cloudinary {
224
  $underlay = Cloudinary::process_layer(Cloudinary::option_consume($options, "underlay"), "underlay");
225
  $if = Cloudinary::process_if(Cloudinary::option_consume($options, "if"));
226
 
 
 
 
 
 
 
 
 
227
  $params = array(
228
- "a" => $angle,
 
229
  "b" => $background,
230
  "bo" => $border,
231
  "c" => $crop,
232
  "co" => $color,
233
- "dpr" => $dpr,
234
  "du" => $duration,
235
- "e" => $effect,
236
  "eo" => $end_offset,
237
  "fl" => $flags,
238
- "h" => $height,
239
  "l" => $overlay,
 
 
 
240
  "so" => $start_offset,
241
  "t" => $named_transformation,
242
  "u" => $underlay,
243
  "vc" => $video_codec,
244
- "w" => $width);
 
 
 
 
245
 
246
  $simple_params = array(
247
  "ac" => "audio_codec",
248
  "af" => "audio_frequency",
249
- "ar" => "aspect_ratio",
250
  "br" => "bit_rate",
251
  "cs" => "color_space",
252
  "d" => "default_image",
@@ -254,31 +269,45 @@ class Cloudinary {
254
  "dn" => "density",
255
  "f" => "fetch_format",
256
  "g" => "gravity",
257
- "o" => "opacity",
258
  "p" => "prefix",
259
  "pg" => "page",
260
- "q" => "quality",
261
- "r" => "radius",
262
  "vs" => "video_sampling",
263
- "x" => "x",
264
- "y" => "y",
265
- "z" => "zoom"
266
  );
267
 
268
  foreach ($simple_params as $param=>$option) {
269
  $params[$param] = Cloudinary::option_consume($options, $option);
270
  }
271
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  $param_filter = function($value) { return $value === 0 || $value === '0' || trim($value) == true; };
273
  $params = array_filter($params, $param_filter);
274
  ksort($params);
275
  if (isset($if)) {
276
- $params = array_merge(array("if"=>$if), $params);
277
  }
278
  $join_pair = function($key, $value) { return $key . "_" . $value; };
279
  $transformation = implode(",", array_map($join_pair, array_keys($params), array_values($params)));
280
  $raw_transformation = Cloudinary::option_consume($options, "raw_transformation");
281
- $transformation = implode(",", array_filter(array($transformation, $raw_transformation)));
282
  array_push($base_transformations, $transformation);
283
  if ($responsive_width) {
284
  $responsive_width_transformation = Cloudinary::config_get("responsive_width_transformation", Cloudinary::$DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION);
@@ -330,11 +359,20 @@ class Cloudinary {
330
  return implode("_", array_filter($keywords, 'Cloudinary::is_not_null'));
331
  }
332
 
 
 
 
 
 
 
 
333
  private static function process_layer($layer, $layer_parameter) {
334
- if (is_array($layer)) {
 
335
  $resource_type = Cloudinary::option_get($layer, "resource_type");
336
  $type = Cloudinary::option_get($layer, "type");
337
  $text = Cloudinary::option_get($layer, "text");
 
338
  $text_style = NULL;
339
  $public_id = Cloudinary::option_get($layer, "public_id");
340
  $format = Cloudinary::option_get($layer, "format");
@@ -345,38 +383,66 @@ class Cloudinary {
345
  if($format != NULL) $public_id = $public_id . "." . $format;
346
  }
347
 
348
- if ($text == NULL && $resource_type != "text"){
349
- if ($public_id == NULL) {
350
- throw new InvalidArgumentException("Must supply public_id for $resource_type $layer_parameter");
351
- }
352
- if($resource_type == "subtitles") {
353
- $text_style = Cloudinary::text_style($layer, $layer_parameter);
354
- }
355
-
356
- } else {
357
- $resource_type = "text";
358
- $type = NULL; // type is ignored for text layers
359
- $text_style = Cloudinary::text_style($layer, $layer_parameter); #FIXME duplicate
360
- if($text != NULL) {
361
- if(!($public_id != NULL xor $text_style != NULL)) {
362
- throw new InvalidArgumentException("Must supply either style parameters or a public_id when providing text parameter in a text $layer_parameter");
363
- }
364
- $text = Cloudinary::smart_escape($text);
365
- $text = str_replace("%2C", "%252C", $text);
366
- $text = str_replace("/", "%252F", $text);
367
- }
368
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
369
  if($resource_type != "image") array_push($components, $resource_type);
370
  if($type != "upload") array_push($components, $type);
371
  array_push($components, $text_style);
372
  array_push($components, $public_id);
373
  array_push($components, $text);
 
 
 
374
  $layer = implode(":", array_filter($components, 'Cloudinary::is_not_null'));
375
  }
 
 
 
 
 
 
 
 
376
  return $layer;
377
  }
378
 
379
- private static $IF_OPERATORS = array(
380
  "=" => 'eq',
381
  "!=" => 'ne',
382
  "<" => 'lt',
@@ -384,36 +450,62 @@ class Cloudinary {
384
  "<=" => 'lte',
385
  ">=" => 'gte',
386
  "&&" => 'and',
387
- "||" => 'or');
388
- private static $IF_PARAMETERS = array(
389
- "width" => 'w',
390
- "height" => 'h',
391
- "page_count" => "pc",
 
 
 
 
392
  "face_count" => "fc",
393
- "aspect_ratio" => "ar"
 
 
 
 
 
 
 
 
394
  );
395
 
396
  private static function translate_if( $source )
397
  {
398
- if (isset(self::$IF_OPERATORS[$source[0]])) {
399
- return self::$IF_OPERATORS[$source[0]];
400
- } elseif (isset(self::$IF_PARAMETERS[$source[0]])) {
401
- return self::$IF_PARAMETERS[$source[0]];
402
  } else {
403
  return $source[0];
404
  }
405
  }
406
 
407
- private static $IF_REPLACE_RE;
 
408
  private static function process_if($if) {
 
 
 
 
 
 
 
 
 
 
 
409
  if (empty(self::$IF_REPLACE_RE)) {
410
- self::$IF_REPLACE_RE = '/(' . implode('|', array_keys(self::$IF_PARAMETERS)) . '|[=<>&|!]+)/';
411
  }
412
- if (isset($if)) {
413
- $if = preg_replace('/[ _]+/', '_', $if);
414
- $if = preg_replace_callback(self::$IF_REPLACE_RE, array("Cloudinary", "translate_if"), $if);
415
  }
416
- return $if;
 
 
417
  }
418
 
419
  private static function process_border($border) {
11
  const RANGE_VALUE_RE = '/^(?P<value>(\d+\.)?\d+)(?P<modifier>[%pP])?$/';
12
  const RANGE_RE = '/^(\d+\.)?\d+[%pP]?\.\.(\d+\.)?\d+[%pP]?$/';
13
 
14
+ const VERSION = "1.8.0";
15
  /** @internal Do not change this value */
16
+ const USER_AGENT = "CloudinaryPHP/1.8.0";
17
 
18
  /**
19
  * Additional information to be passed with the USER_AGENT, e.g. "CloudinaryMagento/1.0.1". This value is set in platform-specific
224
  $underlay = Cloudinary::process_layer(Cloudinary::option_consume($options, "underlay"), "underlay");
225
  $if = Cloudinary::process_if(Cloudinary::option_consume($options, "if"));
226
 
227
+ $aspect_ratio = Cloudinary::option_consume($options, "aspect_ratio");
228
+ $opacity = Cloudinary::option_consume($options, "opacity");
229
+ $quality = Cloudinary::option_consume($options, "quality");
230
+ $radius = Cloudinary::option_consume($options, "radius");
231
+ $x = Cloudinary::option_consume($options, "x");
232
+ $y = Cloudinary::option_consume($options, "y");
233
+ $zoom = Cloudinary::option_consume($options, "zoom");
234
+
235
  $params = array(
236
+ "a" => self::normalize_expression($angle),
237
+ "ar" => self::normalize_expression($aspect_ratio),
238
  "b" => $background,
239
  "bo" => $border,
240
  "c" => $crop,
241
  "co" => $color,
242
+ "dpr" => self::normalize_expression($dpr),
243
  "du" => $duration,
244
+ "e" => self::normalize_expression($effect),
245
  "eo" => $end_offset,
246
  "fl" => $flags,
247
+ "h" => self::normalize_expression($height),
248
  "l" => $overlay,
249
+ "o" => self::normalize_expression($opacity),
250
+ "q" => self::normalize_expression($quality),
251
+ "r" => self::normalize_expression($radius),
252
  "so" => $start_offset,
253
  "t" => $named_transformation,
254
  "u" => $underlay,
255
  "vc" => $video_codec,
256
+ "w" => self::normalize_expression($width),
257
+ "x" => self::normalize_expression($x),
258
+ "y" => self::normalize_expression($y),
259
+ "z" => self::normalize_expression($zoom),
260
+ );
261
 
262
  $simple_params = array(
263
  "ac" => "audio_codec",
264
  "af" => "audio_frequency",
 
265
  "br" => "bit_rate",
266
  "cs" => "color_space",
267
  "d" => "default_image",
269
  "dn" => "density",
270
  "f" => "fetch_format",
271
  "g" => "gravity",
 
272
  "p" => "prefix",
273
  "pg" => "page",
 
 
274
  "vs" => "video_sampling",
 
 
 
275
  );
276
 
277
  foreach ($simple_params as $param=>$option) {
278
  $params[$param] = Cloudinary::option_consume($options, $option);
279
  }
280
 
281
+ $variables = !empty($options["variables"]) ? $options["variables"] : [];
282
+
283
+ $var_params = [];
284
+ foreach($options as $key => $value) {
285
+ if (preg_match('/^\$/', $key)) {
286
+ $var_params[] = $key . '_' . self::normalize_expression((string)$value);
287
+ }
288
+ }
289
+
290
+ sort($var_params);
291
+
292
+ if (!empty($variables)) {
293
+ foreach($variables as $key => $value) {
294
+ $var_params[] = $key . '_' . self::normalize_expression((string)$value);
295
+ }
296
+ }
297
+
298
+ $variables = join(',', $var_params);
299
+
300
+
301
  $param_filter = function($value) { return $value === 0 || $value === '0' || trim($value) == true; };
302
  $params = array_filter($params, $param_filter);
303
  ksort($params);
304
  if (isset($if)) {
305
+ $if = 'if_' . $if;
306
  }
307
  $join_pair = function($key, $value) { return $key . "_" . $value; };
308
  $transformation = implode(",", array_map($join_pair, array_keys($params), array_values($params)));
309
  $raw_transformation = Cloudinary::option_consume($options, "raw_transformation");
310
+ $transformation = implode(",", array_filter(array($if, $variables, $transformation, $raw_transformation)));
311
  array_push($base_transformations, $transformation);
312
  if ($responsive_width) {
313
  $responsive_width_transformation = Cloudinary::config_get("responsive_width_transformation", Cloudinary::$DEFAULT_RESPONSIVE_WIDTH_TRANSFORMATION);
359
  return implode("_", array_filter($keywords, 'Cloudinary::is_not_null'));
360
  }
361
 
362
+ /**
363
+ * Handle overlays.
364
+ * Overlay properties can came as array or as string.
365
+ * @param $layer
366
+ * @param $layer_parameter
367
+ * @return string
368
+ */
369
  private static function process_layer($layer, $layer_parameter) {
370
+ // When overlay is array.
371
+ if (is_array($layer)) {
372
  $resource_type = Cloudinary::option_get($layer, "resource_type");
373
  $type = Cloudinary::option_get($layer, "type");
374
  $text = Cloudinary::option_get($layer, "text");
375
+ $fetch = Cloudinary::option_get($layer, "fetch");
376
  $text_style = NULL;
377
  $public_id = Cloudinary::option_get($layer, "public_id");
378
  $format = Cloudinary::option_get($layer, "format");
383
  if($format != NULL) $public_id = $public_id . "." . $format;
384
  }
385
 
386
+ // Fetch overlay.
387
+ if (!empty($fetch) || $resource_type === "fetch") {
388
+ $public_id = NULL;
389
+ $resource_type = "fetch";
390
+ $fetch = base64_encode($fetch);
391
+ }
392
+
393
+ // Text overlay.
394
+ elseif (!empty($text) || $resource_type === "text") {
395
+ $resource_type = "text";
396
+ $type = NULL; // type is ignored for text layers
397
+ $text_style = Cloudinary::text_style($layer, $layer_parameter); #FIXME duplicate
398
+ if ($text != NULL) {
399
+ if (!($public_id != NULL xor $text_style != NULL)) {
400
+ throw new InvalidArgumentException("Must supply either style parameters or a public_id when providing text parameter in a text $layer_parameter");
401
+ }
402
+ $escaped = Cloudinary::smart_escape($text);
403
+ $escaped = str_replace("%2C", "%252C", $escaped);
404
+ $escaped = str_replace("/", "%252F", $escaped);
405
+ # Don't encode interpolation expressions e.g. $(variable)
406
+ preg_match_all('/\$\([a-zA-Z]\w+\)/', $text, $matches);
407
+ foreach ($matches[0] as $match) {
408
+ $escaped_match = Cloudinary::smart_escape($match);
409
+ $escaped = str_replace($escaped_match, $match, $escaped);
410
+ }
411
+
412
+ $text = $escaped;
413
+ }
414
+ } else {
415
+ if ($public_id == NULL) {
416
+ throw new InvalidArgumentException("Must supply public_id for $resource_type $layer_parameter");
417
+ }
418
+ if ($resource_type == "subtitles") {
419
+ $text_style = Cloudinary::text_style($layer, $layer_parameter);
420
+ }
421
+ }
422
+
423
+ // Build a components array.
424
  if($resource_type != "image") array_push($components, $resource_type);
425
  if($type != "upload") array_push($components, $type);
426
  array_push($components, $text_style);
427
  array_push($components, $public_id);
428
  array_push($components, $text);
429
+ array_push($components, $fetch);
430
+
431
+ // Build a valid overlay string.
432
  $layer = implode(":", array_filter($components, 'Cloudinary::is_not_null'));
433
  }
434
+
435
+ // Handle fetch overlay from string definition.
436
+ elseif (substr($layer, 0, strlen('fetch:')) === 'fetch:') {
437
+ $url = substr($layer, strlen('fetch:'));
438
+ $b64 = base64_encode($url);
439
+ $layer = 'fetch:' . $b64;
440
+ }
441
+
442
  return $layer;
443
  }
444
 
445
+ private static $CONDITIONAL_OPERATORS = array(
446
  "=" => 'eq',
447
  "!=" => 'ne',
448
  "<" => 'lt',
450
  "<=" => 'lte',
451
  ">=" => 'gte',
452
  "&&" => 'and',
453
+ "||" => 'or',
454
+ "*" => 'mul',
455
+ "/" => 'div',
456
+ "+" => 'add',
457
+ "-" => 'sub'
458
+ );
459
+ private static $PREDEFINED_VARS = array(
460
+ "aspect_ratio" => "ar",
461
+ "current_page" => "cp",
462
  "face_count" => "fc",
463
+ "height" => "h",
464
+ "initial_aspect_ratio" => "iar",
465
+ "initial_height" => "ih",
466
+ "initial_width" => "iw",
467
+ "page_count" => "pc",
468
+ "page_x" => "px",
469
+ "page_y" => "py",
470
+ "tags" => "tags",
471
+ "width" => "w"
472
  );
473
 
474
  private static function translate_if( $source )
475
  {
476
+ if (isset(self::$CONDITIONAL_OPERATORS[$source[0]])) {
477
+ return self::$CONDITIONAL_OPERATORS[$source[0]];
478
+ } elseif (isset(self::$PREDEFINED_VARS[$source[0]])) {
479
+ return self::$PREDEFINED_VARS[$source[0]];
480
  } else {
481
  return $source[0];
482
  }
483
  }
484
 
485
+ private static $IF_REPLACE_RE;
486
+
487
  private static function process_if($if) {
488
+ $if = self::normalize_expression($if);
489
+ return $if;
490
+ }
491
+
492
+ private static function normalize_expression($exp) {
493
+ if (is_float($exp)) {
494
+ return number_format($exp, 1);
495
+ }
496
+ if (preg_match('/^!.+!$/', $exp)) {
497
+ return $exp;
498
+ } else {
499
  if (empty(self::$IF_REPLACE_RE)) {
500
+ self::$IF_REPLACE_RE = '/((\|\||>=|<=|&&|!=|>|=|<|\/|\-|\+|\*)(?=[ _])|' . implode('|', array_keys(self::$PREDEFINED_VARS)) . ')/';
501
  }
502
+ if (isset($exp)) {
503
+ $exp = preg_replace('/[ _]+/', '_', $exp);
504
+ $exp = preg_replace_callback(self::$IF_REPLACE_RE, array("Cloudinary", "translate_if"), $exp);
505
  }
506
+ return $exp;
507
+ }
508
+
509
  }
510
 
511
  private static function process_border($border) {
lib/Cloudinary/Search.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace Cloudinary {
4
+
5
+ class Search {
6
+
7
+ private $query_hash;
8
+
9
+ public function __construct() {
10
+ $this->query_hash = array(
11
+ 'sort_by' => array(),
12
+ 'aggregate' => array(),
13
+ 'with_field' => array()
14
+ );
15
+ }
16
+
17
+ public function expression($value) {
18
+ $this->query_hash['expression'] = $value;
19
+ return $this;
20
+ }
21
+
22
+ public function max_results($value) {
23
+ $this->query_hash['max_results'] = $value;
24
+ return $this;
25
+ }
26
+
27
+ public function next_cursor($value) {
28
+ $this->query_hash['next_cursor'] = $value;
29
+ return $this;
30
+ }
31
+
32
+ public function sort_by($field_name, $dir = 'desc') {
33
+ array_push($this->query_hash['sort_by'], array($field_name => $dir));
34
+ return $this;
35
+ }
36
+
37
+ public function aggregate($value) {
38
+ array_push($this->query_hash['aggregate'], $value);
39
+ return $this;
40
+ }
41
+
42
+ public function with_field($value) {
43
+ array_push($this->query_hash['with_field'], $value);
44
+ return $this;
45
+ }
46
+
47
+ public function as_array() {
48
+ return array_filter($this->query_hash, function($value) {
49
+ return ((is_array($value) && !empty($value)) || ($value != NULL));
50
+ });
51
+ }
52
+
53
+ public function execute($options = array()) {
54
+ $api = new Api();
55
+ $uri = array('resources/search');
56
+ $options = array_merge($options, array('content_type' => 'application/json'));
57
+ $method = 'post';
58
+ return $api->call_api( $method, $uri, $this->as_array(), $options);
59
+ }
60
+
61
+ }
62
+
63
+ }
64
+
65
+ ?>
lib/Cloudinary/Uploader.php CHANGED
@@ -8,6 +8,7 @@ namespace Cloudinary {
8
  {
9
  $params = array("timestamp" => time(),
10
  "allowed_formats" => \Cloudinary::encode_array(\Cloudinary::option_get($options, "allowed_formats")),
 
11
  "auto_tagging" => \Cloudinary::option_get($options, "auto_tagging"),
12
  "background_removal" => \Cloudinary::option_get($options, "background_removal"),
13
  "backup" => \Cloudinary::option_get($options, "backup"),
8
  {
9
  $params = array("timestamp" => time(),
10
  "allowed_formats" => \Cloudinary::encode_array(\Cloudinary::option_get($options, "allowed_formats")),
11
+ "async" => \Cloudinary::option_get($options, "async"),
12
  "auto_tagging" => \Cloudinary::option_get($options, "auto_tagging"),
13
  "background_removal" => \Cloudinary::option_get($options, "background_removal"),
14
  "backup" => \Cloudinary::option_get($options, "backup"),
lib/CloudinaryExtension/AutoUploadMapping/ApiClient.php CHANGED
@@ -4,6 +4,7 @@ namespace CloudinaryExtension\AutoUploadMapping;
4
 
5
  use Cloudinary;
6
  use Cloudinary\Api;
 
7
  use CloudinaryExtension\ConfigurationBuilder;
8
  use CloudinaryExtension\ConfigurationInterface;
9
 
@@ -85,11 +86,11 @@ class ApiClient
85
  }
86
 
87
  /**
88
- * @param array $response
89
  * @return array
90
  * @throws \Exception
91
  */
92
- private function parseFetchMappingsResponse(array $response)
93
  {
94
  if (!array_key_exists(self::MAPPINGS_KEY, $response) || !is_array($response[self::MAPPINGS_KEY])) {
95
  throw new \Exception('Illegal mapping response');
4
 
5
  use Cloudinary;
6
  use Cloudinary\Api;
7
+ use Cloudinary\Api\Response;
8
  use CloudinaryExtension\ConfigurationBuilder;
9
  use CloudinaryExtension\ConfigurationInterface;
10
 
86
  }
87
 
88
  /**
89
+ * @param Response $response
90
  * @return array
91
  * @throws \Exception
92
  */
93
+ private function parseFetchMappingsResponse(Response $response)
94
  {
95
  if (!array_key_exists(self::MAPPINGS_KEY, $response) || !is_array($response[self::MAPPINGS_KEY])) {
96
  throw new \Exception('Illegal mapping response');
lib/CloudinaryExtension/CloudinaryImageProvider.php CHANGED
@@ -68,7 +68,7 @@ class CloudinaryImageProvider implements ImageProvider
68
  public function retrieveTransformed(Image $image, Transformation $transformation)
69
  {
70
  return Image::fromPath(
71
- \cloudinary_url($image->getId(), $transformation->build() + ["secure" => true]),
72
  $image->getRelativePath()
73
  );
74
  }
68
  public function retrieveTransformed(Image $image, Transformation $transformation)
69
  {
70
  return Image::fromPath(
71
+ \cloudinary_url($image->getId(), ['transformation' => $transformation->build(), 'secure' => true]),
72
  $image->getRelativePath()
73
  );
74
  }
lib/CloudinaryExtension/Image/Transformation.php CHANGED
@@ -84,16 +84,18 @@ class Transformation
84
 
85
  public function build()
86
  {
87
- return array(
88
- 'fetch_format' => (string)$this->fetchFormat,
89
- 'quality' => (string)$this->quality,
90
- 'crop' => (string)$this->crop,
91
- 'gravity' => (string)$this->gravity ?: null,
92
- 'width' => $this->dimensions ? $this->dimensions->getWidth() : null,
93
- 'height' => $this->dimensions ? $this->dimensions->getHeight() : null,
94
- 'dpr' => (string)$this->dpr,
95
- 'flags' => $this->flags,
96
- 'raw_transformation' => (string)$this->freeform
97
- );
 
 
98
  }
99
  }
84
 
85
  public function build()
86
  {
87
+ return [
88
+ [
89
+ 'fetch_format' => (string)$this->fetchFormat,
90
+ 'quality' => (string)$this->quality,
91
+ 'crop' => (string)$this->crop,
92
+ 'gravity' => (string)$this->gravity ?: null,
93
+ 'width' => $this->dimensions ? $this->dimensions->getWidth() : null,
94
+ 'height' => $this->dimensions ? $this->dimensions->getHeight() : null,
95
+ 'dpr' => (string)$this->dpr,
96
+ 'flags' => $this->flags
97
+ ],
98
+ ['raw_transformation' => (string)$this->freeform]
99
+ ];
100
  }
101
  }
package.xml CHANGED
@@ -1,22 +1,21 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Cloudinary_Cloudinary</name>
4
- <version>2.6.0</version>
5
  <stability>stable</stability>
6
  <license>MIT License (MITL)</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Cloudinary - Image Management In The Cloud</summary>
10
  <description>Cloudinary supercharges your images! Upload images to the cloud, deliver optimized via a fast CDN, perform smart resizing and apply effects.</description>
11
- <notes> Release 2.6.0 notes:&#xD;
12
- - Admin UX improvements&#xD;
13
- - Add module reset feature&#xD;
14
- - Remove unfoldered migration option&#xD;
15
  </notes>
16
  <authors><author><name>Cloudinary</name><user>cloudinary</user><email>accounts+magento@cloudinary.com</email></author></authors>
17
- <date>2017-06-14</date>
18
- <time>14:39:29</time>
19
- <contents><target name="magecommunity"><dir name="Cloudinary"><dir name="Cloudinary"><dir name="Block"><dir name="Adminhtml"><dir name="Log"><file name="Grid.php" hash="1f8c277b31e21a8d28bcb57716a9a1f7"/></dir><file name="Log.php" hash="d76ab8c1f2ab39137a2726437c6e487a"/><dir name="Manage"><file name="Grid.php" hash="b6a05f6ba08c5ba0d08846a7b0a06776"/></dir><file name="Manage.php" hash="c17b5839709263d544b7e27dac52da45"/><dir name="Page"><file name="Menu.php" hash="891d6a4c075ba03c9a20658076c86ad0"/></dir><dir name="Reset"><dir name="Edit"><file name="Form.php" hash="059109b8230f9404921fb53660fdb228"/></dir><file name="Edit.php" hash="6944d440bcedcef8d8d118ecb2e61019"/></dir><dir name="System"><dir name="Config"><dir name="Form"><file name="Free.php" hash="33a3aff8e241d6ca142c6dfb59c1a90b"/></dir><file name="Signup.php" hash="ed6accbe7a4ce16bb0679eaf0c2dbb22"/></dir></dir></dir></dir><dir name="Helper"><file name="Autoloader.php" hash="393b3e2fc25e63ca28157152d2542b18"/><file name="Console.php" hash="7c909e3226c51c05d6da1f6ff9cbbfc9"/><file name="Cron.php" hash="805557370a2006b15444b7a62bbbc65a"/><file name="Data.php" hash="42c9d44f1bbe530e30cf5379846dea65"/><file name="Image.php" hash="af1c1d734793d6b08feaa7e1abd591d0"/><file name="Reset.php" hash="a7baf65e9478dc8202971c22fa383b57"/></dir><dir name="Model"><dir name="AutoUploadMapping"><file name="Configuration.php" hash="a9c2e1176ec36cea6f5183b24793dc2d"/></dir><dir name="Catalog"><dir name="Product"><file name="Image.php" hash="b5d14bcb836158890152c9fed191f8bc"/><dir name="Media"><file name="Config.php" hash="c2dbac447d4a22c920c19b0d4eb2672e"/></dir><file name="Media.php" hash="05726616a07d7d08933e9654e6107283"/></dir></dir><dir name="Cms"><dir name="Adminhtml"><dir name="Template"><file name="Filter.php" hash="792893f6b4e884a8e42847d457a6068c"/></dir></dir><file name="Synchronisation.php" hash="8d830a18f169a0ff5f7d865e3afcb710"/><dir name="Template"><file name="Filter.php" hash="c3fe64f98128043de13e92156a26ab02"/></dir><file name="Uploader.php" hash="021195c01a7e6fd9e72c5a30ebd11554"/><dir name="Wysiwyg"><dir name="Images"><file name="Storage.php" hash="0d23e557d6db06308886d9307fe92665"/></dir></dir></dir><file name="CollectionCounter.php" hash="e69953aee5d966a3ec13d33533f017e0"/><file name="Configuration.php" hash="66d648cf736d5410f26fd15f12d6f9c7"/><file name="Cron.php" hash="a7296d26862df0d382023d33496bb80a"/><dir name="Exception"><file name="BadFilePathException.php" hash="68135da8dfe2f0589a531b4bd36e3330"/></dir><file name="Image.php" hash="84d42417651e2feefdb1b0c048f61ca4"/><file name="Logger.php" hash="19f93cb1c0276bc522749ef60c03c351"/><file name="MagentoFolderTranslator.php" hash="37219fc1804d6ad8d1686af8509e1963"/><file name="Migration.php" hash="30f671877307d93904fd823d01d35c1d"/><file name="MigrationError.php" hash="67eca6725679a5dae6eab65efae39c64"/><file name="Observer.php" hash="e6bedc4a11bb83020aa906a39c19e04d"/><dir name="Resource"><dir name="Cms"><dir name="Synchronisation"><file name="Collection.php" hash="226db91ad96a348f0d937781358f9dec"/></dir></dir><dir name="Media"><file name="Collection.php" hash="f54d914a6f79c7b3ab51f822bf64de39"/></dir><file name="Migration.php" hash="69a545d0627016afc03ea097641aa749"/><dir name="MigrationError"><file name="Collection.php" hash="3c5ef530b18b4cd7763a610b84cd3d41"/></dir><file name="MigrationError.php" hash="e6de24a80cb0daed6ead44c699dce535"/><dir name="Synchronisation"><file name="Collection.php" hash="d16275121feb30e57b9b54122e26f05c"/></dir><file name="Synchronisation.php" hash="5b721d854d8f89bc3310e46081be7153"/></dir><file name="Synchronisation.php" hash="05414c5959efc7656b8e101617005d9a"/><file name="SynchronisedMediaUnifier.php" hash="4467ead90fe094ecbea9657266984492"/><file name="SynchronizationChecker.php" hash="35e9c5ad347357d92e921e65056303a6"/><dir name="System"><dir name="Config"><file name="Free.php" hash="a4c47b0b5d60d2e40d12975c98d69eae"/><dir name="Source"><dir name="Dropdown"><file name="Dpr.php" hash="2b9bfd5f836dbdb5d7224d298264f540"/><file name="Gravity.php" hash="c241498e2093640892170673cd7550cd"/><file name="Quality.php" hash="09920e6156a1d6088879cdcea616e312"/></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="CloudinaryController.php" hash="c3402e1e9797ecd9b18068b0eb33ee8f"/><file name="CloudinaryajaxController.php" hash="dbc6b59db79182a6e9069d4a63bc0c0d"/><file name="CloudinarylogController.php" hash="6178610f821e3d2a51985c45136b8ab1"/><file name="CloudinaryresetController.php" hash="c86108b6f9deaef13bbbc7a021bcd277"/></dir></dir><dir name="data"><dir name="cloudinary_setup"><file name="data-upgrade-0.1.0-0.1.1.php" hash="4c6ce6cd9ab0d94654afb4a398fb3d6c"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="ce3689d26ca0e8a4b74ce683c245e716"/><file name="config.xml" hash="89b5ca0bb42210eeefe3e35e3d68003e"/><file name="system.xml" hash="43325a790e33ceffde1429f588395cc1"/></dir><dir name="sql"><dir name="cloudinary_setup"><file name="install-0.1.0.php" hash="55d93b3dab573c2a932edbb5a2fa4865"/><file name="upgrade-0.1.0-0.1.1.php" hash="6c8d430fbf7b9714586b67db3d455008"/><file name="upgrade-1.1.3-1.1.4.php" hash="d6314fc1843b2061d0d04ae60c4d8091"/><file name="upgrade-1.1.4-1.1.5.php" hash="5b035e4b600cbbc743e9ff6a7b505230"/><file name="upgrade-1.1.5-1.1.6.php" hash="323c5e50635018be420cf524072f6a92"/><file name="upgrade-2.0.0-2.1.0.php" hash="9d053bed5099e064eed808a090755b03"/><file name="upgrade-2.1.0-2.5.0.php" hash="641c9aae29e22a54f52c6913e874cd56"/><file name="upgrade-2.5.0-2.6.0.php" hash="b38da8fbc177b9a64e3ba25fca434d00"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Cloudinary_Cloudinary.xml" hash="9337962a4ccf8a43164d5d71dfd2d756"/></dir></target><target name="magelib"><dir name="CloudinaryExtension"><dir name="AutoUploadMapping"><file name="ApiClient.php" hash="c37bfa114f18192ad34422a277c86afa"/><file name="Configuration.php" hash="0c28915836a4d7ba4390f2831c86aa6f"/><file name="RequestProcessor.php" hash="ef82cf531a21b4879b9facadd8085070"/></dir><file name="Cloud.php" hash="59b0debf9ae297e4e824e39ba819b1d1"/><file name="CloudinaryImageManager.php" hash="94af20e7b144adc4a27ee011aabbefe3"/><file name="CloudinaryImageProvider.php" hash="c4199a5384e6c42316ab4c5c74ed35e3"/><file name="ConfigurationBuilder.php" hash="c8832b207d9228ef14b3c74100ee74c4"/><file name="ConfigurationInterface.php" hash="4129b1e282fb0000b78946f07baa740c"/><file name="CredentialValidator.php" hash="965b0bd024f668aabcc9f30ef2e3c240"/><file name="Credentials.php" hash="71054eb4af7b6496608ffd14912bdbe4"/><dir name="Exception"><file name="ApiError.php" hash="d6fb1e32ca96183e9800c3706de37206"/><file name="FileExists.php" hash="6969387c67deef15a378cb94b9d269ac"/><file name="InvalidCredentials.php" hash="abecc635a25f6c9896c605ad16e1f7d7"/><file name="MigrationError.php" hash="92ea7aa65f4e14e606fa107d33f3ad30"/></dir><file name="FolderTranslator.php" hash="19a335acf751d67bd7efe46829602490"/><dir name="Image"><file name="ImageFactory.php" hash="0a2e066331584d33a9c4ec03787fd6e5"/><file name="LocalImage.php" hash="ab9b814b1a006baf05b9904af3ebce74"/><file name="Synchronizable.php" hash="b842f71ed25718838233207b7748f1bf"/><file name="SynchronizationChecker.php" hash="f2c45545766a81fede68138cf84dd1af"/><dir name="Transformation"><file name="Crop.php" hash="84e57281780a57326c938ac776641e8b"/><file name="Dimensions.php" hash="86a36c564aa41a08da2cf383d611c060"/><file name="Dpr.php" hash="f78cd1bfabaf3088ca8d4af972bfd453"/><file name="FetchFormat.php" hash="c745a6d80b509755cb6ae9fe37b95d76"/><file name="Freeform.php" hash="fdcbcea659f8908af54f30492b306fb5"/><file name="Gravity.php" hash="c1c2adf4dbbeaa6b06d67d2014300559"/><file name="Quality.php" hash="23a857f3910aecf6e45645194ff7f54e"/></dir><file name="Transformation.php" hash="35d6080fe0824517319164f3ba4edb44"/></dir><file name="Image.php" hash="3090cfbaa3b2a90b5ef4a2a94b165581"/><file name="ImageInterface.php" hash="4a7c7e39d7fda0b0fa99affcac78ec8c"/><file name="ImageProvider.php" hash="a615c472cdc8a6ad7d887133db35c262"/><dir name="Migration"><file name="BatchUploader.php" hash="87d9dcf1c07fb9975283d7e4f577f1b9"/><file name="Logger.php" hash="648b47bb065de0c81b386ac300b4f9a3"/><file name="Queue.php" hash="add92864192b0950c29c91ffe5e5a3ee"/><file name="SynchronizedMediaRepository.php" hash="6b4e07f253aad9b845c68d51a1ab4166"/><file name="Task.php" hash="ac11d06c531d48b38cf88f6e8f2bdc19"/></dir><dir name="Security"><file name="ApiSignature.php" hash="049c7db2684ec2a6cf5bb4efcd064951"/><file name="CloudinaryEnvironmentVariable.php" hash="418af61bdbcfef955df29ac47c54415b"/><file name="ConsoleUrl.php" hash="4e748cfe0f5a0aeab2307c623179c6f9"/><file name="EnvironmentVariable.php" hash="297fa60b819ffc028b9a32dae6eef63d"/><file name="Key.php" hash="ac3a50b59f2a7db1edcf30386759c7ec"/><file name="Secret.php" hash="b1010679976575d57752dbb07f1b94ed"/><file name="SignedConsoleUrl.php" hash="791e1f1080be23423c2ad87f431f6221"/></dir><file name="SynchroniseAssetsRepositoryInterface.php" hash="e0d8e270ae2c74214e82e53e04e3dc0f"/><file name="UploadConfig.php" hash="a68f1ea7b84574ec36a8d2fac9bd6054"/><file name="UploadResponseValidator.php" hash="2d20dba12898b277b20b010d24f18859"/><file name="UrlGenerator.php" hash="06d223e5628c68570a2af4f8fb2306ce"/><file name="ValidateRemoteUrlRequest.php" hash="c2e2eb712e5293ad508a23610dfbbd6d"/></dir><dir name="Cloudinary"><file name="Api.php" hash="d71322346c3625db7c3563cdad191e8c"/><file name="AuthToken.php" hash="bec8b856baf85d89a249c932c3eba39f"/><file name="Cloudinary.php" hash="f2ec7b7bc8fc7c978f7773c3d4ccc5dd"/><file name="CloudinaryField.php" hash="411714580d21b58115ab07737367173a"/><file name="Helpers.php" hash="4db8371fc84d34be49c8ea04eee7d6eb"/><file name="PreloadedFile.php" hash="73cc9e276f96553814f05eae592d11ee"/><file name="Uploader.php" hash="eae92a330d19654028a8d16410616421"/><file name="cacert.pem" hash="c4290b9deb70d0bef2f88b67fc68c8ec"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="cloudinary"><file name="cloudinary.xml" hash="871fd14e699e5ee23d2a44cd2332abd7"/></dir></dir><dir name="template"><dir name="cloudinary"><file name="log.phtml" hash="ca027cf9501afc17dda51355c0243771"/><file name="manage.phtml" hash="7f20f5013e2a716561f445636f3bed13"/><file name="reset.phtml" hash="6c13650ef05118b7fd06b0907c7a34ae"/><dir name="system"><dir name="config"><file name="free.phtml" hash="77ed47576496e0b28ff4eaf155ded5b6"/><file name="signup.phtml" hash="2a0e06990eb542f22531ac2ebb5996f5"/></dir></dir></dir></dir></dir></dir></dir></target></contents>
20
  <compatible/>
21
  <dependencies><required><php><min>5.4.0</min><max>7.1.0</max></php></required></dependencies>
22
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Cloudinary_Cloudinary</name>
4
+ <version>2.7.0</version>
5
  <stability>stable</stability>
6
  <license>MIT License (MITL)</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>Cloudinary - Image Management In The Cloud</summary>
10
  <description>Cloudinary supercharges your images! Upload images to the cloud, deliver optimized via a fast CDN, perform smart resizing and apply effects.</description>
11
+ <notes> Release 2.7.0 notes:&#xD;
12
+ - Support free transform chained transformations&#xD;
13
+ - Set format and quality defaults to auto&#xD;
 
14
  </notes>
15
  <authors><author><name>Cloudinary</name><user>cloudinary</user><email>accounts+magento@cloudinary.com</email></author></authors>
16
+ <date>2017-06-19</date>
17
+ <time>09:49:48</time>
18
+ <contents><target name="magecommunity"><dir name="Cloudinary"><dir name="Cloudinary"><dir name="Block"><dir name="Adminhtml"><dir name="Log"><file name="Grid.php" hash="1f8c277b31e21a8d28bcb57716a9a1f7"/></dir><file name="Log.php" hash="d76ab8c1f2ab39137a2726437c6e487a"/><dir name="Manage"><file name="Grid.php" hash="b6a05f6ba08c5ba0d08846a7b0a06776"/></dir><file name="Manage.php" hash="c17b5839709263d544b7e27dac52da45"/><dir name="Page"><file name="Menu.php" hash="891d6a4c075ba03c9a20658076c86ad0"/></dir><dir name="Reset"><dir name="Edit"><file name="Form.php" hash="059109b8230f9404921fb53660fdb228"/></dir><file name="Edit.php" hash="6944d440bcedcef8d8d118ecb2e61019"/></dir><dir name="System"><dir name="Config"><dir name="Form"><file name="Free.php" hash="33a3aff8e241d6ca142c6dfb59c1a90b"/></dir><file name="Signup.php" hash="ed6accbe7a4ce16bb0679eaf0c2dbb22"/></dir></dir></dir></dir><dir name="Helper"><file name="Autoloader.php" hash="393b3e2fc25e63ca28157152d2542b18"/><file name="Config.php" hash="737331dc824063845b8b908c0d18f04c"/><file name="Console.php" hash="7c909e3226c51c05d6da1f6ff9cbbfc9"/><file name="Cron.php" hash="805557370a2006b15444b7a62bbbc65a"/><file name="Data.php" hash="42c9d44f1bbe530e30cf5379846dea65"/><file name="Image.php" hash="af1c1d734793d6b08feaa7e1abd591d0"/><file name="Reset.php" hash="a7baf65e9478dc8202971c22fa383b57"/></dir><dir name="Model"><dir name="AutoUploadMapping"><file name="Configuration.php" hash="a9c2e1176ec36cea6f5183b24793dc2d"/></dir><dir name="Catalog"><dir name="Product"><file name="Image.php" hash="b5d14bcb836158890152c9fed191f8bc"/><dir name="Media"><file name="Config.php" hash="c2dbac447d4a22c920c19b0d4eb2672e"/></dir><file name="Media.php" hash="05726616a07d7d08933e9654e6107283"/></dir></dir><dir name="Cms"><dir name="Adminhtml"><dir name="Template"><file name="Filter.php" hash="792893f6b4e884a8e42847d457a6068c"/></dir></dir><file name="Synchronisation.php" hash="8d830a18f169a0ff5f7d865e3afcb710"/><dir name="Template"><file name="Filter.php" hash="c3fe64f98128043de13e92156a26ab02"/></dir><file name="Uploader.php" hash="69d6855309eb35d78c532e4789d6d526"/><dir name="Wysiwyg"><dir name="Images"><file name="Storage.php" hash="0d23e557d6db06308886d9307fe92665"/></dir></dir></dir><file name="CollectionCounter.php" hash="e69953aee5d966a3ec13d33533f017e0"/><file name="Configuration.php" hash="66d648cf736d5410f26fd15f12d6f9c7"/><file name="Cron.php" hash="a7296d26862df0d382023d33496bb80a"/><dir name="Exception"><file name="BadFilePathException.php" hash="68135da8dfe2f0589a531b4bd36e3330"/></dir><file name="Image.php" hash="d9ff80e2bf61fdad36a496437ff2ee1d"/><file name="Logger.php" hash="59671974f707abbed687e88f8d6a3b35"/><file name="MagentoFolderTranslator.php" hash="37219fc1804d6ad8d1686af8509e1963"/><file name="Migration.php" hash="30f671877307d93904fd823d01d35c1d"/><file name="MigrationError.php" hash="67eca6725679a5dae6eab65efae39c64"/><dir name="Observer"><file name="Config.php" hash="4f07c81f36b2d198673627b4bca12e39"/><file name="Product.php" hash="e52cf2454b7ccb23f1a0cbc7c2cd8a6b"/><file name="System.php" hash="29a76486ce525dbd844935b5b8000835"/></dir><dir name="Resource"><dir name="Cms"><dir name="Synchronisation"><file name="Collection.php" hash="226db91ad96a348f0d937781358f9dec"/></dir></dir><dir name="Media"><file name="Collection.php" hash="f54d914a6f79c7b3ab51f822bf64de39"/></dir><file name="Migration.php" hash="69a545d0627016afc03ea097641aa749"/><dir name="MigrationError"><file name="Collection.php" hash="3c5ef530b18b4cd7763a610b84cd3d41"/></dir><file name="MigrationError.php" hash="e6de24a80cb0daed6ead44c699dce535"/><dir name="Synchronisation"><file name="Collection.php" hash="d16275121feb30e57b9b54122e26f05c"/></dir><file name="Synchronisation.php" hash="5b721d854d8f89bc3310e46081be7153"/></dir><file name="Synchronisation.php" hash="05414c5959efc7656b8e101617005d9a"/><file name="SynchronisedMediaUnifier.php" hash="4467ead90fe094ecbea9657266984492"/><file name="SynchronizationChecker.php" hash="35e9c5ad347357d92e921e65056303a6"/><dir name="System"><dir name="Config"><file name="Free.php" hash="a4c47b0b5d60d2e40d12975c98d69eae"/><dir name="Source"><dir name="Dropdown"><file name="Dpr.php" hash="2b9bfd5f836dbdb5d7224d298264f540"/><file name="Gravity.php" hash="c241498e2093640892170673cd7550cd"/><file name="Quality.php" hash="09920e6156a1d6088879cdcea616e312"/></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="CloudinaryController.php" hash="2dede30a95297addc9a4542ce758262d"/><file name="CloudinaryajaxController.php" hash="b862b92cacb10cc81b2edb03a010b5e6"/><file name="CloudinarylogController.php" hash="6178610f821e3d2a51985c45136b8ab1"/><file name="CloudinaryresetController.php" hash="c86108b6f9deaef13bbbc7a021bcd277"/></dir></dir><dir name="data"><dir name="cloudinary_setup"><file name="data-upgrade-0.1.0-0.1.1.php" hash="4c6ce6cd9ab0d94654afb4a398fb3d6c"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="ce3689d26ca0e8a4b74ce683c245e716"/><file name="config.xml" hash="eec85d1de7212e3c024bb55e31258089"/><file name="system.xml" hash="43325a790e33ceffde1429f588395cc1"/></dir><dir name="sql"><dir name="cloudinary_setup"><file name="install-0.1.0.php" hash="55d93b3dab573c2a932edbb5a2fa4865"/><file name="upgrade-0.1.0-0.1.1.php" hash="6c8d430fbf7b9714586b67db3d455008"/><file name="upgrade-1.1.3-1.1.4.php" hash="d6314fc1843b2061d0d04ae60c4d8091"/><file name="upgrade-1.1.4-1.1.5.php" hash="5b035e4b600cbbc743e9ff6a7b505230"/><file name="upgrade-1.1.5-1.1.6.php" hash="323c5e50635018be420cf524072f6a92"/><file name="upgrade-2.0.0-2.1.0.php" hash="9d053bed5099e064eed808a090755b03"/><file name="upgrade-2.1.0-2.5.0.php" hash="641c9aae29e22a54f52c6913e874cd56"/><file name="upgrade-2.5.0-2.6.0.php" hash="b38da8fbc177b9a64e3ba25fca434d00"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Cloudinary_Cloudinary.xml" hash="9337962a4ccf8a43164d5d71dfd2d756"/></dir></target><target name="magelib"><dir name="CloudinaryExtension"><dir name="AutoUploadMapping"><file name="ApiClient.php" hash="cc7417a53b73c92509736959727cc3d9"/><file name="Configuration.php" hash="0c28915836a4d7ba4390f2831c86aa6f"/><file name="RequestProcessor.php" hash="ef82cf531a21b4879b9facadd8085070"/></dir><file name="Cloud.php" hash="59b0debf9ae297e4e824e39ba819b1d1"/><file name="CloudinaryImageManager.php" hash="94af20e7b144adc4a27ee011aabbefe3"/><file name="CloudinaryImageProvider.php" hash="c13ba73cc22f2e7c738676f746d146bc"/><file name="ConfigurationBuilder.php" hash="c8832b207d9228ef14b3c74100ee74c4"/><file name="ConfigurationInterface.php" hash="4129b1e282fb0000b78946f07baa740c"/><file name="CredentialValidator.php" hash="965b0bd024f668aabcc9f30ef2e3c240"/><file name="Credentials.php" hash="71054eb4af7b6496608ffd14912bdbe4"/><dir name="Exception"><file name="ApiError.php" hash="d6fb1e32ca96183e9800c3706de37206"/><file name="FileExists.php" hash="6969387c67deef15a378cb94b9d269ac"/><file name="InvalidCredentials.php" hash="abecc635a25f6c9896c605ad16e1f7d7"/><file name="MigrationError.php" hash="92ea7aa65f4e14e606fa107d33f3ad30"/></dir><file name="FolderTranslator.php" hash="19a335acf751d67bd7efe46829602490"/><dir name="Image"><file name="ImageFactory.php" hash="0a2e066331584d33a9c4ec03787fd6e5"/><file name="LocalImage.php" hash="ab9b814b1a006baf05b9904af3ebce74"/><file name="Synchronizable.php" hash="b842f71ed25718838233207b7748f1bf"/><file name="SynchronizationChecker.php" hash="f2c45545766a81fede68138cf84dd1af"/><dir name="Transformation"><file name="Crop.php" hash="84e57281780a57326c938ac776641e8b"/><file name="Dimensions.php" hash="86a36c564aa41a08da2cf383d611c060"/><file name="Dpr.php" hash="f78cd1bfabaf3088ca8d4af972bfd453"/><file name="FetchFormat.php" hash="c745a6d80b509755cb6ae9fe37b95d76"/><file name="Freeform.php" hash="fdcbcea659f8908af54f30492b306fb5"/><file name="Gravity.php" hash="c1c2adf4dbbeaa6b06d67d2014300559"/><file name="Quality.php" hash="23a857f3910aecf6e45645194ff7f54e"/></dir><file name="Transformation.php" hash="f117d3117900e42d00a0e64461c2a771"/></dir><file name="Image.php" hash="3090cfbaa3b2a90b5ef4a2a94b165581"/><file name="ImageInterface.php" hash="4a7c7e39d7fda0b0fa99affcac78ec8c"/><file name="ImageProvider.php" hash="a615c472cdc8a6ad7d887133db35c262"/><dir name="Migration"><file name="BatchUploader.php" hash="87d9dcf1c07fb9975283d7e4f577f1b9"/><file name="Logger.php" hash="648b47bb065de0c81b386ac300b4f9a3"/><file name="Queue.php" hash="add92864192b0950c29c91ffe5e5a3ee"/><file name="SynchronizedMediaRepository.php" hash="6b4e07f253aad9b845c68d51a1ab4166"/><file name="Task.php" hash="ac11d06c531d48b38cf88f6e8f2bdc19"/></dir><dir name="Security"><file name="ApiSignature.php" hash="049c7db2684ec2a6cf5bb4efcd064951"/><file name="CloudinaryEnvironmentVariable.php" hash="418af61bdbcfef955df29ac47c54415b"/><file name="ConsoleUrl.php" hash="4e748cfe0f5a0aeab2307c623179c6f9"/><file name="EnvironmentVariable.php" hash="297fa60b819ffc028b9a32dae6eef63d"/><file name="Key.php" hash="ac3a50b59f2a7db1edcf30386759c7ec"/><file name="Secret.php" hash="b1010679976575d57752dbb07f1b94ed"/><file name="SignedConsoleUrl.php" hash="791e1f1080be23423c2ad87f431f6221"/></dir><file name="SynchroniseAssetsRepositoryInterface.php" hash="e0d8e270ae2c74214e82e53e04e3dc0f"/><file name="UploadConfig.php" hash="a68f1ea7b84574ec36a8d2fac9bd6054"/><file name="UploadResponseValidator.php" hash="2d20dba12898b277b20b010d24f18859"/><file name="UrlGenerator.php" hash="06d223e5628c68570a2af4f8fb2306ce"/><file name="ValidateRemoteUrlRequest.php" hash="c2e2eb712e5293ad508a23610dfbbd6d"/></dir><dir name="Cloudinary"><file name="Api.php" hash="6595974e7fe061bdbb343943c1a975b2"/><file name="AuthToken.php" hash="bec8b856baf85d89a249c932c3eba39f"/><file name="Cloudinary.php" hash="f9b22b842d8dcabfd291a4d3021286a3"/><file name="CloudinaryField.php" hash="411714580d21b58115ab07737367173a"/><file name="Helpers.php" hash="4db8371fc84d34be49c8ea04eee7d6eb"/><file name="PreloadedFile.php" hash="73cc9e276f96553814f05eae592d11ee"/><file name="Search.php" hash="775a02974591dc1b95a084c501a372cf"/><file name="Uploader.php" hash="485a4bc302b36c5f55e189f696019a33"/><file name="cacert.pem" hash="c4290b9deb70d0bef2f88b67fc68c8ec"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="cloudinary"><file name="cloudinary.xml" hash="871fd14e699e5ee23d2a44cd2332abd7"/></dir></dir><dir name="template"><dir name="cloudinary"><file name="log.phtml" hash="ca027cf9501afc17dda51355c0243771"/><file name="manage.phtml" hash="7f20f5013e2a716561f445636f3bed13"/><file name="reset.phtml" hash="6c13650ef05118b7fd06b0907c7a34ae"/><dir name="system"><dir name="config"><file name="free.phtml" hash="8b7cfc3cf8a2b6e86fbf71e3c49f902f"/><file name="signup.phtml" hash="2a0e06990eb542f22531ac2ebb5996f5"/></dir></dir></dir></dir></dir></dir></dir></target></contents>
19
  <compatible/>
20
  <dependencies><required><php><min>5.4.0</min><max>7.1.0</max></php></required></dependencies>
21
  </package>