en Jump to content
NemoPS

[FREE MODULE] Ask a question

Recommended Posts

Not really, it should just hook to the tabContent area. One thing that won't work for sure is the displayAdminProductsExtra hook, to check questions in the product's back office

Share this post


Link to post
Share on other sites

Not really, it should just hook to the tabContent area. One thing that won't work for sure is the displayAdminProductsExtra hook, to check questions in the product's back office

Is there any way to get it work in 1.7 by changing some coding.?

Share this post


Link to post
Share on other sites

See if the hook runs I guess. In the module's core file, hookProductTabContent, add this

die('a');

See if the product page dies to 'a'

If so, keep moving it down until you reach a breakpoint

Share this post


Link to post
Share on other sites

Thank you for this awesome module. Is perfect and work just fine. 
I have only one issue with this :)  

I can not move the hook. For the moment it show the question/answer  in More info tab. (Informatio tab)
I want hook under or above blockproductscategory for example.  On the bottom of our the website. 

I remove all the hooks from module, I have hooked step by step but no good result. 

post-1380816-0-44930300-1506604859_thumb.jpg 

Any ideea ? 

Thank you 

Share this post


Link to post
Share on other sites

Hello

 

is it possible send e-mail to admin (e-shop owner) when question is placed?

 

I see mail template "qna_admin" in mails folder and PHP function sendRequest() in prestagna.php file with title "New question to be moderated", but nothing happend when question is placed.

 

Is that function disabled?

Share this post


Link to post
Share on other sites

Hello,
Yes, it's supposed to actually, what language do you use?

As for the hook, you can just clone hookDisplayProductTabContent and rename it to hookFooterProduct

Share this post


Link to post
Share on other sites
Good morning, I downloaded a module "ask a question" to ask questions to customers and followed the steps of the following link to configure it: http://sobreprestashop.blogspot.com.es/2014/11/integrar-modulo-en the-page-of-the-page-of-product-in-prestashop1.6.html #

The problem is after having followed the steps of the link happens that this module is duplicated in each tab of the tab of the products: in the more, in reviews and in the tab itself ask a question. Would anyone know how to fix it or why? Thank you very much.

Share this post


Link to post
Share on other sites

Hello,

 

is there a way to automatically disable some products when another module enables them?

 

I have an automatic import manager with more than 20k items and it re-enables them when the cron runs.

 

Thank you and sorry for any inconvenience

 

Daniel

Share this post


Link to post
Share on other sites
Hi Nemo, 

 

Great module and nice job but i can't place the module in tab. (website PS 1.6.1.13)

 

In modules position, i have these hooks: displayProductTab and displayProductTabContent but appears below the product tabs.

 

 

 

How can i place the module in one tab ?   

 

Thanks and sorry for my english.

Edited by tresorsdargan

Share this post


Link to post
Share on other sites

Hello nemo. 

First thanks for great module.

I added this module to cms page. I create a hook and now i can see module in cms page,but send button not work. can you help me fix it? 

I want create section where customer can ask a question not only about products and all questions and answers are in one place.

Share this post


Link to post
Share on other sites

So i try to change php code of module but all i get is blank page of my site. can you help me change it if you have free time?

i just want to do it only for cms, i don´t need to use it in product table.

i try add id-cms to database and change some line in php but all wrong.

thanks

Share this post


Link to post
Share on other sites

Hi Nemo,

Hope you are well and finally settled (we had email corespondence while back)

Im using this module and its great but a lot space for improvements.
Of course, implementing needs time and time is money but I would agree on payed version :)

Here is a simple modification that would be helpful a lot.

Sometimes when we have few questions that we need to respond to, we dont have option to answer one and then publish it and leave others to replay later.
For example if we have 3 questions and we write one answer and leave other 2 not answered and click save, all 3 will dissapear from the list and we would need to go into each product and respond them one by one.

