Studioforty9_Recaptcha - Version 1.0.0

Version Notes

Tested on Magento versions: 1.8.0.0, 1.8.1.0, 1.9.0.1 and 1.9.1.0

Download this release

Release Info

Developer StudioForty9
Extension Studioforty9_Recaptcha
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

app/code/community/StudioForty9/Recaptcha/Block/Autorender.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Block_Autorender
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Block
20
+ */
21
+ class Studioforty9_Recaptcha_Block_Autorender extends Mage_Core_Block_Template
22
+ {
23
+ /**
24
+ * Get the reCAPTACHA javascript code.
25
+ *
26
+ * @return string
27
+ */
28
+ public function getRecaptchaScript()
29
+ {
30
+ if (! Mage::helper('studioforty9_recaptcha')->isEnabled()) {
31
+ return '';
32
+ }
33
+
34
+ return '<script src="https://www.google.com/recaptcha/api.js"></script>';
35
+ }
36
+
37
+ /**
38
+ * Get the reCAPTCHA html code.
39
+ *
40
+ * @return string
41
+ */
42
+ public function getRecaptchaHtml()
43
+ {
44
+ /** @var Studioforty9_Recaptcha_Helper_Data $helper */
45
+ $helper = Mage::helper('studioforty9_recaptcha');
46
+
47
+ if (! $helper->isEnabled()) {
48
+ return '';
49
+ }
50
+
51
+ $html = sprintf(
52
+ '<div class="g-recaptcha" data-theme="%s" data-sitekey="%s"></div>',
53
+ $helper->getTheme(),
54
+ $helper->getSiteKey()
55
+ );
56
+
57
+ return $html;
58
+ }
59
+ }
app/code/community/StudioForty9/Recaptcha/Helper/Data.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Helper_Data
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Helper
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Helper_Data extends Mage_Core_Helper_Abstract
23
+ {
24
+ const MODULE_ENABLED = 'google/recaptcha/enabled';
25
+ const MODULE_KEY_SITE = 'google/recaptcha/site_key';
26
+ const MODULE_KEY_SECRET = 'google/recaptcha/secret_key';
27
+ const MODULE_KEY_THEME = 'google/recaptcha/theme';
28
+
29
+ /**
30
+ * Is the module enabled in configuration.
31
+ *
32
+ * @codeCoverageIgnore
33
+ * @return bool
34
+ */
35
+ public function isEnabled()
36
+ {
37
+ return (bool) Mage::getStoreConfig(self::MODULE_ENABLED);
38
+ }
39
+
40
+ /**
41
+ * The recaptcha site key.
42
+ *
43
+ * @codeCoverageIgnore
44
+ * @return string
45
+ */
46
+ public function getSiteKey()
47
+ {
48
+ return Mage::getStoreConfig(self::MODULE_KEY_SITE);
49
+ }
50
+
51
+ /**
52
+ * The recaptcha secret key.
53
+ *
54
+ * @codeCoverageIgnore
55
+ * @return string
56
+ */
57
+ public function getSecretKey()
58
+ {
59
+ return Mage::getStoreConfig(self::MODULE_KEY_SECRET);
60
+ }
61
+
62
+ /**
63
+ * The recaptcha widget theme.
64
+ *
65
+ * @codeCoverageIgnore
66
+ * @return string
67
+ */
68
+ public function getTheme()
69
+ {
70
+ return Mage::getStoreConfig(self::MODULE_KEY_THEME);
71
+ }
72
+ }
app/code/community/StudioForty9/Recaptcha/Helper/Request.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Helper_Request
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Helper
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Helper_Request extends Mage_Core_Helper_Abstract
23
+ {
24
+ const REQUEST_URL = 'https://www.google.com/recaptcha/api/siteverify';
25
+ const REQUEST_RESPONSE = 'g-recaptcha-response';
26
+
27
+ /**
28
+ * @var Varien_Http_Client $_client
29
+ */
30
+ protected $_client;
31
+
32
+ /**
33
+ * Set the client to make the request to recaptca.
34
+ *
35
+ * @param Varien_Http_Client $client The http client to use
36
+ *
37
+ * @return $this
38
+ */
39
+ public function setHttpClient(Varien_Http_Client $client)
40
+ {
41
+ $this->_client = $client;
42
+ return $this;
43
+ }
44
+
45
+ /**
46
+ * Get the Http Client to use for the request to reCAPTCHA
47
+ *
48
+ * @return Varien_Http_Client
49
+ */
50
+ public function getHttpClient()
51
+ {
52
+ if (is_null($this->_client)) {
53
+ $this->_client = new Varien_Http_Client();
54
+ }
55
+
56
+ $this->_client->setUri(self::REQUEST_URL);
57
+
58
+ return $this->_client;
59
+ }
60
+
61
+ /**
62
+ * Verify the details of the recaptcha request.
63
+ *
64
+ * @return Studioforty9_Recaptcha_Helper_Response
65
+ */
66
+ public function verify()
67
+ {
68
+ $params = array(
69
+ 'secret' => $this->_getHelper()->getSecretKey(),
70
+ 'response' => $this->_getRequest()->getPost(self::REQUEST_RESPONSE),
71
+ 'remoteip' => $this->_getRequest()->getClientIp(true)
72
+ );
73
+
74
+ $client = $this->getHttpClient();
75
+ $client->setParameterGet($params);
76
+
77
+ $response = $client->request('GET');
78
+ $data = Mage::helper('core')->jsonDecode($response->getBody());
79
+
80
+ $errors = array();
81
+ if (array_key_exists('error-codes', $data)) {
82
+ $errors = $data['error-codes'];
83
+ }
84
+
85
+ return new Studioforty9_Recaptcha_Helper_Response($data['success'], $errors);
86
+ }
87
+
88
+ /**
89
+ * Get the module data helper.
90
+ *
91
+ * @codeCoverageIgnore
92
+ * @return Studioforty9_Recaptcha_Helper_Data
93
+ */
94
+ protected function _getHelper()
95
+ {
96
+ return Mage::helper('studioforty9_recaptcha');
97
+ }
98
+ }
app/code/community/StudioForty9/Recaptcha/Helper/Response.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Helper_Response
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Helper
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Helper_Response extends Mage_Core_Helper_Abstract
23
+ {
24
+ const MISSING_INPUT_SECRET = 'missing-input-secret';
25
+ const INVALID_INPUT_SECRET = 'invalid-input-secret';
26
+ const MISSING_INPUT_RESPONSE = 'missing-input-response';
27
+ const INVALID_INPUT_RESPONSE = 'invalid-input-response';
28
+
29
+ /**
30
+ * @var bool $_success
31
+ */
32
+ protected $_success = false;
33
+
34
+ /**
35
+ * @var array $_errorCodes
36
+ */
37
+ protected $_errorCodes = array();
38
+
39
+ /**
40
+ * @var array $_errorDescriptions
41
+ */
42
+ protected $_errorDescriptions = array(
43
+ self::MISSING_INPUT_SECRET => 'The secret parameter is missing.',
44
+ self::INVALID_INPUT_SECRET => 'The secret parameter is invalid or malformed.',
45
+ self::MISSING_INPUT_RESPONSE => 'The response parameter is missing.',
46
+ self::INVALID_INPUT_RESPONSE => 'The response parameter is invalid or malformed.'
47
+ );
48
+
49
+ /**
50
+ * The constructor allows for a shortcut method of setting the $success and
51
+ * $errorCodes properties.
52
+ *
53
+ * @param bool $success A boolean flag to determine success
54
+ * @param array $errorCodes An array of error codes
55
+ */
56
+ public function __construct($success, $errorCodes = array())
57
+ {
58
+ $this->setSuccess($success);
59
+ $this->setErrorCodes($errorCodes);
60
+ }
61
+
62
+ /**
63
+ * Set the success flag.
64
+ *
65
+ * @param bool $success A boolean flag to determine success
66
+ *
67
+ * @return $this
68
+ */
69
+ public function setSuccess($success)
70
+ {
71
+ $this->_success = $success;
72
+ return $this;
73
+ }
74
+
75
+ /**
76
+ * Set the array of error codes from the response.
77
+ *
78
+ * @param array $errorCodes An array of error codes
79
+ *
80
+ * @return $this
81
+ */
82
+ public function setErrorCodes($errorCodes)
83
+ {
84
+ $this->_errorCodes = $errorCodes;
85
+ return $this;
86
+ }
87
+
88
+ /**
89
+ * Is the response a success.
90
+ *
91
+ * @return bool
92
+ */
93
+ public function isSuccess()
94
+ {
95
+ return ($this->_success === true);
96
+ }
97
+
98
+ /**
99
+ * Is the response a failure.
100
+ *
101
+ * @return bool
102
+ */
103
+ public function isFailure()
104
+ {
105
+ return !$this->isSuccess();
106
+ }
107
+
108
+ /**
109
+ * Are there any errors passed in from the response.
110
+ *
111
+ * @return bool
112
+ */
113
+ public function hasErrors()
114
+ {
115
+ return !empty($this->_errorCodes);
116
+ }
117
+
118
+ /**
119
+ * An array of descriptive errors.
120
+ *
121
+ * @return array
122
+ */
123
+ public function getErrors()
124
+ {
125
+ $errors = array();
126
+ foreach ($this->_errorCodes as $errorCode) {
127
+ $errors[] = $this->getErrorDescription($errorCode);
128
+ }
129
+
130
+ return $errors;
131
+ }
132
+
133
+ /**
134
+ * Get the error description.
135
+ *
136
+ * @param string $errorCode The human readable translation of the error code
137
+ *
138
+ * @return string
139
+ */
140
+ public function getErrorDescription($errorCode)
141
+ {
142
+ if (!array_key_exists($errorCode, $this->_errorDescriptions)) {
143
+ return 'Unknown error.';
144
+ }
145
+
146
+ return $this->_errorDescriptions[$errorCode];
147
+ }
148
+ }
app/code/community/StudioForty9/Recaptcha/Model/Observer/Contacts.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Model_Observer_Contacts
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Model
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Model_Observer_Contacts
23
+ {
24
+ /**
25
+ * Run the event on the contacts module, index controller, post action
26
+ * pre dispatch observer.
27
+ *
28
+ * @param Varien_Event_Observer $observer The observer from the controller
29
+ *
30
+ * @return Varien_Event_Observer
31
+ */
32
+ public function onContactsPostPreDispatch(Varien_Event_Observer $observer)
33
+ {
34
+ if (!Mage::helper('studioforty9_recaptcha')->isEnabled()) {
35
+ return $observer;
36
+ }
37
+
38
+ /** @var Mage_Contacts_IndexController $controller */
39
+ $controller = $observer->getEvent()->getControllerAction();
40
+
41
+ /** @var Studioforty9_Recaptcha_Helper_Request $request */
42
+ $request = Mage::helper('studioforty9_recaptcha/request');
43
+ /** @var Studioforty9_Recaptcha_Helper_Response $response */
44
+ $response = $request->verify();
45
+
46
+ if ($response->isFailure()) {
47
+ Mage::getSingleton('core/session')->addError(
48
+ $response->__(
49
+ 'There was an error with the recaptcha code, please try again.'
50
+ )
51
+ );
52
+
53
+ if ($response->hasErrors()) {
54
+ $this->_logErrors($response);
55
+ }
56
+
57
+ $redirectUrl = $controller->getRequest()->getBaseUrl() . '/contacts';
58
+ $controller->getResponse()->setRedirect($redirectUrl)->sendResponse();
59
+ $controller->getRequest()->setDispatched(true);
60
+ $controller->setFlag(
61
+ '',
62
+ Mage_Core_Controller_Front_Action::FLAG_NO_DISPATCH,
63
+ true
64
+ );
65
+
66
+ return $controller;
67
+ }
68
+
69
+ return $observer;
70
+ }
71
+
72
+ /**
73
+ * Log the errors from Google reCAPTCHA to system.log
74
+ *
75
+ * @param Studioforty9_Recaptcha_Helper_Response $response The response helper
76
+ *
77
+ * @return void
78
+ */
79
+ protected function _logErrors(Studioforty9_Recaptcha_Helper_Response $response)
80
+ {
81
+ Mage::log(
82
+ sprintf(
83
+ 'reCAPTCHA Errors: %1$s',
84
+ implode(', ', $response->getErrors())
85
+ )
86
+ );
87
+ }
88
+ }
app/code/community/StudioForty9/Recaptcha/Model/Source/Theme.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Model_Source_Theme
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Model
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Model_Source_Theme
23
+ {
24
+ /**
25
+ * Return the options for setting the theme.
26
+ *
27
+ * @return array
28
+ */
29
+ public function toOptionArray()
30
+ {
31
+ return array(
32
+ 'light' => $this->_getDataHelper()->__('Light'),
33
+ 'dark' => $this->_getDataHelper()->__('Dark')
34
+ );
35
+ }
36
+
37
+ /**
38
+ * Fetch the data helper for the module.
39
+ *
40
+ * @codeCoverageIgnore
41
+ * @return Studioforty9_Recaptcha_Helper_Data
42
+ */
43
+ protected function _getDataHelper()
44
+ {
45
+ return Mage::helper('studioforty9_recaptcha');
46
+ }
47
+ }
app/code/community/StudioForty9/Recaptcha/Test/Block/Autorender.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Test_Block_Autorender
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Test
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Test_Block_Autorender extends EcomDev_PHPUnit_Test_Case
23
+ {
24
+ /** @var Studioforty9_Recaptcha_Block_Autorender */
25
+ protected $block;
26
+
27
+ public function setUp()
28
+ {
29
+ $this->block = new Studioforty9_Recaptcha_Block_Autorender();
30
+
31
+ parent::setUp();
32
+ }
33
+
34
+ protected function getMockDataHelper($enabled, $theme = 'light', $siteKey = '123456789', $secretKey = '987654321')
35
+ {
36
+ $helper = $this->getHelperMock('studioforty9_recaptcha', array(
37
+ 'isEnabled', 'getSiteKey', 'getSecretKey', 'getTheme'
38
+ ), false, array(), null, false);
39
+
40
+ $helper->expects($this->any())
41
+ ->method('isEnabled')
42
+ ->will($this->returnValue($enabled));
43
+
44
+
45
+ $helper->expects($this->any())
46
+ ->method('getSiteKey')
47
+ ->will($this->returnValue($siteKey));
48
+
49
+
50
+ $helper->expects($this->any())
51
+ ->method('getSecretKey')
52
+ ->will($this->returnValue($secretKey));
53
+
54
+
55
+ $helper->expects($this->any())
56
+ ->method('getTheme')
57
+ ->will($this->returnValue($theme));
58
+
59
+ return $helper;
60
+ }
61
+
62
+ public function test_getRecaptchaScript_returns_empty_string_when_module_disabled()
63
+ {
64
+ $dataHelper = $this->getMockDataHelper(false);
65
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
66
+
67
+ $expected = '';
68
+ $actual = $this->block->getRecaptchaScript();
69
+ $this->assertEquals($expected, $actual);
70
+ }
71
+
72
+ public function test_getRecaptchaScript_returns_script_tag_html_when_module_enabled()
73
+ {
74
+ $dataHelper = $this->getMockDataHelper(true);
75
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
76
+
77
+ $expected = '<script src="https://www.google.com/recaptcha/api.js"></script>';
78
+ $actual = $this->block->getRecaptchaScript();
79
+ $this->assertEquals($expected, $actual);
80
+ }
81
+
82
+ public function test_getRecaptchaHtml_returns_empty_string_when_module_disabled()
83
+ {
84
+ $dataHelper = $this->getMockDataHelper(false);
85
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
86
+
87
+ $expected = '';
88
+ $actual = $this->block->getRecaptchaHtml();
89
+ $this->assertEquals($expected, $actual);
90
+ }
91
+
92
+ public function test_getRecaptchaHtml_returns_expected_html_when_module_enabled_using_light_theme()
93
+ {
94
+ $dataHelper = $this->getMockDataHelper(true, 'light');
95
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
96
+
97
+ $theme = 'light';
98
+ $siteKey = '123456789';
99
+ $expected = sprintf('<div class="g-recaptcha" data-theme="%s" data-sitekey="%s"></div>', $theme, $siteKey);
100
+ $actual = $this->block->getRecaptchaHtml();
101
+ $this->assertEquals($expected, $actual);
102
+ }
103
+
104
+ public function test_getRecaptchaHtml_returns_expected_html_when_module_enabled_using_dark_theme()
105
+ {
106
+ $dataHelper = $this->getMockDataHelper(true, 'dark');
107
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
108
+
109
+ $theme = 'dark';
110
+ $siteKey = '123456789';
111
+ $expected = sprintf('<div class="g-recaptcha" data-theme="%s" data-sitekey="%s"></div>', $theme, $siteKey);
112
+ $actual = $this->block->getRecaptchaHtml();
113
+ $this->assertEquals($expected, $actual);
114
+ }
115
+ }
app/code/community/StudioForty9/Recaptcha/Test/Config/Module.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Test_Config_Module
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Test
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Test_Config_Module extends EcomDev_PHPUnit_Test_Case_Config
23
+ {
24
+
25
+ public function test_module_is_in_correct_code_pool()
26
+ {
27
+ $this->assertModuleCodePool('community');
28
+ }
29
+
30
+
31
+ public function test_module_version_is_correct()
32
+ {
33
+ $this->assertModuleVersion('1.0.0');
34
+ }
35
+
36
+
37
+ public function test_block_are_configured()
38
+ {
39
+ $this->assertBlockAlias('studioforty9_recaptcha/autorender', 'Studioforty9_Recaptcha_Block_Autorender');
40
+ }
41
+
42
+
43
+ public function test_models_are_configured()
44
+ {
45
+ $this->assertModelAlias('studioforty9_recaptcha/observer_contacts', 'Studioforty9_Recaptcha_Model_Observer_Contacts');
46
+ }
47
+
48
+
49
+ public function test_helpers_are_configured()
50
+ {
51
+ $this->assertHelperAlias('studioforty9_recaptcha/data', 'Studioforty9_Recaptcha_Helper_Data');
52
+ $this->assertHelperAlias('studioforty9_recaptcha/request', 'Studioforty9_Recaptcha_Helper_Request');
53
+ $this->assertHelperAlias('studioforty9_recaptcha/response', 'Studioforty9_Recaptcha_Helper_Response');
54
+ }
55
+
56
+
57
+ public function test_access_granted_for_config_acl()
58
+ {
59
+
60
+ $this->assertConfigNodeValue(
61
+ 'adminhtml/acl/resources/admin/children/system/children/config/children/studioforty9_recaptcha/title',
62
+ 'ReCaptcha Configuration Settings'
63
+ );
64
+ }
65
+
66
+ public function test_config_has_event_observer_defined()
67
+ {
68
+ $this->assertEventObserverDefined(
69
+ 'frontend',
70
+ 'controller_action_predispatch_contacts_index_post',
71
+ 'studioforty9_recaptcha/observer_contacts',
72
+ 'onContactsPostPreDispatch'
73
+ );
74
+ }
75
+
76
+ /*public function test_config_defaults()
77
+ {
78
+ $this->assertDefaultConfigValue('google/recaptcha/enabled', '0');
79
+ $this->assertDefaultConfigValue('google/recaptcha/site_key', '');
80
+ $this->assertDefaultConfigValue('google/recaptcha/secret_key', '');
81
+ $this->assertDefaultConfigValue('google/recaptcha/theme', 'light');
82
+ }*/
83
+
84
+ public function test_layout_updates_are_correct()
85
+ {
86
+ $this->assertLayoutFileDefined('frontend', 'studioforty9_recaptcha.xml', 'studioforty9_recaptcha');
87
+ $this->assertLayoutFileExists('frontend', 'studioforty9_recaptcha.xml', 'default', 'base');
88
+ }
89
+
90
+ public function test_translate_nodes_are_correct()
91
+ {
92
+ $this->assertConfigNodeValue(
93
+ 'frontend/translate/modules/studioforty9_recaptcha/files/default',
94
+ 'Studioforty9_Recaptcha.csv'
95
+ );
96
+ }
97
+ }
app/code/community/StudioForty9/Recaptcha/Test/Helper/Request.php ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Mock_Http_Client
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Test
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Mock_Http_Client extends Varien_Http_Client
23
+ {
24
+ protected function _trySetCurlAdapter()
25
+ {
26
+ $this->setAdapter(new Zend_Http_Client_Adapter_Test());
27
+ return $this;
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Studioforty9_Recaptcha_Test_Helper_Request
33
+ *
34
+ * @category Studioforty9
35
+ * @package Studioforty9_Recaptcha
36
+ * @subpackage Test
37
+ * @author StudioForty9 <info@studioforty9.com>
38
+ */
39
+ class Studioforty9_Recaptcha_Test_Helper_Request extends EcomDev_PHPUnit_Test_Case
40
+ {
41
+ /** @var Studioforty9_Recaptcha_Helper_Request $helper */
42
+ protected $helper;
43
+
44
+ /**
45
+ * Get a mock response object with the body value already set.
46
+ *
47
+ * @param string $body
48
+ * @return Zend_Http_Response
49
+ */
50
+ protected function getMockResponse($body)
51
+ {
52
+ $response = $this->getMockBuilder('Zend_Http_Response')
53
+ ->disableOriginalConstructor()
54
+ ->setMethods(array('getBody'))
55
+ ->getMock();
56
+
57
+ $response->expects($this->any())->method('getBody')->will($this->returnValue($body));
58
+
59
+ return $response;
60
+ }
61
+
62
+ /**
63
+ * Get a mock request object with the response value already set.
64
+ *
65
+ * @param string $response
66
+ * @return Mock_Http_Client
67
+ */
68
+ protected function getMockRequest($response)
69
+ {
70
+ $client = $this->getMockBuilder('Mock_Http_Client')
71
+ ->disableOriginalConstructor()
72
+ ->setMethods(array('request'))
73
+ ->getMock();
74
+
75
+ $client->expects($this->any())->method('request')->will($this->returnValue($response));
76
+
77
+ return $client;
78
+ }
79
+
80
+ public function setUp()
81
+ {
82
+ $this->helper = new Studioforty9_Recaptcha_Helper_Request();
83
+ }
84
+
85
+ public function test_getHttpClient_returns_expected_object_when_set()
86
+ {
87
+ $this->helper->setHttpClient(new Mock_Http_Client());
88
+ $this->assertInstanceOf('Mock_Http_Client', $this->helper->getHttpClient());
89
+ }
90
+
91
+ public function test_getHttpClient_returns_expected_object_when_not_set()
92
+ {
93
+ $this->assertInstanceOf('Varien_Http_Client', $this->helper->getHttpClient());
94
+ }
95
+
96
+ public function test_verify_with_missing_secret_key()
97
+ {
98
+ // Create a mock request object and replace the one stored in the registry
99
+ Mage::app()->getRequest()->setPost(Studioforty9_Recaptcha_Helper_Request::REQUEST_RESPONSE, 'test');
100
+ $mockResponse = $this->getMockResponse('{"success":false,"error-codes": ["missing-input-secret"]}');
101
+ $mockRequest = $this->getMockRequest($mockResponse);
102
+
103
+ // Create a mock client object and set it on the object
104
+ $this->helper->setHttpClient($mockRequest);
105
+ $response = $this->helper->verify();
106
+
107
+ $this->assertInstanceOf('Studioforty9_Recaptcha_Helper_Response', $response);
108
+ $this->assertFalse($response->isSuccess());
109
+ $this->assertTrue($response->hasErrors());
110
+ $errors = $response->getErrors();
111
+ $this->assertEquals('The secret parameter is missing.', $errors[0]);
112
+ }
113
+
114
+ public function test_verify_with_invalid_secret_key()
115
+ {
116
+ // Create a mock request object and replace the one stored in the registry
117
+ Mage::app()->getRequest()->setPost(Studioforty9_Recaptcha_Helper_Request::REQUEST_RESPONSE, 'test');
118
+ $mockResponse = $this->getMockResponse('{"success":false,"error-codes": ["invalid-input-secret"]}');
119
+ $mockRequest = $this->getMockRequest($mockResponse);
120
+
121
+ // Create a mock client object and set it on the object
122
+ $this->helper->setHttpClient($mockRequest);
123
+ $response = $this->helper->verify();
124
+
125
+ $this->assertInstanceOf('Studioforty9_Recaptcha_Helper_Response', $response);
126
+ $this->assertFalse($response->isSuccess());
127
+ $this->assertTrue($response->hasErrors());
128
+ $errors = $response->getErrors();
129
+ $this->assertEquals('The secret parameter is invalid or malformed.', $errors[0]);
130
+ }
131
+
132
+ public function test_verify_with_missing_input_response()
133
+ {
134
+ // Create a mock request object and replace the one stored in the registry
135
+ Mage::app()->getRequest()->setPost(Studioforty9_Recaptcha_Helper_Request::REQUEST_RESPONSE, 'test');
136
+ $mockResponse = $this->getMockResponse('{"success":false,"error-codes": ["missing-input-response"]}');
137
+ $mockRequest = $this->getMockRequest($mockResponse);
138
+
139
+ // Create a mock client object and set it on the object
140
+ $this->helper->setHttpClient($mockRequest);
141
+ $response = $this->helper->verify();
142
+
143
+ $this->assertInstanceOf('Studioforty9_Recaptcha_Helper_Response', $response);
144
+ $this->assertFalse($response->isSuccess());
145
+ $this->assertTrue($response->hasErrors());
146
+ $errors = $response->getErrors();
147
+ $this->assertEquals('The response parameter is missing.', $errors[0]);
148
+ }
149
+
150
+ public function test_verify_with_invalid_input_response()
151
+ {
152
+ // Create a mock request object and replace the one stored in the registry
153
+ Mage::app()->getRequest()->setPost(Studioforty9_Recaptcha_Helper_Request::REQUEST_RESPONSE, 'test');
154
+ $mockResponse = $this->getMockResponse('{"success":false,"error-codes": ["invalid-input-response"]}');
155
+ $mockRequest = $this->getMockRequest($mockResponse);
156
+
157
+ // Create a mock client object and set it on the object
158
+ $this->helper->setHttpClient($mockRequest);
159
+ $response = $this->helper->verify();
160
+
161
+ $this->assertInstanceOf('Studioforty9_Recaptcha_Helper_Response', $response);
162
+ $this->assertFalse($response->isSuccess());
163
+ $this->assertTrue($response->hasErrors());
164
+ $errors = $response->getErrors();
165
+ $this->assertEquals('The response parameter is invalid or malformed.', $errors[0]);
166
+ }
167
+ }
app/code/community/StudioForty9/Recaptcha/Test/Helper/Response.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Test_Helper_Response
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Test
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Test_Helper_Response extends EcomDev_PHPUnit_Test_Case
23
+ {
24
+ /** @var Studioforty9_Recaptcha_Helper_Response $helper */
25
+ protected $helper;
26
+
27
+ public function test_can_construct_with_success_true()
28
+ {
29
+ $helper = new Studioforty9_Recaptcha_Helper_Response(true);
30
+ $this->assertTrue($helper->isSuccess());
31
+ }
32
+
33
+ public function test_can_construct_with_success_false()
34
+ {
35
+ $helper = new Studioforty9_Recaptcha_Helper_Response(false);
36
+ $this->assertTrue($helper->isFailure());
37
+ }
38
+
39
+ public function test_error_code_strings_are_correct()
40
+ {
41
+ $this->assertEquals('missing-input-secret', Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_SECRET);
42
+ $this->assertEquals('invalid-input-secret', Studioforty9_Recaptcha_Helper_Response::INVALID_INPUT_SECRET);
43
+ $this->assertEquals('missing-input-response', Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_RESPONSE);
44
+ $this->assertEquals('invalid-input-response', Studioforty9_Recaptcha_Helper_Response::INVALID_INPUT_RESPONSE);
45
+ }
46
+
47
+ public function test_error_descriptions_are_correct()
48
+ {
49
+ $helper = new Studioforty9_Recaptcha_Helper_Response(false);
50
+
51
+ $this->assertEquals(
52
+ 'The secret parameter is missing.',
53
+ $helper->getErrorDescription(Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_SECRET)
54
+ );
55
+ $this->assertEquals(
56
+ 'The secret parameter is invalid or malformed.',
57
+ $helper->getErrorDescription(Studioforty9_Recaptcha_Helper_Response::INVALID_INPUT_SECRET)
58
+ );
59
+ $this->assertEquals(
60
+ 'The response parameter is missing.',
61
+ $helper->getErrorDescription(Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_RESPONSE)
62
+ );
63
+ $this->assertEquals(
64
+ 'The response parameter is invalid or malformed.',
65
+ $helper->getErrorDescription(Studioforty9_Recaptcha_Helper_Response::INVALID_INPUT_RESPONSE)
66
+ );
67
+ }
68
+
69
+ public function test_getErrorDescription_returns_unknown_error_string_when_something_unknown_is_passed_in()
70
+ {
71
+ $helper = new Studioforty9_Recaptcha_Helper_Response(false);
72
+ $this->assertEquals(
73
+ 'Unknown error.',
74
+ $helper->getErrorDescription('not a real error')
75
+ );
76
+ }
77
+
78
+ public function test_hasErrors_returns_false_when_constructed_with_no_errors()
79
+ {
80
+ $helper = new Studioforty9_Recaptcha_Helper_Response(false);
81
+ $this->assertFalse($helper->hasErrors());
82
+ }
83
+
84
+ public function test_hasErrors_returns_true_when_constructed_with_errors()
85
+ {
86
+ $helper = new Studioforty9_Recaptcha_Helper_Response(false, array(Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_RESPONSE));
87
+ $this->assertTrue($helper->hasErrors());
88
+ }
89
+
90
+ public function test_getErrors_returns_expected_descriptions()
91
+ {
92
+ $errorCodes = array(
93
+ Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_SECRET,
94
+ Studioforty9_Recaptcha_Helper_Response::INVALID_INPUT_SECRET,
95
+ Studioforty9_Recaptcha_Helper_Response::MISSING_INPUT_RESPONSE,
96
+ Studioforty9_Recaptcha_Helper_Response::INVALID_INPUT_RESPONSE
97
+ );
98
+ $helper = new Studioforty9_Recaptcha_Helper_Response(false, $errorCodes);
99
+ $errors = $helper->getErrors();
100
+
101
+ $this->assertCount(4, $errors);
102
+ $this->assertInternalType('array', $errors);
103
+ $this->assertEquals($errors[0], 'The secret parameter is missing.');
104
+ }
105
+ }
app/code/community/StudioForty9/Recaptcha/Test/Model/Observer/Contacts.php ADDED
@@ -0,0 +1,268 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Test_Model_Observer_Contacts
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Test
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Test_Model_Observer_Contacts extends EcomDev_PHPUnit_Test_Case
23
+ {
24
+ /** @var Studioforty9_Recaptcha_Model_Observer_Contacts $observer */
25
+ protected $observer;
26
+
27
+ /** @var Mage_Core_Model_Session $session */
28
+ protected $session;
29
+
30
+ public function setUp()
31
+ {
32
+ $this->session = $this->replaceSession('core/session');
33
+ $this->observer = new Studioforty9_Recaptcha_Model_Observer_Contacts();
34
+ }
35
+
36
+ public function test_onContactsPostPreDispatch_returns_observer_when_module_disabled()
37
+ {
38
+ $dataHelper = $this->getMockDataHelper();
39
+ $dataHelper->expects($this->once())->method('isEnabled')->will($this->returnValue(false));
40
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
41
+
42
+ $observer = $this->getMockObserver();
43
+ $result = $this->observer->onContactsPostPreDispatch($observer);
44
+
45
+ $this->assertInstanceOf('Varien_Event_Observer', $result);
46
+ }
47
+
48
+ public function test_onContactsPostPreDispatch_returns_observer_on_verify_success_when_module_enabled()
49
+ {
50
+ // Expect studioforty9_recaptcha::isEnabled to be called once
51
+ $dataHelper = $this->getMockDataHelper();
52
+ $dataHelper->expects($this->once())->method('isEnabled')->will($this->returnValue(true));
53
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
54
+
55
+ $responseHelper = new Studioforty9_Recaptcha_Helper_Response(true);
56
+
57
+ // Expect verify to be called once and return $responseHelper
58
+ $requestHelper = $this->getMockRequestHelper();
59
+ $requestHelper->expects($this->once())->method('verify')->will($this->returnValue($responseHelper));
60
+ $this->replaceByMock('helper', 'studioforty9_recaptcha/request', $requestHelper);
61
+
62
+ // Mock the controller object
63
+ $controller = $this->getMockController();
64
+ // Mock the event object
65
+ // Expect getControllerAction to be called once and return $controller
66
+ $event = $this->getMockEvent($controller);
67
+ // Mock the observer object
68
+ $observer = $this->getMockObserver();
69
+ // Expect getEvent to be called once and return the event object
70
+ $observer->expects($this->once())->method('getEvent')->will($this->returnValue($event));
71
+
72
+ // Call the onContactsPostPreDispatch method
73
+ $result = $this->observer->onContactsPostPreDispatch($observer);
74
+
75
+ $this->assertInstanceOf('Varien_Event_Observer', $result);
76
+ }
77
+
78
+ public function test_onContactsPostPreDispatch_returns_controller_on_verify_failed_with_module_enabled()
79
+ {
80
+ // Mock the data helper
81
+ $dataHelper = $this->getMockDataHelper();
82
+ // Expect isEnabled to called once and return true
83
+ $dataHelper->expects($this->once())->method('isEnabled')->will($this->returnValue(true));
84
+ $this->replaceByMock('helper', 'studioforty9_recaptcha', $dataHelper);
85
+
86
+ // Setup the expected response
87
+ $responseHelper = new Studioforty9_Recaptcha_Helper_Response(false, array('missing-input-response'));
88
+
89
+ // Mock the request helper
90
+ $requestHelper = $this->getMockRequestHelper();
91
+ // Expect verify to be called once and return the $responseHelper
92
+ $requestHelper->expects($this->once())->method('verify')->will($this->returnValue($responseHelper));
93
+ $this->replaceByMock('helper', 'studioforty9_recaptcha/request', $requestHelper);
94
+
95
+ // Mock the response object
96
+ $response = $this->getMockResponse();
97
+
98
+ // Expect setRedirect to be called once
99
+ // It should set the redirect url to the base url + /contacts
100
+ // And return the response object
101
+ $response->expects($this->once())
102
+ ->method('setRedirect')
103
+ ->with($this->equalTo(Mage::getBaseUrl() . '/contacts'))
104
+ ->will($this->returnSelf());
105
+
106
+ // Expect sendResponse to be called once
107
+ // And return the response object
108
+ $response->expects($this->once())
109
+ ->method('sendResponse')
110
+ ->will($this->returnSelf());
111
+
112
+ // Mock the request object
113
+ $request = $this->getMockRequest();
114
+
115
+ // Expect setDispatched to be called once
116
+ // It should set the value to true
117
+ // And return the request object
118
+ $request->expects($this->once())
119
+ ->method('setDispatched')
120
+ ->with($this->equalTo(true))
121
+ ->will($this->returnSelf());
122
+
123
+ // Expect getBaseUrl to be called once
124
+ // And return the base url of the website
125
+ $request->expects($this->once())
126
+ ->method('getBaseUrl')
127
+ ->will($this->returnValue(Mage::getBaseUrl()));
128
+
129
+ // Mock the controller object
130
+ $controller = $this->getMockController();
131
+
132
+ // Expect getResponse to be called once
133
+ // And return the response object
134
+ $controller->expects($this->once())
135
+ ->method('getResponse')
136
+ ->will($this->returnValue($response));
137
+
138
+ // Expect getRequest to be called twice
139
+ // 1. For getBaseUrl
140
+ // 2. For setDispatched
141
+ // And return the request object
142
+ $controller->expects($this->exactly(2))
143
+ ->method('getRequest')
144
+ ->will($this->returnValue($request));
145
+
146
+ // Expect setFlag to be called once
147
+ // It should set the following parameters:
148
+ // 1. $action : '' (empty string)
149
+ // 2. $flag : Mage_Core_Controller_Front_Action::FLAG_NO_DISPATCH ('no-dispatch')
150
+ // 3. $value : true
151
+ // And return the controller object
152
+ $controller->expects($this->once())
153
+ ->method('setFlag')
154
+ ->with(
155
+ $this->equalTo(''),
156
+ $this->equalTo(Mage_Core_Controller_Front_Action::FLAG_NO_DISPATCH),
157
+ $this->equalTo(true)
158
+ )
159
+ ->will($this->returnSelf());
160
+
161
+ // Mock the event object
162
+ $event = $this->getMockEvent($controller);
163
+
164
+ // Mock the observer object
165
+ $observer = $this->getMockObserver();
166
+
167
+ // Expect getEvent to be called once and return the event object
168
+ $observer->expects($this->once())->method('getEvent')->will($this->returnValue($event));
169
+
170
+ // Run the observer
171
+ $result = $this->observer->onContactsPostPreDispatch($observer);
172
+
173
+ // If all went to plan, we should have our controller back
174
+ $this->assertInstanceOf('Mage_Core_Controller_Front_Action', $result);
175
+
176
+ // Does the session have a new message?
177
+ $this->assertEquals(
178
+ 'There was an error with the recaptcha code, please try again.',
179
+ $this->session->getMessages()->getLastAddedMessage()->getCode()
180
+ );
181
+ }
182
+
183
+ /* ----- MOCK OBJECTS ----- */
184
+
185
+ protected function getMockResponse()
186
+ {
187
+ // Mock Response
188
+ $response = $this->getMockBuilder('Zend_Controller_Response_Abstract')
189
+ ->disableOriginalConstructor()
190
+ ->setMethods(array('setRedirect', 'sendResponse'))
191
+ ->getMock();
192
+
193
+ return $response;
194
+ }
195
+
196
+ protected function getMockRequest()
197
+ {
198
+ $request = $this->getMockBuilder('Zend_Controller_Request_Abstract')
199
+ ->disableOriginalConstructor()
200
+ ->setMethods(array('setDispatched', 'getBaseUrl'))
201
+ ->getMock();
202
+
203
+ return $request;
204
+ }
205
+
206
+ protected function getMockController()
207
+ {
208
+ // Mock Controller
209
+ $controller = $this->getMockBuilder('Mage_Core_Controller_Front_Action')
210
+ ->disableOriginalConstructor()
211
+ ->setMethods(array('getResponse', 'getRequest', 'setFlag'))
212
+ ->getMock();
213
+
214
+ return $controller;
215
+ }
216
+
217
+ protected function getMockObserver()
218
+ {
219
+ $observer = $this->getMockBuilder('Varien_Event_Observer')
220
+ ->disableOriginalConstructor()
221
+ ->setMethods(array('getEvent'))
222
+ ->getMock();
223
+
224
+ return $observer;
225
+ }
226
+
227
+ protected function getMockDataHelper()
228
+ {
229
+ $helper = $this->getHelperMock('studioforty9_recaptcha', array(
230
+ 'isEnabled', 'getSiteKey', 'getSecretKey', 'getTheme'
231
+ ), false, array(), null, false);
232
+
233
+ return $helper;
234
+ }
235
+
236
+ protected function getMockRequestHelper()
237
+ {
238
+ $helper = $this->getHelperMock('studioforty9_recaptcha/request', array('verify'), false, array(), null, false);
239
+
240
+ return $helper;
241
+ }
242
+
243
+ protected function getMockEvent($controller)
244
+ {
245
+ $event = $this->getMockBuilder('Varien_Event')
246
+ ->disableOriginalConstructor()
247
+ ->setMethods(array('getControllerAction'))
248
+ ->getMock();
249
+
250
+ $event->expects($this->once())
251
+ ->method('getControllerAction')
252
+ ->will($this->returnValue($controller));
253
+
254
+ return $event;
255
+ }
256
+
257
+ protected function replaceSession($type)
258
+ {
259
+ $session = $this->getModelMockBuilder($type)
260
+ ->disableOriginalConstructor()
261
+ ->setMethods(null)
262
+ ->getMock();
263
+
264
+ $this->replaceByMock('singleton', $type, $session);
265
+
266
+ return $session;
267
+ }
268
+ }
app/code/community/StudioForty9/Recaptcha/Test/Model/Source/Theme.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ */
13
+
14
+ /**
15
+ * Studioforty9_Recaptcha_Test_Model_Source_Theme
16
+ *
17
+ * @category Studioforty9
18
+ * @package Studioforty9_Recaptcha
19
+ * @subpackage Test
20
+ * @author StudioForty9 <info@studioforty9.com>
21
+ */
22
+ class Studioforty9_Recaptcha_Test_Model_Source_Theme extends EcomDev_PHPUnit_Test_Case
23
+ {
24
+ /** @var Studioforty9_Recaptcha_Model_Source_Theme $observer */
25
+ protected $model;
26
+
27
+ public function setUp()
28
+ {
29
+ $this->model = new Studioforty9_Recaptcha_Model_Source_Theme();
30
+ }
31
+
32
+ public function test_toOptionArray_returns_expected_array()
33
+ {
34
+ $options = $this->model->toOptionArray();
35
+
36
+ $this->assertArrayHasKey('light', $options);
37
+ $this->assertArrayHasKey('dark', $options);
38
+
39
+ $this->assertEquals('Light', $options['light']);
40
+ $this->assertEquals('Dark', $options['dark']);
41
+ }
42
+ }
app/code/community/StudioForty9/Recaptcha/etc/config.xml ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Studioforty9_Recaptcha
5
+ *
6
+ * @category Studioforty9
7
+ * @package Studioforty9_Recaptcha
8
+ * @author StudioForty9 <info@studioforty9.com>
9
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
10
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
11
+ * @version 1.0.0
12
+ * @link https://github.com/studioforty9/recaptcha
13
+ */
14
+ -->
15
+ <config>
16
+ <modules>
17
+ <Studioforty9_Recaptcha>
18
+ <version>1.0.0</version>
19
+ </Studioforty9_Recaptcha>
20
+ </modules>
21
+ <global>
22
+ <blocks>
23
+ <studioforty9_recaptcha>
24
+ <class>Studioforty9_Recaptcha_Block</class>
25
+ </studioforty9_recaptcha>
26
+ </blocks>
27
+ <helpers>
28
+ <studioforty9_recaptcha>
29
+ <class>Studioforty9_Recaptcha_Helper</class>
30
+ </studioforty9_recaptcha>
31
+ </helpers>
32
+ <models>
33
+ <studioforty9_recaptcha>
34
+ <class>Studioforty9_Recaptcha_Model</class>
35
+ </studioforty9_recaptcha>
36
+ </models>
37
+ </global>
38
+ <frontend>
39
+ <layout>
40
+ <updates>
41
+ <studioforty9_recaptcha>
42
+ <file>studioforty9_recaptcha.xml</file>
43
+ </studioforty9_recaptcha>
44
+ </updates>
45
+ </layout>
46
+ <translate>
47
+ <modules>
48
+ <studioforty9_recaptcha>
49
+ <files>
50
+ <default>Studioforty9_Recaptcha.csv</default>
51
+ </files>
52
+ </studioforty9_recaptcha>
53
+ </modules>
54
+ </translate>
55
+ <events>
56
+ <controller_action_predispatch_contacts_index_post>
57
+ <observers>
58
+ <studioforty9_recaptcha>
59
+ <class>studioforty9_recaptcha/observer_contacts</class>
60
+ <method>onContactsPostPreDispatch</method>
61
+ </studioforty9_recaptcha>
62
+ </observers>
63
+ </controller_action_predispatch_contacts_index_post>
64
+ </events>
65
+ </frontend>
66
+ <adminhtml>
67
+ <acl>
68
+ <resources>
69
+ <admin>
70
+ <children>
71
+ <system>
72
+ <children>
73
+ <config>
74
+ <children>
75
+ <studioforty9_recaptcha translate="title" module="studioforty9_recaptcha">
76
+ <title>ReCaptcha Configuration Settings</title>
77
+ </studioforty9_recaptcha>
78
+ </children>
79
+ </config>
80
+ </children>
81
+ </system>
82
+ </children>
83
+ </admin>
84
+ </resources>
85
+ </acl>
86
+ </adminhtml>
87
+ <default>
88
+ <google>
89
+ <recaptcha>
90
+ <enabled>0</enabled>
91
+ <site_key></site_key>
92
+ <secret_key></secret_key>
93
+ <theme>light</theme>
94
+ </recaptcha>
95
+ </google>
96
+ </default>
97
+ <phpunit>
98
+ <suite>
99
+ <modules>
100
+ <Studioforty9_Recaptcha/>
101
+ </modules>
102
+ </suite>
103
+ </phpunit>
104
+ </config>
app/code/community/StudioForty9/Recaptcha/etc/system.xml ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Studioforty9_Recaptcha
5
+ *
6
+ * @category Studioforty9
7
+ * @package Studioforty9_Recaptcha
8
+ * @author StudioForty9 <info@studioforty9.com>
9
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
10
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
11
+ * @version 1.0.0
12
+ * @link https://github.com/studioforty9/recaptcha
13
+ */
14
+ -->
15
+ <config>
16
+ <sections>
17
+ <google>
18
+ <groups>
19
+ <recaptcha translate="label title" module="studioforty9_recaptcha">
20
+ <label>Google ReCaptcha</label>
21
+ <frontend_type>text</frontend_type>
22
+ <sort_order>1000</sort_order>
23
+ <show_in_default>1</show_in_default>
24
+ <show_in_website>1</show_in_website>
25
+ <show_in_store>1</show_in_store>
26
+ <fields>
27
+ <enabled translate="label">
28
+ <label>Enabled</label>
29
+ <frontend_type>select</frontend_type>
30
+ <source_model>adminhtml/system_config_source_yesno</source_model>
31
+ <sort_order>10</sort_order>
32
+ <show_in_default>1</show_in_default>
33
+ <show_in_website>1</show_in_website>
34
+ <show_in_store>1</show_in_store>
35
+ </enabled>
36
+ <site_key translate="label">
37
+ <label>Site Key</label>
38
+ <frontend_type>text</frontend_type>
39
+ <sort_order>20</sort_order>
40
+ <show_in_default>1</show_in_default>
41
+ <show_in_website>1</show_in_website>
42
+ <show_in_store>1</show_in_store>
43
+ </site_key>
44
+ <secret_key translate="label">
45
+ <label>Secret Key</label>
46
+ <frontend_type>text</frontend_type>
47
+ <sort_order>30</sort_order>
48
+ <show_in_default>1</show_in_default>
49
+ <show_in_website>1</show_in_website>
50
+ <show_in_store>1</show_in_store>
51
+ </secret_key>
52
+ <theme translate="label">
53
+ <label>Theme</label>
54
+ <frontend_type>select</frontend_type>
55
+ <source_model>studioforty9_recaptcha/source_theme</source_model>
56
+ <sort_order>40</sort_order>
57
+ <show_in_default>1</show_in_default>
58
+ <show_in_website>1</show_in_website>
59
+ <show_in_store>1</show_in_store>
60
+ </theme>
61
+ </fields>
62
+ </recaptcha>
63
+ </groups>
64
+ </google>
65
+ </sections>
66
+ </config>
app/design/frontend/base/default/layout/studioforty9_recaptcha.xml ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Studioforty9_Recaptcha
5
+ *
6
+ * @category Studioforty9
7
+ * @package Studioforty9_Recaptcha
8
+ * @author StudioForty9 <info@studioforty9.com>
9
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
10
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
11
+ * @version 1.0.0
12
+ * @link https://github.com/studioforty9/recaptcha
13
+ */
14
+ -->
15
+ <layout version="0.1.0">
16
+
17
+ <contacts_index_index>
18
+ <reference name="contactForm">
19
+ <block type="studioforty9_recaptcha/autorender" name="studioforty9.recaptcha.autorender" template="studioforty9/recaptcha/autorender.phtml"/>
20
+ </reference>
21
+ </contacts_index_index>
22
+
23
+ </layout>
app/design/frontend/base/default/template/studioforty9/recaptcha/autorender.phtml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Studioforty9_Recaptcha
4
+ *
5
+ * @category Studioforty9
6
+ * @package Studioforty9_Recaptcha
7
+ * @author StudioForty9 <info@studioforty9.com>
8
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
9
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
10
+ * @version 1.0.0
11
+ * @link https://github.com/studioforty9/recaptcha
12
+ * @see Studioforty9_Recaptcha_Block_Autorender
13
+ */
14
+ ?>
15
+ <div class="recaptcha">
16
+ <?php echo $this->getRecaptchaHtml(); ?>
17
+ <?php echo $this->getRecaptchaScript(); ?>
18
+ </div>
app/etc/modules/Studioforty9_Recaptcha.xml ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * Studioforty9_Recaptcha
5
+ *
6
+ * @category Studioforty9
7
+ * @package Studioforty9_Recaptcha
8
+ * @author StudioForty9 <info@studioforty9.com>
9
+ * @copyright 2014 StudioForty9 (http://www.studioforty9.com)
10
+ * @license https://github.com/studioforty9/recaptcha/blob/master/LICENCE BSD
11
+ * @version 1.0.0
12
+ * @link https://github.com/studioforty9/recaptcha
13
+ */
14
+ -->
15
+ <config>
16
+ <modules>
17
+ <Studioforty9_Recaptcha>
18
+ <active>true</active>
19
+ <codePool>community</codePool>
20
+ </Studioforty9_Recaptcha>
21
+ </modules>
22
+ </config>
app/locale/en_US/Studioforty9_Recaptcha.csv ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ "There was an error with the recaptcha code, please try again.","There was an error with the recaptcha code, please try again."
2
+ "Light","Light"
3
+ "Dark","Dark"
package.xml ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Studioforty9_Recaptcha</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/BSD-3-Clause">BSDL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Google reCAPTCHA for the Contacts page form.</summary>
10
+ <description>&lt;h3&gt;Support and Feature Requests&lt;/h3&gt;&#xD;
11
+ &#xD;
12
+ https://github.com/studioforty9/recaptcha/issues&#xD;
13
+ &#xD;
14
+ &lt;h3&gt;How to Configure&lt;/h3&gt;&#xD;
15
+ &#xD;
16
+ &lt;ol&gt;&#xD;
17
+ &lt;li&gt;Once you've got the module installed, sign into your Google account and visit https://www.google.com/recaptcha.&lt;/li&gt;&#xD;
18
+ &lt;li&gt;Hit the "Get reCAPTCHA" link and you'll be taken to your account overview page. Register a new site by adding a label and any domains you want to allow for this specific reCAPTCHA widget.&lt;/li&gt;&#xD;
19
+ &lt;li&gt;Under 'Adding reCAPTCHA to your site' you should see 'Keys', specifically your 'Site Key' and 'Secret Key', copy and paste both keys into their respective configuration fields under 'System -&gt; Configuration -&gt; Sales -&gt; Google API -&gt; Google ReCaptcha'.&lt;/li&gt;&#xD;
20
+ &lt;li&gt;Copy the /contacts/form.phtml template over to your theme, if you haven't already done so, just above the `buttons-set` div paste in the following code:&lt;/li&gt;&#xD;
21
+ &lt;/ul&gt;&#xD;
22
+ &lt;?php echo $this-&gt;getChildHtml('studioforty9.recaptcha.autorender'); ?&gt;&#xD;
23
+ &#xD;
24
+ &#xD;
25
+ </description>
26
+ <notes>Tested on Magento versions: 1.8.0.0, 1.8.1.0, 1.9.0.1 and 1.9.1.0</notes>
27
+ <authors><author><name>StudioForty9</name><user>SF9</user><email>info@studioforty9.com</email></author><author><name>Eoghan O'Brien</name><user>eoghanobrien</user><email>eoghan@eoghanobrien.com</email></author></authors>
28
+ <date>2014-12-09</date>
29
+ <time>22:50:18</time>
30
+ <contents><target name="magecommunity"><dir name="StudioForty9"><dir name="Recaptcha"><dir name="Block"><file name="Autorender.php" hash="7a2e7003a75cff32829adac6ebd2846c"/></dir><dir name="Helper"><file name="Data.php" hash="e3839c00e2837b28193d23e63f533b37"/><file name="Request.php" hash="84f061fe40931b993c339d29d26fceab"/><file name="Response.php" hash="aad903c4cd076ea78f96ddeb179f1b85"/></dir><dir name="Model"><dir name="Observer"><file name="Contacts.php" hash="824d5739d6a854312c20764b10a8762e"/></dir><dir name="Source"><file name="Theme.php" hash="4dd05e3bbce98ee7e4ed3bab33fd3365"/></dir></dir><dir name="Test"><dir name="Block"><file name="Autorender.php" hash="a5e6de4f6f0298bd709cd404d34ccd0e"/></dir><dir name="Config"><file name="Module.php" hash="e4ce75427cf4dd943b9b83a47fdabf58"/></dir><dir name="Helper"><file name="Request.php" hash="efae2d639b27e416e0175fac0e6ac638"/><file name="Response.php" hash="c602e7c60e4ad66ff13bc77bdbb1fba5"/></dir><dir name="Model"><dir name="Observer"><file name="Contacts.php" hash="2d4c043d55d275c6d73530f7937a1ecc"/></dir><dir name="Source"><file name="Theme.php" hash="8da1a1f9317b2407bca042d088c4ce1d"/></dir></dir></dir><dir name="etc"><file name="config.xml" hash="537a7e975415d51427c51dc11fb89987"/><file name="system.xml" hash="c9a73cd77c5c0d0c001f1bf848cabaae"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="studioforty9_recaptcha.xml" hash="57f4c8f17f08c04985cd582f4768191e"/></dir><dir name="template"><dir name="studioforty9"><dir name="recaptcha"><file name="autorender.phtml" hash="71a2e1820a9b8e83cba2b3f711cb5eaa"/></dir></dir></dir></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><file name="Studioforty9_Recaptcha.csv" hash="6387abc316e524840fa3b1fcc49dc25d"/></dir></target><target name="mageetc"><dir name="modules"><file name="Studioforty9_Recaptcha.xml" hash="6f8f14cebd2b8681e2631d1c4b7acf0b"/></dir></target></contents>
31
+ <compatible/>
32
+ <dependencies><required><php><min>5.3.0</min><max>5.5.99</max></php></required></dependencies>
33
+ </package>