diff --git a/README.md b/README.md
index 1e40abd..ef30609 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
captcha_module
-Contrib module contaning captcha logic.
+Contrib module containing captcha logic.
diff --git a/controllers/oecaptchacontact.php b/controllers/oecaptchacontact.php
new file mode 100644
index 0000000..b9af7d9
--- /dev/null
+++ b/controllers/oecaptchacontact.php
@@ -0,0 +1,44 @@
+getCaptcha()->passCaptcha()) {
+ return false;
+ }
+
+ return parent::send();
+ }
+
+ /**
+ * Template variable getter. Returns object of handling CAPTCHA image
+ *
+ * @return object
+ */
+ public function getCaptcha()
+ {
+ if ($this->captcha === null) {
+ $this->captcha = oxNew('oeCaptcha');
+ }
+
+ return $this->captcha;
+ }
+
+}
diff --git a/controllers/oecaptchadetails.php b/controllers/oecaptchadetails.php
new file mode 100644
index 0000000..a2056e3
--- /dev/null
+++ b/controllers/oecaptchadetails.php
@@ -0,0 +1,52 @@
+getCaptcha()->passCaptcha(false)) {
+ $this->_iPriceAlarmStatus = 2;
+ return;
+ }
+
+ return parent::addme();
+ }
+
+ /**
+ * Template variable getter. Returns object of handling CAPTCHA image
+ *
+ * @return object
+ */
+ public function getCaptcha()
+ {
+ if ($this->captcha === null) {
+ $this->captcha = oxNew('oeCaptcha');
+ }
+ return $this->captcha;
+ }
+}
diff --git a/controllers/oecaptchainvite.php b/controllers/oecaptchainvite.php
new file mode 100644
index 0000000..f849ec9
--- /dev/null
+++ b/controllers/oecaptchainvite.php
@@ -0,0 +1,49 @@
+getCaptcha()->passCaptcha()) {
+ return false;
+ }
+
+ return parent::send();
+ }
+
+ /**
+ * Template variable getter. Returns object of handling CAPTCHA image
+ *
+ * @return object
+ */
+ public function getCaptcha()
+ {
+ if ($this->captcha === null) {
+ $this->captcha = oxNew('oeCaptcha');
+ }
+
+ return $this->captcha;
+ }
+
+}
diff --git a/controllers/oecaptchapricealarm.php b/controllers/oecaptchapricealarm.php
new file mode 100644
index 0000000..ddea7eb
--- /dev/null
+++ b/controllers/oecaptchapricealarm.php
@@ -0,0 +1,37 @@
+ pricealarm.
+ */
+class oeCaptchaPricealarm extends oeCaptchaPricealarm_parent
+{
+ /**
+ * Validates email
+ * address. If email is wrong - returns false and exits. If email
+ * address is OK - creates prcealarm object and saves it
+ * (oxpricealarm::save()). Sends pricealarm notification mail
+ * to shop owner.
+ *
+ * @return bool false on error
+ */
+ public function addme()
+ {
+ //control captcha
+ $captcha = oxNew('oeCaptcha');
+ if (!$captcha->passCaptcha(false)) {
+ $this->_iPriceAlarmStatus = 2;
+
+ return;
+ }
+
+ return parent::addme();
+ }
+}
diff --git a/controllers/oecaptchasuggest.php b/controllers/oecaptchasuggest.php
new file mode 100644
index 0000000..73d1db8
--- /dev/null
+++ b/controllers/oecaptchasuggest.php
@@ -0,0 +1,52 @@
+editval, error
+ *
+ * @return null
+ */
+ public function send()
+ {
+ // spam spider prevension
+ if (!$this->getCaptcha()->passCaptcha()) {
+ return false;
+ }
+
+ return parent::send();
+ }
+
+ /**
+ * Template variable getter. Returns object of handling CAPTCHA image
+ *
+ * @return object
+ */
+ public function getCaptcha()
+ {
+ if ($this->captcha === null) {
+ $this->captcha = oxNew('oeCaptcha');
+ }
+
+ return $this->captcha;
+ }
+}
diff --git a/core/oecaptcha.php b/core/oecaptcha.php
new file mode 100644
index 0000000..88ef8b8
--- /dev/null
+++ b/core/oecaptcha.php
@@ -0,0 +1,234 @@
+text) {
+ $this->text = '';
+ for ($i = 0; $i < $this->macLength; $i++) {
+ $this->text .= strtolower($this->macChars{rand(0, strlen($this->macChars) - 1)});
+ }
+ }
+
+ return $this->text;
+ }
+
+ /**
+ * Returns text hash
+ *
+ * @param string $text User supplie text
+ *
+ * @return string
+ */
+ public function getHash($text = null)
+ {
+ // inserting captcha record
+ $time = time() + $this->timeout;
+ $textHash = $this->getTextHash($text);
+
+ // if session is started - storing captcha info here
+ $session = $this->getSession();
+ if ($session->isSessionStarted()) {
+ $hash = oxUtilsObject::getInstance()->generateUID();
+ $hashArray = $session->getVariable('captchaHashes');
+ $hashArray[$hash] = array($textHash => $time);
+ $session->setVariable('captchaHashes', $hashArray);
+ } else {
+ $database = oxDb::getDb();
+ $query = "insert into oecaptcha (oxhash, oxtime) values (" .
+ $database->quote($textHash) . ", " . $database->quote($time) . ")";
+ $database->execute($query);
+ $hash = $database->getOne('select LAST_INSERT_ID()', false, false);
+ }
+
+ return $hash;
+ }
+
+ /**
+ * Returns given string captcha hash
+ *
+ * @param string $text string to hash
+ *
+ * @return string
+ */
+ public function getTextHash($text)
+ {
+ if (!$text) {
+ $text = $this->getText();
+ }
+ $text = strtolower($text);
+
+ return md5('ox' . $text);
+ }
+
+ /**
+ * Returns url to CAPTCHA image generator.
+ *
+ * @return string
+ */
+ public function getImageUrl()
+ {
+ $url = $this->getConfig()->getCurrentShopUrl() . 'modules/oe/captcha/core/utils/verificationimg.php?e_mac=';
+ $key = $this->getConfig()->getConfigParam('oecaptchakey');
+ $key = empty($key) ? null : $key;
+ $url .= oxRegistry::getUtils()->strMan($this->getText(), $key);
+
+ return $url;
+ }
+
+ /**
+ * Checks if image could be generated
+ *
+ * @return bool
+ */
+ public function isImageVisible()
+ {
+ return ((function_exists('imagecreatetruecolor') || function_exists('imagecreate')) && $this->getConfig()->getConfigParam('iUseGDVersion') > 1);
+ }
+
+ /**
+ * Check if captcha is passed.
+ *
+ * @return bool
+ */
+ public function passCaptcha($displayError = true)
+ {
+ $return = true;
+
+ // spam spider prevention
+ $mac = $this->getConfig()->getRequestParameter('c_mac');
+ $macHash = $this->getConfig()->getRequestParameter('c_mach');
+
+ if (!$this->pass($mac, $macHash)) {
+ $return = false;
+ }
+
+ if (!$return && $displayError) {
+ // even if there is no exception, use this as a default display method
+ oxRegistry::get('oxUtilsView')->addErrorToDisplay('MESSAGE_WRONG_VERIFICATION_CODE');
+ }
+
+ return $return;
+ }
+
+ /**
+ * Verifies captcha input vs supplied hash. Returns true on success.
+ *
+ * @param string $mac User supplied text
+ * @param string $macHash Generated hash
+ *
+ * @return bool
+ */
+ protected function pass($mac, $macHash)
+ {
+ $time = time();
+ $hash = $this->getTextHash($mac);
+ $pass = $this->passFromSession($macHash, $hash, $time);
+
+ // if captcha info was NOT stored in session
+ if ($pass === null) {
+ $pass = $this->passFromDb((int) $macHash, $hash, $time);
+ }
+
+ return (bool) $pass;
+ }
+
+ /**
+ * Checks for session captcha hash validity
+ *
+ * @param string $macHash hash key
+ * @param string $hash captcha hash
+ * @param int $time check time
+ *
+ * @return bool
+ */
+ protected function passFromSession($macHash, $hash, $time)
+ {
+ $pass = null;
+ $session = $this->getSession();
+
+ if (($hashArray = $session->getVariable('captchaHashes'))) {
+ $pass = (isset($hashArray[$macHash][$hash]) && $hashArray[$macHash][$hash] >= $time) ? true : false;
+ unset($hashArray[$macHash]);
+ if (!empty($hashArray)) {
+ $session->setVariable('captchaHashes', $hashArray);
+ } else {
+ $session->deleteVariable('captchaHashes');
+ }
+ }
+
+ return $pass;
+ }
+
+ /**
+ * Checks for DB captcha hash validity
+ *
+ * @param int $macHash hash key
+ * @param string $hash captcha hash
+ * @param int $time check time
+ *
+ * @return bool
+ */
+ protected function passFromDb($macHash, $hash, $time)
+ {
+ $database = oxDb::getDb();
+ $where = "where oxid = " . $database->quote($macHash) . " and oxhash = " . $database->quote($hash);
+ $query = "select 1 from oecaptcha " . $where;
+ $pass = (bool) $database->getOne($query, false, false);
+
+ if ($pass) {
+ // cleanup
+ $query = "delete from oecaptcha " . $where;
+ $database->execute($query);
+ }
+
+ // garbage cleanup
+ $query = "delete from oecaptcha where oxtime < $time";
+ $database->execute($query);
+
+ return $pass;
+ }
+
+}
diff --git a/core/oecaptchaevents.php b/core/oecaptchaevents.php
new file mode 100644
index 0000000..948dce1
--- /dev/null
+++ b/core/oecaptchaevents.php
@@ -0,0 +1,62 @@
+execute($query);
+
+ }
+
+ /**
+ * Remove table oecaptcha.
+ * NOTE: table oecaptcha contains temporary data if any and can be
+ * removed without side effects on module deactivation
+ */
+ public static function removeCaptchaTable()
+ {
+ $query = "DROP TABLE IF EXISTS `oecaptcha`";
+
+ oxDb::getDb()->execute($query);
+ }
+
+ /**
+ * Execute action on activate event
+ *
+ * @return null
+ */
+ public static function onActivate()
+ {
+ self::addCaptchaTable();
+ }
+
+ /**
+ * Execute action on deactivate event
+ *
+ * @return null
+ */
+ public static function onDeactivate()
+ {
+ self::removeCaptchaTable();
+ }
+}
diff --git a/core/utils/verificationimg.php b/core/utils/verificationimg.php
new file mode 100644
index 0000000..b47a476
--- /dev/null
+++ b/core/utils/verificationimg.php
@@ -0,0 +1,106 @@
+getConfigParam('oecaptchakey');
+
+ if (empty($key)) {
+ $key = getOxConfKey();
+ }
+
+ return $decryptor->decrypt($value, $key);
+ }
+}
+
+if (!function_exists('getOxConfKey')) {
+
+ /**
+ * Get default config key.
+ *
+ * @return string
+ */
+ function getOxConfKey()
+ {
+ $fileName = getShopBasePath() . '/core/oxconfk.php';
+ $configFile = new oxConfigFile($fileName);
+
+ return $configFile->getVar("sConfigKey");
+ }
+
+}
+
+$mac = strRem($emac);
+generateVerificationImg($mac);
diff --git a/docs/README.txt b/docs/README.txt
new file mode 100755
index 0000000..5400211
--- /dev/null
+++ b/docs/README.txt
@@ -0,0 +1,36 @@
+==Title==
+OE Captcha
+
+==Author==
+OXID eSales AG
+
+==Prefix==
+oe
+
+==Shop Version==
+6.x
+
+==Version==
+1.0.0
+
+==Link==
+http://www.oxid-esales.com/
+
+==Mail==
+
+
+==Description==
+OE Captcha Module
+
+==Installation==
+Activate the module in administration area.
+
+==Extend==
+
+
+==Modules==
+
+==Modified original templates==
+
+==Uninstall==
+Disable the module in administration area and delete module folder.
diff --git a/metadata.php b/metadata.php
new file mode 100755
index 0000000..9d7b722
--- /dev/null
+++ b/metadata.php
@@ -0,0 +1,63 @@
+ 'oecaptcha',
+ 'title' => array(
+ 'de' => 'Simple Captcha',
+ 'en' => 'Simple Captcha',
+ ),
+ 'description' => array(
+ 'de' => 'OXID eSales Simple Captcha Module',
+ 'en' => 'OXID eSales Simple Captcha Module',
+ ),
+ 'thumbnail' => 'out/pictures/picture.png',
+ 'version' => '1.0.0',
+ 'author' => 'OXID eSales AG',
+ 'url' => 'http://www.oxid-esales.com/',
+ 'email' => '',
+ 'extend' => array('details' => 'oe/captcha/controllers/oecaptchadetails',
+ 'contact' => 'oe/captcha/controllers/oecaptchacontact',
+ 'invite' => 'oe/captcha/controllers/oecaptchainvite',
+ 'pricealarm' => 'oe/captcha/controllers/oecaptchapricealarm',
+ 'suggest' => 'oe/captcha/controllers/oecaptchasuggest'),
+ 'files' => array(
+ 'oecaptcha' => 'oe/captcha/core/oecaptcha.php',
+ 'oecaptchaEvents' => 'oe/captcha/core/oecaptchaevents.php',
+ ),
+ 'templates' => array(),
+ 'blocks' => array(
+ array('template' => 'form/contact.tpl', 'block'=>'captcha_form', 'file'=>'/views/blocks/captcha_form.tpl'),
+ array('template' => 'form/invite.tpl', 'block'=>'captcha_form', 'file'=>'/views/blocks/captcha_form.tpl'),
+ array('template' => 'form/pricealarm.tpl', 'block'=>'captcha_form', 'file'=>'/views/blocks/captcha_form.tpl'),
+ array('template' => 'form/suggest.tpl', 'block'=>'captcha_form', 'file'=>'/views/blocks/captcha_form.tpl'),
+ ),
+ 'settings' => array(
+ array('group' => 'main', 'name' => 'oecaptchakey', 'type' => 'str', 'value' => ''),
+ ),
+ 'events' => array(
+ 'onActivate' => 'oecaptchaevents::onActivate',
+ 'onDeactivate' => 'oecaptchaevents::onDeactivate'
+ ),
+);
diff --git a/out/pictures/picture.png b/out/pictures/picture.png
new file mode 100755
index 0000000..3818857
Binary files /dev/null and b/out/pictures/picture.png differ
diff --git a/tests/unit/CaptchaTestCase.php b/tests/unit/CaptchaTestCase.php
new file mode 100644
index 0000000..b378e19
--- /dev/null
+++ b/tests/unit/CaptchaTestCase.php
@@ -0,0 +1,40 @@
+execute($query);
+ }
+
+ /**
+ * Fixture set up.
+ */
+ protected function tearDown()
+ {
+ $query = "DROP TABLE `oecaptcha`";
+ oxDb::getDb()->execute($query);
+
+ parent::tearDown();
+ }
+
+}
diff --git a/tests/unit/core/oecaptchaEventsTest.php b/tests/unit/core/oecaptchaEventsTest.php
new file mode 100644
index 0000000..d527557
--- /dev/null
+++ b/tests/unit/core/oecaptchaEventsTest.php
@@ -0,0 +1,59 @@
+execute("DROP TABLE IF EXISTS `oecaptcha`");
+ }
+
+ /**
+ * Tear down the fixture.
+ */
+ public function tearDown()
+ {
+ oeCaptchaEvents::addCaptchaTable();
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test onActivate event.
+ */
+ public function testOnActivate()
+ {
+ oeCaptchaEvents::onActivate();
+
+ $oDbMetaDataHandler = oxNew('oxDbMetaDataHandler');
+
+ //If session is not available, table oecaptcha is where captcha information is stored
+ $this->assertTrue($oDbMetaDataHandler->tableExists('oecaptcha'));
+
+ }
+
+ /**
+ * Test onActivate event.
+ */
+ public function testOnDeactivate()
+ {
+ oeCaptchaEvents::onDeactivate();
+
+ $oDbMetaDataHandler = oxNew('oxDbMetaDataHandler');
+
+ //If session is not available, table oecaptcha is where captcha information is stored
+ $this->assertFalse($oDbMetaDataHandler->tableExists('oecaptcha'));
+
+ }
+
+}
diff --git a/tests/unit/core/oecaptchaTest.php b/tests/unit/core/oecaptchaTest.php
new file mode 100644
index 0000000..fb7bd44
--- /dev/null
+++ b/tests/unit/core/oecaptchaTest.php
@@ -0,0 +1,230 @@
+captcha = $this->getProxyClass('oecaptcha');
+ }
+
+ /**
+ * oeCaptcha::getText() test case
+ */
+ public function testGetText()
+ {
+ $this->assertNull($this->captcha->getNonPublicVar('text'));
+ $sText = $this->captcha->getText();
+ $this->assertEquals($sText, $this->captcha->getNonPublicVar('text'));
+ $this->assertEquals(5, strlen($sText));
+ }
+
+ /**
+ * oeCaptcha::getTextHash() test case
+ */
+ public function testGetTextHash()
+ {
+ $this->assertEquals('c4b961848aeff4d9b083fe15a56c9bd0', $this->captcha->getTextHash('test1'));
+ }
+
+ /**
+ * oeCaptcha::getHash() test case
+ */
+ public function testGetHashNoSession()
+ {
+ $session = $this->getMock('oxSession', array('isSessionStarted'));
+ $session->expects($this->once())->method('isSessionStarted')->will($this->returnValue(false));
+
+ $captcha = $this->getMock('oeCaptcha', array('getSession'));
+ $captcha->expects($this->once())->method('getSession')->will($this->returnValue($session));
+
+ $hash = $captcha->getHash('test');
+ $this->assertEquals(oxDb::getDb()->getOne('select LAST_INSERT_ID()', false, false), $hash);
+ }
+
+ /**
+ * oeCaptcha::getHash() test case
+ * #0004286 adding case for multiple hashes
+ */
+ public function testGetHashSession()
+ {
+ $session = $this->getMock('oxSession', array('isSessionStarted'));
+ $session->expects($this->exactly(2))->method('isSessionStarted')->will($this->returnValue(true));
+
+ $captcha = $this->getMock('oeCaptcha', array('getSession'));
+ $captcha->expects($this->exactly(2))->method('getSession')->will($this->returnValue($session));
+ $hash1 = $captcha->getHash('test1');
+ $hash2 = $captcha->getHash('test2');
+
+ $captchaHash = oxRegistry::getSession()->getVariable('captchaHashes');
+ $this->assertNotNull($captchaHash);
+ $this->assertTrue(isset($captchaHash[$hash1]));
+ $this->assertTrue(isset($captchaHash[$hash2]));
+ }
+
+ /**
+ * oeCaptcha::getImageUrl() test case
+ */
+ public function testGetImageUrl()
+ {
+ $this->setConfigParam('oecaptchakey', 'someTestCaptchaKey');
+ $this->captcha->setNonPublicVar('text', 'test1');
+ $expected = $this->getConfig()->getShopUrl() . 'modules/oe/captcha/core/utils/verificationimg.php?e_mac=ox_MAsbCBYgVBoQ';
+
+ $this->assertEquals($expected, $this->captcha->getImageUrl());
+ }
+
+ /**
+ * oeCaptcha::getImageUrl() test case if sCaptcha key is not set
+ */
+ public function testGetImageUrlFallbackKey()
+ {
+ $this->setConfigParam('oecaptchakey', '');
+ $this->captcha->setNonPublicVar('text', 'test1');
+
+ $expected = $this->getConfig()->getShopUrl() . 'modules/oe/captcha/core/utils/verificationimg.php?e_mac=ox_MB4FUUYlYlld';
+ $this->assertEquals($expected, $this->captcha->getImageUrl());
+ }
+
+ /**
+ * oeCaptcha::isImageVisible() test case
+ */
+ public function testIsImageVisible()
+ {
+ $this->assertTrue($this->captcha->isImageVisible());
+ }
+
+ /**
+ * oeCaptcha::isImageVisible() test case
+ */
+ public function testIsImageVisibleLowGD()
+ {
+ $this->getConfig()->setConfigParam('iUseGDVersion', 0);
+ $this->assertFalse($this->captcha->isImageVisible());
+ }
+
+ /**
+ * oeCaptcha::pass() test case
+ */
+ public function testDbPassCorrect()
+ {
+ $captcha = $this->getMock('oeCaptcha', array('passFromSession'));
+ $captcha->expects($this->once())->method('passFromSession')->will($this->returnValue(null));
+
+ // reseting session
+ $session = oxNew('oxSession');
+ $captcha->setSession($session);
+
+ $captcha->getHash('3at8u');
+ $hash = oxDb::getDb()->getOne('select LAST_INSERT_ID()', false, false);
+ $this->assertTrue($captcha->pass('3at8u', $hash));
+ }
+
+ /**
+ * oeCaptcha::pass() test case
+ */
+ public function testDbPassFail()
+ {
+ $captcha = $this->getMock('oeCaptcha', array('passFromSession'));
+ $captcha->expects($this->once())->method('passFromSession')->will($this->returnValue(null));
+
+ $this->assertFalse($captcha->pass('3at8v', 'd9a470912b222133fb913da36c0f50d0'));
+ }
+
+ /**
+ * oeCaptcha::pass() test case
+ * #0004286 adding case for multiple hashes
+ */
+ public function testSessionPassCorrect()
+ {
+ $mac1 = '3at8u';
+ $mac2 = '3at8u';
+ $hash1 = 1234;
+ $hash2 = 1235;
+
+ $captcha = oxNew('oeCaptcha');
+ $hash = array(
+ $hash1 => array($captcha->getTextHash($mac1) => time() + 3600),
+ $hash2 => array($captcha->getTextHash($mac2) => time() + 3600)
+ );
+ $session = $this->getSession();
+ $session->setVariable('captchaHashes', $hash);
+
+ $captcha = $this->getMock('oeCaptcha', array('passFromDb'));
+ $captcha->expects($this->never())->method('passFromDb');
+
+ $this->assertTrue($captcha->pass($mac1, $hash1));
+ $this->assertEquals(1, count($session->getVariable('captchaHashes')));
+
+ $this->assertTrue($captcha->pass($mac2, $hash2));
+ $this->assertNull($session->getVariable('captchaHashes'));
+ }
+
+ /**
+ * oeCaptcha::pass() test case
+ */
+ public function testSessionPassFail()
+ {
+ $this->getSession()->setVariable('captchaHashes', array('testHash' => array('testTextHash' => 132)));
+
+ $captcha = $this->getMock('oeCaptcha', array('passFromDb'));
+ $captcha->expects($this->never())->method('passFromDb');
+
+ $this->assertFalse($captcha->pass('3at8v', 'd9a470912b222133fb913da36c0f50d0'));
+ }
+
+ /**
+ * Test passing captcha.
+ */
+ public function testPassCaptchaYes()
+ {
+ $captcha = $this->getMock('oeCaptcha', array('pass'));
+ $captcha->expects($this->once())->method('pass')->will($this->returnValue(true));
+
+ $result = $captcha->passCaptcha();
+ $this->assertTrue($result);
+ }
+
+ /**
+ * Test not passing captcha.
+ */
+ public function testPassCaptchaNo()
+ {
+ $utilsView = $this->getMock('oxUtilsView', array('addErrorToDisplay'));
+ $utilsView->expects($this->once())->method('addErrorToDisplay')->with($this->equalTo('MESSAGE_WRONG_VERIFICATION_CODE'));
+ oxRegistry::set('oxUtilsView', $utilsView);
+
+ $captcha = $this->getMock('oeCaptcha', array('pass'));
+ $captcha->expects($this->once())->method('pass')->will($this->returnValue(false));
+
+ $result = $captcha->passCaptcha();
+ $this->assertFalse($result);
+ }
+
+ /**
+ * Test not passing captcha without displaying error message.
+ */
+ public function testPassCaptchaNoWithoutDisplayMessage()
+ {
+ $utilsView = $this->getMock('oxUtilsView', array('addErrorToDisplay'));
+ $utilsView->expects($this->never())->method('addErrorToDisplay');
+ oxRegistry::set('oxUtilsView', $utilsView);
+
+ $captcha = $this->getMock('oeCaptcha', array('pass'));
+ $captcha->expects($this->once())->method('pass')->will($this->returnValue(false));
+
+ $result = $captcha->passCaptcha(false);
+ $this->assertFalse($result);
+ }
+}
diff --git a/tests/unit/views/contactTest.php b/tests/unit/views/contactTest.php
new file mode 100644
index 0000000..e33988f
--- /dev/null
+++ b/tests/unit/views/contactTest.php
@@ -0,0 +1,150 @@
+deleteVariable('Errors');
+
+ $params['oxuser__oxusername'] = 'aaaa@aaa.com';
+ $this->setRequestParameter('editval', $params);
+ $contact = oxNew('Contact');
+
+ $this->assertFalse($contact->send());
+
+ //checking if warning was added to errors list
+ $message = oxRegistry::getLang()->translateString('MESSAGE_WRONG_VERIFICATION_CODE');
+ $errors = oxRegistry::getSession()->getVariable('Errors');
+ $error = unserialize($errors['default'][0]);
+
+ $this->assertEquals($message, $error->getOxMessage());
+ }
+
+ /**
+ * Test if send mail is not executed if user data is not entered
+ * and warning message is displayed
+ */
+ public function testSaveWithoutUserData()
+ {
+ oxRegistry::getSession()->deleteVariable('Errors');
+ oxTestModules::addFunction('oeCaptcha', 'pass', '{return true;}');
+
+ $params['oxuser__oxusername'] = 'aaaa@aaa.com';
+ $this->setRequestParameter('editval', $params);
+ $contact = oxNew('Contact');
+
+ $this->assertFalse($contact->send());
+
+ //checking if warning was added to errors list
+ $message = oxRegistry::getLang()->translateString('ERROR_MESSAGE_INPUT_NOTALLFIELDS');
+ $errors = oxRegistry::getSession()->getVariable('Errors');
+ $error = unserialize($errors['default'][0]);
+
+ $this->assertEquals($message, $error->getOxMessage());
+ }
+
+ /**
+ * Test send mail
+ */
+ public function testSave()
+ {
+ oxTestModules::addFunction('oeCaptcha', 'pass', '{return true;}');
+ oxTestModules::addFunction('oxemail', 'sendContactMail', '{return true;}');
+
+ $params['oxuser__oxusername'] = 'aaaa@aaa.com';
+ $params['oxuser__oxfname'] = 'first name';
+ $params['oxuser__oxlname'] = 'last name';
+ $this->setRequestParameter('editval', $params);
+ $this->setRequestParameter('c_subject', 'testSubject');
+ $contact = $this->getProxyClass('Contact');
+ $contact->send();
+
+ $this->assertEquals(1, $contact->getNonPublicVar('_blContactSendStatus'));
+ }
+
+ /**
+ * Test getting object for handling CAPTCHA image
+ */
+ public function testGetCaptcha()
+ {
+ $contact = oxNew('Contact');
+ $this->assertEquals(oxNew('oeCaptcha'), $contact->getCaptcha());
+ }
+
+ /**
+ * Test case for bug #0002065: Contact-Mail shows MR or MRS instead of localized salutation
+ */
+ public function testSendForBugtrackEntry0002065()
+ {
+ $params = array(
+ 'oxuser__oxusername' => 'info@oxid-esales.com',
+ 'oxuser__oxfname' => 'admin',
+ 'oxuser__oxlname' => 'admin',
+ 'oxuser__oxsal' => 'MR'
+ );
+
+ $this->setRequestParameter('editval', $params);
+ $this->setRequestParameter('c_message', 'message');
+ $this->setRequestParameter('c_subject', 'subject');
+
+ $language = oxRegistry::getLang();
+ $message = $language->translateString('MESSAGE_FROM') . ' ' . $language->translateString('MR') .
+ ' admin admin(info@oxid-esales.com)
message';
+
+ $email = $this->getMock('oxemail', array('sendContactMail'));
+ $email->expects($this->once())->method('sendContactMail')->with($this->equalTo('info@oxid-esales.com'),
+ $this->equalTo('subject'), $this->equalTo($message))->will($this->returnValue(true));
+ oxTestModules::addModuleObject('oxemail', $email);
+
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(true));
+
+ $contact = $this->getMock('oecaptchacontact', array('getCaptcha'));
+ $contact->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+ $contact->send();
+ }
+
+ /**
+ * Testing method send()
+ */
+ public function testSendEmailNotSend()
+ {
+ $utils = $this->getMock('oxUtilsView', array('addErrorToDisplay'));
+ $utils->expects($this->once())->method('addErrorToDisplay')->with($this->equalTo('ERROR_MESSAGE_CHECK_EMAIL'));
+ oxTestModules::addModuleObject('oxUtilsView', $utils);
+
+ $params = array(
+ 'oxuser__oxusername' => 'info@oxid-esales.com',
+ 'oxuser__oxfname' => 'admin',
+ 'oxuser__oxlname' => 'admin',
+ 'oxuser__oxsal' => 'MR'
+ );
+
+ $this->setRequestParameter('editval', $params);
+ $this->setRequestParameter('c_message', 'message');
+ $this->setRequestParameter('c_subject', 'subject');
+
+ $email = $this->getMock('oxemail', array('sendContactMail'));
+ $email->expects($this->once())->method('sendContactMail')->will($this->returnValue(false));
+ oxTestModules::addModuleObject('oxemail', $email);
+
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(true));
+
+ $contact = $this->getMock('oecaptchacontact', array('getCaptcha'));
+ $contact->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+ $contact->send();
+ }
+}
diff --git a/tests/unit/views/detailsTest.php b/tests/unit/views/detailsTest.php
new file mode 100644
index 0000000..86a415a
--- /dev/null
+++ b/tests/unit/views/detailsTest.php
@@ -0,0 +1,45 @@
+getProxyClass('oecaptchadetails');
+ $this->assertEquals(oxNew('oeCaptcha'), $details->getCaptcha());
+ }
+
+ /**
+ * Invalid captcha test case.
+ */
+ public function testAddmeInvalidCaptcha()
+ {
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(false));
+
+ $email = $this->getMock('oxEmail', array('sendPricealarmNotification'));
+ $email->expects($this->never())->method('sendPricealarmNotification');
+ oxTestModules::addModuleObject('oxEmail', $email);
+
+ $details = $this->getMock($this->getProxyClassName('oecaptchadetails'), array('getCaptcha'));
+ $details->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+
+ $details->addme();
+ $this->assertSame(2, $details->getNonPublicVar('_iPriceAlarmStatus'));
+ }
+
+}
+
+
diff --git a/tests/unit/views/inviteTest.php b/tests/unit/views/inviteTest.php
new file mode 100644
index 0000000..6a7be7e
--- /dev/null
+++ b/tests/unit/views/inviteTest.php
@@ -0,0 +1,106 @@
+cleanUpTable('oxinvitations', 'oxuserid');
+
+ parent::tearDown();
+ }
+
+ /**
+ * Testing method getCaptcha()
+ *
+ * @return null
+ */
+ public function testGetCaptcha()
+ {
+ $invite = $this->getProxyClass('oecaptchainvite');
+ $this->assertEquals(oxNew('oeCaptcha'), $invite->getCaptcha());
+ }
+
+ /**
+ * Testing method send() - no captcha text
+ */
+ public function testSendWithoutCaptcha()
+ {
+ $this->setRequestParameter('editval', array('rec_email' => 'testRecEmail@oxid-esales.com',
+ 'send_name' => 'testSendName',
+ 'send_email' => 'testSendEmail@oxid-esales.com',
+ 'send_message' => 'testSendMessage',
+ 'send_subject' => 'testSendSubject'));
+ $this->getConfig()->setConfigParam('blInvitationsEnabled', true);
+
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(false));
+
+ $invite = $this->getMock('oecaptchainvite', array('getCaptcha', 'getUser'));
+ $invite->expects($this->never())->method('getUser');
+ $invite->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+ $invite->send();
+ $this->assertFalse($invite->getInviteSendStatus());
+ }
+
+ /**
+ * Testing method send()
+ */
+ public function testSend()
+ {
+ $this->setRequestParameter('editval', array('rec_email' => array('testRecEmail@oxid-esales.com'), 'send_name' => 'testSendName', 'send_email' => 'testSendEmail@oxid-esales.com', 'send_message' => 'testSendMessage', 'send_subject' => 'testSendSubject'));
+ $this->getConfig()->setConfigParam('blInvitationsEnabled', true);
+
+ $email = $this->getMock('oxEmail', array('sendInviteMail'));
+ $email->expects($this->once())->method('sendInviteMail')->will($this->returnValue(true));
+ oxTestModules::addModuleObject('oxEmail', $email);
+
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(true));
+
+ $invite = $this->getMock('oecaptchainvite', array('getCaptcha', 'getUser'));
+ $invite->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+ $invite->expects($this->any())->method('getUser')->will($this->returnValue(oxNew('oxUser')));
+ $invite->send();
+ $this->assertTrue($invite->getInviteSendStatus());
+ }
+
+ /**
+ * Testing method render()
+ *
+ * @return null
+ */
+ public function testRender()
+ {
+ $this->getConfig()->setConfigParam('blInvitationsEnabled', true);
+
+ $invite = $this->getMock('invite', array('getUser'));
+ $invite->expects($this->any())->method('getUser')->will($this->returnValue(oxNew('oxUser')));
+
+ $this->assertEquals('page/privatesales/invite.tpl', $invite->render());
+ }
+
+ /**
+ * Testing method render() - mail was sent status
+ */
+ public function testRenderMailWasSent()
+ {
+ $this->getConfig()->setConfigParam('blInvitationsEnabled', true);
+
+ $invite = $this->getProxyClass('invite');
+ $invite->setNonPublicVar('_iMailStatus', 1);
+ $invite->render();
+
+ $this->assertTrue($invite->getInviteSendStatus());
+ }
+
+}
diff --git a/tests/unit/views/pricealarmTest.php b/tests/unit/views/pricealarmTest.php
new file mode 100644
index 0000000..a192f33
--- /dev/null
+++ b/tests/unit/views/pricealarmTest.php
@@ -0,0 +1,111 @@
+cleanUpTable('oxpricealarm', 'oxartid');
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test incorrect captcha.
+ */
+ public function testAddmeIncorectCaptcha()
+ {
+ $priceAlarm = $this->getProxyClass('oecaptchapricealarm');
+ $this->setRequestParameter('c_mac', 'aa');
+ $this->setRequestParameter('c_mach', 'bb');
+
+ $priceAlarm->addme();
+
+ $this->assertEquals(2, $priceAlarm->getNonPublicVar('_iPriceAlarmStatus'));
+
+ $query = 'select count(oxid) from oxpricealarm';
+ $this->assertEquals(0, oxDb::getDb()->getOne($query));
+ }
+
+ /**
+ * Test incorrect email.
+ */
+ public function testAddmeIncorectEmail()
+ {
+ $priceAlarm = $this->getProxyClass('oecaptchapricealarm');
+ oxTestModules::addFunction('oeCaptcha', 'passCaptcha', '{return true;}');
+
+ $this->setRequestParameter('pa', array('email' => 'ladyGaga'));
+ $priceAlarm->addme();
+
+ $this->assertEquals(0, $priceAlarm->getNonPublicVar('_iPriceAlarmStatus'));
+
+ $query = 'select count(oxid) from oxpricealarm';
+ $this->assertEquals(0, oxDb::getDb()->getOne($query));
+ }
+
+ /**
+ * Test all is well.
+ */
+ public function testAddmeSavesAndSendsPriceAlarm()
+ {
+ $priceAlarm = $this->getProxyClass('pricealarm');
+ oxTestModules::addFunction('oeCaptcha', 'passCaptcha', '{return true;}');
+ oxTestModules::addFunction('oxEmail', 'sendPricealarmNotification', '{return 999;}');
+
+ $this->getSession()->setVariable('usr', 'testUserId');
+ $parameters['email'] = 'goodemail@ladyGagaFans.lt';
+ $parameters['aid'] = '_testArtId';
+ $parameters['price'] = '10';
+
+ $parameters['mano'] = '101';
+
+ $this->setRequestParameter('pa', $parameters);
+ $priceAlarm->addme();
+
+ $this->assertEquals(999, $priceAlarm->getNonPublicVar('_iPriceAlarmStatus'));
+
+ $query = 'select * from oxpricealarm';
+ $alarm = oxDb::getDb(oxDB::FETCH_MODE_ASSOC)->getRow($query);
+
+ $this->assertEquals($parameters['email'], $alarm['OXEMAIL']);
+ $this->assertEquals($parameters['aid'], $alarm['OXARTID']);
+ $this->assertEquals($parameters['price'], $alarm['OXPRICE']);
+ $this->assertEquals('testUserId', $alarm['OXUSERID']);
+ $this->assertEquals('EUR', $alarm['OXCURRENCY']);
+ $this->assertEquals(0, $alarm['OXLANG']);
+ }
+
+ /**
+ * Test saving active language.
+ */
+ public function testAddmeSavesCurrentActiveLanguage()
+ {
+ $priceAlarm = $this->getProxyClass('pricealarm');
+ oxTestModules::addFunction('oeCaptcha', 'passCaptcha', '{return true;}');
+ oxTestModules::addFunction('oxEmail', 'sendPricealarmNotification', '{return 999;}');
+
+ $this->getSession()->setVariable('usr', 'testUserId');
+ $parameters['email'] = 'goodemail@ladyGagaFans.lt';
+
+ oxRegistry::getLang()->setBaseLanguage(1);
+ $this->setRequestParameter('pa', $parameters);
+
+ $priceAlarm->addme();
+
+ $query = 'select oxlang from oxpricealarm';
+ $language = oxDb::getDb(oxDB::FETCH_MODE_ASSOC)->getOne($query);
+
+ $this->assertEquals(1, $language);
+ }
+
+}
diff --git a/tests/unit/views/suggestTest.php b/tests/unit/views/suggestTest.php
new file mode 100644
index 0000000..c28a415
--- /dev/null
+++ b/tests/unit/views/suggestTest.php
@@ -0,0 +1,111 @@
+execute($sDelete);
+
+ $sDelete = "delete from oxobject2list where oxlistid like 'testlist%'";
+ oxDb::getDB()->execute($sDelete);
+
+ parent::tearDown();
+ }
+
+ /**
+ * Test getter for suggest data.
+ */
+ public function testGetSuggestData()
+ {
+ oxTestModules::addFunction('oeCaptcha', 'passCaptcha', '{return true;}');
+ $this->setRequestParameter('editval', array('name' => 'test', 'value' => 'testvalue'));
+
+ $suggest = $this->getProxyClass('oecaptchasuggest');
+ $suggest->send();
+
+ $parameter = $suggest->getSuggestData();
+
+ $this->assertEquals('test', $parameter->name);
+ $this->assertEquals('testvalue', $parameter->value);
+ }
+
+ /**
+ * Test captcha getter.
+ */
+ public function testGetCaptcha()
+ {
+ $suggest = $this->getProxyClass('oecaptchasuggest');
+ $this->assertEquals(oxNew('oeCaptcha'), $suggest->getCaptcha());
+ }
+
+ /**
+ * Test all is well.
+ */
+ public function testSendPass()
+ {
+ $this->setRequestParameter(
+ 'editval',
+ array(
+ 'name' => 'test',
+ 'value' => 'testvalue',
+ 'rec_name' => 'test1',
+ 'rec_email' => 'recmail@oxid.lt',
+ 'send_name' => 'test3',
+ 'send_email' => 'sendmail@oxid.lt',
+ 'send_message' => 'test5',
+ 'send_subject' => 'test6',
+ )
+ );
+
+ $email = $this->getMock('stdclass', array('sendSuggestMail'));
+ $email->expects($this->once())->method('sendSuggestMail')
+ ->will($this->returnValue(1));
+
+ oxTestModules::addModuleObject('oxemail', $email);
+
+ $product = $this->getMock('oxarticle', array('getId'));
+ $product->expects($this->once())->method('getId')->will($this->returnValue('XProduct'));
+
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(true));
+
+ $suggest = $this->getMock('oecaptchasuggest', array('getProduct', 'getCaptcha'));
+ $suggest->expects($this->once())->method('getProduct')->will($this->returnValue($product));
+ $suggest->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+
+ $this->setRequestParameter('searchparam', 'searchparam&&A');
+ $this->setRequestParameter('searchcnid', 'searchcnid&&A');
+ $this->setRequestParameter('searchvendor', 'searchvendor&&A');
+ $this->setRequestParameter('searchmanufacturer', 'searchmanufacturer&&A');
+ $this->setRequestParameter('listtype', 'listtype&&A');
+
+ $expected = 'details?anid=XProduct&searchparam=searchparam%26%26A&searchcnid=searchcnid&&A&searchvendor=searchvendor&&A&searchmanufacturer=searchmanufacturer&&A&listtype=listtype&&A';
+ $this->assertEquals($expected, $suggest->send());
+ }
+
+ /**
+ * Test invalid captcha case.
+ */
+ public function testSendInvalidCaptcha()
+ {
+ $captcha = $this->getMock('oeCaptcha', array('passCaptcha'));
+ $captcha->expects($this->once())->method('passCaptcha')->will($this->returnValue(false));
+
+ $suggest = $this->getMock('oecaptchasuggest', array('getProduct', 'getCaptcha'));
+ $suggest->expects($this->never())->method('getProduct');
+ $suggest->expects($this->once())->method('getCaptcha')->will($this->returnValue($captcha));
+
+ $this->assertFalse($suggest->send());
+ }
+}
diff --git a/translations/de/oecaptcha_de_lang.php b/translations/de/oecaptcha_de_lang.php
new file mode 100755
index 0000000..0effcb4
--- /dev/null
+++ b/translations/de/oecaptcha_de_lang.php
@@ -0,0 +1,17 @@
+ 'UTF-8',
+ 'MESSAGE_WRONG_VERIFICATION_CODE' => 'Der Prüfcode, den Sie eingegeben haben, ist nicht korrekt. Bitte versuchen Sie es erneut!'
+);
diff --git a/translations/en/oecaptcha_en_lang.php b/translations/en/oecaptcha_en_lang.php
new file mode 100755
index 0000000..45abef1
--- /dev/null
+++ b/translations/en/oecaptcha_en_lang.php
@@ -0,0 +1,17 @@
+ 'UTF-8',
+ 'MESSAGE_WRONG_VERIFICATION_CODE' => "The verification code you entered is not correct. Please try again."
+);
diff --git a/views/admin/de/module_options.php b/views/admin/de/module_options.php
new file mode 100644
index 0000000..8440e95
--- /dev/null
+++ b/views/admin/de/module_options.php
@@ -0,0 +1,13 @@
+ 'UTF-8',
+ 'SHOP_MODULE_GROUP_main' => 'Allgemein',
+ 'SHOP_MODULE_oecaptchakey' => 'Captcha Key',
+);
diff --git a/views/admin/en/module_options.php b/views/admin/en/module_options.php
new file mode 100644
index 0000000..b9b8e88
--- /dev/null
+++ b/views/admin/en/module_options.php
@@ -0,0 +1,13 @@
+ 'UTF-8',
+ 'SHOP_MODULE_GROUP_main' => 'General',
+ 'SHOP_MODULE_oecaptchakey' => 'Captcha Key',
+);
diff --git a/views/blocks/captcha_form.tpl b/views/blocks/captcha_form.tpl
new file mode 100644
index 0000000..8f10081
--- /dev/null
+++ b/views/blocks/captcha_form.tpl
@@ -0,0 +1,18 @@
+[{$smarty.block.parent}]
+
+[{assign var="oCaptcha" value=$oView->getCaptcha()}]
+
+
+
+ [{oxmultilang ident="ERROR_MESSAGE_INPUT_NOTALLFIELDS"}] +
+