This is quite hard as we dont know where are those product in the list which is you must admint a bit messy.
http://prntscr.com/hdaz7k

I hope i was clear enough. If not I can make a video :)

Share this post


Link to post
Share on other sites

Hi nemo,

This module is working fine, the only problem I have is that there is and error in the first line of the following files: "qna_admin.html", "qna_answered.html" and "qna_rejected.html"; located in modules/prestaqna/mails/en. This is causing the emails that are being send to be empty, but I don't know how to solve it.

This is the line that is giving the error (Erroneous DOCTYPE. Expected <!DOCTYPE html>:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">

Could you help me, please?

 

 

 

 

Edited by herbobcn

Share this post


Link to post
Share on other sites

Not by default, you have to assign it in the core file (I don't have it handy right now, so I can't recall the exact name of the method, but it's something like sendMail)

Share this post


Link to post
Share on other sites

Hello!!

First of all, congrats for this amazing job! Is exactly what I was looking for!

But, I work with Prestashop 1.7 and I couldn't make it work, nothing appears on product pages or product tabs.

What I'm doing wrong?

Thanks!!

Share this post


Link to post
Share on other sites

Not at the moment, the 1.7 user base is too small right now, and the version itself has some very annoying quirks to make it worth the time investment. Maybe for 1.8 :)

Share this post


Link to post
Share on other sites

@NemoPS You are the star of this forum but my question is quite simple - is this module is SPAM free? What kind of security is included in this script to prevent bots from using it?

I am asking due to some prestashop spam problems and just to be sure if this module is 100% safe to use :) How it is safe in the backend section as well?

Share this post


Link to post
Share on other sites

Very interesting question.

I was concerned by contact form mail.ru spam and installed server a,d form recaptcha protection.

Is there a risk with the question module NemoPS ? I guess there is :(

Edited by KevinNash

Share this post


Link to post
Share on other sites

There is a bug when using in 1.6 in prestaqna.php and if You try to delete something it is doing nothing because it had DB_PREFIX in delete instance
 

if(!Db::getInstance()->delete($this->table_name, 'id_qna ='.(int)(Tools::getValue('reject'))))

which was something like ps_ps_qna insead of ps_qna.
Change in 2 places this code to

if(!Db::getInstance()->delete(_DB_PREFIX_.$this->table_name, 'id_qna ='.(int)(Tools::getValue('reject'))))

and deleting will be working again :)


But my question is not only about SPAM FREE but about entire system free :) I saw some pSQL() in queries and You are realy skilled developer but this is quite old module and could You just look to see if there is any security flaws that I might concider to fix? :) 
 

Edited by hakeryk2

Share this post


Link to post
Share on other sites

I understand your concern. Yes it is old and yes I would do it if I had enough time. At the same time, the market has shrunk and it's a free module, it would need a complete revamp but  right now it's just not cost effective, and I have other things to do as well business-wise(yeah I do realize it's a sucky answer, but it's real)

Share this post


Link to post
Share on other sites

Too bad Nemo ;)

It is indeed a wonderful and useful module.

Can't you find some time ( I know, I know, it is easy to say ) to just update it a little on the security part ?

Share this post


Link to post
Share on other sites
On 9.03.2018 at 10:35 PM, NemoPS said:

I understand your concern. Yes it is old and yes I would do it if I had enough time. At the same time, the market has shrunk and it's a free module, it would need a complete revamp but  right now it's just not cost effective, and I have other things to do as well business-wise(yeah I do realize it's a sucky answer, but it's real)


Ok, thanks for letting me know. I made up it by myselft with including spam protection with ReCaptcha from Google (wow, it was easier than I thought), I double checked entire code and everythings seems to be ok now.

There is a one issue - I would love to share this with users but I made so many changes based only for my shop that it is just impossible but if someone want to know how to add google recaptcha to this I can write it.

Thank You for this - it was quite fun to make it fit for my needs.

Share this post


Link to post
Share on other sites

Hi hakeryk2,

Like you my module is heavily modified to fit my shop.

I am very, very interested to add Google ReCaptcha :)

Can you please share how to do it ?

Share this post


Link to post
Share on other sites

Ok, I will try because I noticed that I received a few spam mails since I am using this module, and after implementing reCaptcha spam is gone. @NemoPS You can attach link to this post in Your first post in this thread to make it easier to find for new users .



1) Go to https://www.google.com/recaptcha/admin#list and get Your reCaptcha secret keys. Type the labels of Your project, Choose the type of reCaptcha reCaptcha V2 or Invisible reCaptcha (I choosed Invinsible). Types domains that You will use recaptcha in. Hit Register button.

2) After that You will see that You earned Site key and Secret Key - note them somewhere or leave the tab in browser. You will need them.

3) Open modules\prestaqna\views\templates\hook\prestaqna_tab_content.tpl or prestaqna_tab_content15.tpl if You are using 1.5 and add on the begining of the file this code:

<script src="https://www.google.com/recaptcha/api.js" async defer></script>

Before that code responsible for creating a send button 

<a href="javascript:void(0)" title="{l s='Send question!' mod='prestaqna'}" class="btn btn-default" id="submitQNA">{l s='Send question!' mod='prestaqna'}</a>

add this code that will display recaptcha box, please add Site Key to this (not secret key)

<div class="g-recaptcha" data-sitekey="yourSiteKeyCodeFromPoint2"></div>


4) Now open modules\prestaqna\prestaqna.php and look for public static function sendRequest($postdata). To made it easier for You I will post entire function with changes and just replace entire function.

!!! Please fill your Secret Key to $secret variable
 

public static function sendRequest($postdata)
	{
		$message = $postdata['qna_q'];
		$name = $postdata['qna_name'];
		$email = $postdata['qna_email'];
		$product = $postdata['qna_prod'];


		if (!Validate::isMessage($message))
			return 'mex'; //invalid message
		if (!Validate::isGenericName($name))
			return 'name'; //invalid message
		if (!Validate::isEmail($email))
			return 'mail'; //invalid message

		if (isset($postdata['g-recaptcha-response']) && !empty($postdata['g-recaptcha-response'])) {
			
			//your site secret key
			$secret = 'YourSECRETKeyThatYouReceivedFROMGoogle';
			
			$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' . $secret . '&response=' . $postdata['g-recaptcha-response']);
			$responseData = json_decode($verifyResponse);
			if ($responseData->success) {
				$data = array('question' => pSQL($message), 'email' => pSQL($email), 'name' => pSQL($name), 		'approved' => 0, 'id_product' =>(int)$product, 'date_added' => date('Y-m-d'));
				$name = Product::getProductName((int)$product);

				if(!Db::getInstance()->insert('qna', $data))
					return 'err';

				if(version_compare(_PS_VERSION_, '1.5', '>'))
				{
					$context = Context::getContext();
					Mail::Send($context->language->id, 'qna_admin', Mail::l('New question to be moderated'),
						array(
							'{message}' => $message,
							'{product_name}' => $name,
							'{author_email}' => $email
						),
						strval(Configuration::get('PS_SHOP_EMAIL')), NULL, strval(Configuration::get('PS_SHOP_EMAIL')), NULL, NULL, NULL, dirname(__FILE__).'/mails/');
					return true;
				} else {
					global $cookie;
					Mail::Send($cookie->id_lang, 'qna_admin', Mail::l('New question to be moderated'),
						array(
							'{message}' => $message,
							'{product_name}' => $name,
							'{author_email}' => $email
						),
						strval(Configuration::get('PS_SHOP_EMAIL')), NULL, strval(Configuration::get('PS_SHOP_EMAIL')), NULL, NULL, NULL, dirname(__FILE__).'/mails/');
					return true;
				}
			} else {
				return 'Failed to receive success status from reCaptcha!';
			}
		} else {
			return 'Please tick the box in reCAPTCHA form.';
		}
	}

And that is it. Upload the files, remove the cache files from theme and tell me if it works for You.

Main issue with that is that it is not working on localhost so You will have to made changes in working site online.

 

Edited by hakeryk2
Some fix thanks to Kevin

Share this post


Link to post
Share on other sites

Thank you very much hakeryk2, it works like a charm !

I have 2 questions :

=>

'{author_email}' => $email

I don't have this piece of code in my original file, I tried with it but no customer email in the email I receive but I would love to get it here.

I suppose you modifier the module to achieve that, can you help me t odo the same ?

=> About the recaptcha, does it also prevent direct code submission by a bot ? I mean a bit who would send directly a POST without a real use of the form ?

For example this modification prevent humans and bot spam for contact-form http://area51.enter-solutions.com/snippets/74

Thanks in advance :)

Edited by KevinNash

Share this post


Link to post
Share on other sites

Ok, I edited it on my version and I was looking into original file and I forgot to remove this

'{author_email}' => $email

but this is adding {author_email} variable aviailable in email template prestaqna/mails/yourlanguage/qna_admin.html and qna_admin.txt. It is quite usefull to get this email in message to Your shop because sometimes you will reply via your original email, not through Q&A panel because question is quite fragile and You don't want to have it on Your site. It is often usefull if You will delete by accident this question from shop but You still want to reply to this question. You will know where to reply :)

 

Yes, it is preventing bot from submitting a post without content as well :) NemoPS took care of validation and there is no chance to do something by this because in post there is a secret key and if it is not the same the rest of code will not to be executed.

Edit, Oh sorry - You can move this part
 

$data = array('question' => pSQL($message), 'email' => pSQL($email), 'name' => pSQL($name), 'approved' => 0, 'id_product' =>(int)$product, 'date_added' => date('Y-m-d'));

into this if statement

if ($responseData->success) {
	$data = array('question' => pSQL($message), 'email' => pSQL($email), 'name' => pSQL($name), 'approved' => 0, 'id_product' =>(int)$product, 'date_added' => date('Y-m-d'));
// rest of the code


I edited post above with proper solution. Dunno why i did this way :) Now is ok.

If You want I can share modification that is allowing You approve question one by one, not all of them in bulk like it is in original version. It was annoying that I had to reply all of the question and then submit so I changed this to make it one by one.

Edited by hakeryk2

Share this post


Link to post
Share on other sites

The space before 'approved' seems to be a little bit too long ;) :

 

$data = array('question' => pSQL($message), 'email' => pSQL($email), 'name' => pSQL($name), 		'approved' => 0, 'id_product' =>(int)$product, 'date_added' => date('Y-m-d'));
				$name = Product::getProductName((int)$product);

 

Edit : I moved the part a you said but what does it change exactly ? It worked before the swap and it still works.

Edited by KevinNash

Share this post


Link to post
Share on other sites
Quote

Edit : I moved the part a you said but what does it change exactly ? It worked before the swap and it still works.


@KevinNash Before question was submitted into database before checking ReCaptcha and it was only sending email when recaptcha was correct, after change if captcha is not correct then question is not added to database at all. Prevent to attack database by bots and spammers (same thing xD).


So ... now. For everyone who wants to have ability to accept/approve answers to questions one by one instead of default one like "You have to answer all of the question because If You don't or you will answer only for one question and You hit "Approve Q&Ns" then You will accept empty answers for them". So, let's begin. I am working on non-modified version from first post. We will add link to product in front office as well.

questions.thumb.png.a3ef22eac27b90d5bec18d34acfeb53a.png

 

  1. Open modules/prestaqna/prestaqna.php and look for line 200 with this:
    <tr><th>'.$this->l('Product').'</th><th>'.$this->l('Question').'</th><th>'.$this->l('By').'</th><th>'.$this->l('E-mail').'</th><th>'.$this->l('Answer').'</th><th></th></tr>

    and change it to this (we are adding one <th></th>
     

    <tr><th>'.$this->l('Product').'</th><th>'.$this->l('Question').'</th><th>'.$this->l('By').'</th><th>'.$this->l('E-mail').'</th><th>'.$this->l('Answer').'</th><th></th><th></th></tr>

     

  2. Now go to line 218 and after this
     

    <td><a href="'.$thispage.'&reject='.$question['id_qna'].'" title="'.$this->l('Reject').'"><img src="../img/admin/delete.gif" alt="Delete"></a></td>

    add this code which will create an accept button so Your code will look like this
     

    <td><a href="'.$thispage.'&reject='.$question['id_qna'].'" title="'.$this->l('Reject').'"><img src="../img/admin/delete.gif" alt="Delete"></a></td>
    <td><input type="image" src="../img/admin/ok.gif" class="btn btn-success" name="accept" value="'.$question['id_qna'].'"></td>

     

  3. Now let's move to getContent() function and look for line responsible for rejecting a question which starts in 98 line and ends in 113. It looks like this
     

    else if (Tools::isSubmit('reject'))
    		{
    			$email = Db::getInstance()->getValue('SELECT email FROM '._DB_PREFIX_.$this->table_name. ' WHERE id_qna ='.(int)(Tools::getValue('reject')));
    			if(!Db::getInstance()->delete(_DB_PREFIX_.$this->table_name, 'id_qna ='.(int)(Tools::getValue('reject'))))
    				$this->_errors[] = mysql_error();
    			// else {
    			// if(!Mail::Send($cookie->id_lang, 'qna_rejected', $this->l('Question rejected'),
    			// 	array(),
    			// 	$email, NULL, strval(Configuration::get('PS_SHOP_EMAIL')), strval(Configuration::get('PS_SHOP_NAME')), NULL, NULL, dirname(__FILE__).'/mails/', true))
    			// 	$this->_errors[] = $this->l('Error while sending notification email');
    			// }
    
    			if (!$this->_errors)
    				$this->_html .= $this->displayConfirmation($this->l('Question rejected!'));
    
    		}

    After that we have to add another else if statement which accepting so the code will look like this
     

    else if (Tools::isSubmit('reject'))
    		{
    			$email = Db::getInstance()->getValue('SELECT email FROM '._DB_PREFIX_.$this->table_name. ' WHERE id_qna ='.(int)(Tools::getValue('reject')));
    			if(!Db::getInstance()->delete(_DB_PREFIX_.$this->table_name, 'id_qna ='.(int)(Tools::getValue('reject'))))
    				$this->_errors[] = mysql_error();
    			// else {
    			// if(!Mail::Send($cookie->id_lang, 'qna_rejected', $this->l('Question rejected'),
    			// 	array(),
    			// 	$email, NULL, strval(Configuration::get('PS_SHOP_EMAIL')), strval(Configuration::get('PS_SHOP_NAME')), NULL, NULL, dirname(__FILE__).'/mails/', true))
    			// 	$this->_errors[] = $this->l('Error while sending notification email');
    			// }
    
    			if (!$this->_errors)
    				$this->_html .= $this->displayConfirmation($this->l('Question rejected!'));
    
    		} else if (Tools::isSubmit('accept')) {
    
    			$answers = Tools::getValue('answer');
    			$id_qna = (int)Tools::getValue('accept');
    
    			$answer = $answers[$id_qna];
    
    			if (!$answer['answer']) {
    				$this->_errors[] = $this->l('You did not provide answer to the question');
    				return false;
    			} else if (!Db::getInstance()->update($this->table_name, array('question' => pSQL($answer['question']), 'answer' => pSQL($answer['answer']), 'approved' => 1), 'id_qna = '.$id_qna)) {
    				$this->_errors[] = $this->l('Error while approving question ID #') . (int)$id_qna . ': ' . mysql_error();
    			} else { //validated, send email to the customer
    				// Rebuild the cache for product if using external caching systems
    				$product = new Product((int)$answer['id_product']);
    				if (Validate::isLoadedObject($product))
    					$product->save();
    
    				if (!$this->sendEmail($answer['email'], (int)$answer['id_product'], $answer['pname']))
    					$this->_errors[] = $this->l('Error while sending the email to').' '.$answer['email'];
    
    			}
    		} // end adding accept


    And that is it.

    Oh, and if You want a product name to be a link to the product just add after 227 line with foreach statement
     

    foreach ($pending as $question) {
    	// added to create a product link
        $link = new Link();
        
        // .....rest of the code


    and change line 235 from

    '.$question['pname'].'

    to this

    <a target="_blank" href="'.$link->getProductLink((int)$question['id_product']).'">'.$question['pname'].'</a>


    Good luck.

     

Edited by hakeryk2

Share this post


Link to post
Share on other sites

Thanks nemo and hakeryk2.

on hakeryk2 tip for accept one question by one, you should remove or comment 

return false; to get empty reply error.

Or you should remove entire first if statement for ability of accept comments without mandatory admin reply..

should look like:

} else if (Tools::isSubmit('accept')) {

			$answers = Tools::getValue('answer');
			$id_qna = (int)Tools::getValue('accept');

			$answer = $answers[$id_qna];

			if (!Db::getInstance()->update($this->table_name, array('question' => pSQL($answer['question']), 'answer' => pSQL($answer['answer']), 'approved' => 1), 'id_qna = '.$id_qna)) {
				$this->_errors[] = $this->l('Error while approving question ID #') . (int)$id_qna . ': ' . mysql_error();
			} else { //validated, send email to the customer
				// Rebuild the cache for product if using external caching systems
				$product = new Product((int)$answer['id_product']);
				if (Validate::isLoadedObject($product))
					$product->save();

				if (!$this->sendEmail($answer['email'], (int)$answer['id_product'], $answer['pname']))
					$this->_errors[] = $this->l('Error while sending the email to').' '.$answer['email'];

			}
		} // end adding accept

Thanks again..

Share this post


Link to post
Share on other sites

Well, actually I made that for myself and I forgot to share with this :) Tommorow I will add this feature to you guys.

All You need to do is change entire foreach statement from this:
 

foreach ($answers as $id_qna => $content) {
				if(!Db::getInstance()->update($this->table_name, array('question' => pSQL($content['question']), 'answer' => pSQL($content['answer']), 'approved' => 1), 'id_qna = '.$id_qna))
					$this->_errors[] = $this->l('Error while approving id #').$id_qna.': '.mysql_error();
				else { //validated, send email to the customer
					if(!$this->sendEmail($content['email'], $content['id_product'], $content['pname']))
						$this->_errors[] = $this->l('Error while sending the email to').' '.$content['email'];
				}
			}

To this one:
 

foreach ($answers as $id_qna => $content) {
				if (!empty($content['answer'])) {
					if (!Db::getInstance()->update($this->table_name, array('question' => pSQL($content['question']), 'answer' => pSQL($content['answer']), 'approved' => 1), 'id_qna = '.$id_qna)) {
						$this->_errors[] = $this->l('Error while approving id #').$id_qna.': '.mysql_error();
					} else {
						//validated, send email to the customer
						// Rebuild the cache for product
						$product = new Product((int)$content['id_product']);
						if (Validate::isLoadedObject($product))
							$product->save();

						if(!$this->sendEmail($content['email'], $content['id_product'], $content['pname']))
							$this->_errors[] = $this->l('Error while sending the email to').' '.$content['email'];
					}
				} else {
					$this->_errors[] = $this->l('There was no answer for question #') . $id_qna;
				}
			}

 

Edited by hakeryk2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More