Symfony 4 - Problem sending email after change my DNS - api

Click here
to see my diagram app.
Hey, my client change her DNS (like that : xxx-dns.com to dns.com) and this is ok, except one problem.. In react native app, I have contact form for send message to pro "partner", and this pro partner are in the process of switching their emails from xxx-dns.com to dns.com.
BUT the contact form provide by SwitchMailer doesn't work with the new DNS, I have check all configuration files, same for the server, the controller is (I think) ok.
Please help me, it's been a week
I have var_dump() all information in my controller, check api endpoint, navigate into my server and check configuration files.
This is my contact controller :
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Twig\Environment as Twig;
class ContactController extends AbstractController
{
/**
* #var string
*/
private $mailFrom;
/**
* #var string
*/
private $backUrl;
private $tokenStorage;
public function __construct(string $mailFrom, string $backUrl, TokenStorageInterface $tokenStorage)
{
$this->mailFrom = $mailFrom;
$this->backUrl = $backUrl;
$this->tokenStorage = $tokenStorage;
}
/**
* #Route("/contact", name="app_send_contact")
*/
public function sendAction(\Swift_Mailer $mailer, Twig $twig, Request $request)
{
// Retrieve user
$currentUser = $this->tokenStorage->getToken()->getUser();
if (!$currentUser) {
return $this->json(array('success' => false, 'message' => 'Utilisateur introuvable.'));
}
// Prepare parameters
$contactObject = $request->request->get('object');
$contactMessage = $request->request->get('message');
// Retrieve establishment
$establishment = $currentUser->getEstablishments()->first();
if (!$establishment) {
return $this->json(array('success' => false, 'message' => 'Etablissement introuvable.'));
}
// Prepare mail
$mailTitle = $currentUser->getFirstname() . ' ' . $currentUser->getLastname() . ' vous a envoyé un message : ' . $contactObject;
// Send mail to establishment
$message = (new \Swift_Message($mailTitle))
->setFrom($this->mailFrom)
->setTo($establishment->getEmail())
->setReplyTo($currentUser->getEmail(), $currentUser->getFirstname() . ' ' . $currentUser->getLastname())
->setBody(
$twig->render(
'emails/contact.html.twig',
array(
'user' => $currentUser,
'establishment' => $establishment,
'contact_object' => $contactObject,
'contact_message' => $contactMessage,
'back_url' => $this->backUrl,
)
),
'text/html'
);
$mailer->send($message);
// Prepare mail
$mailTitle = 'Confirmation de demande de contact';
// Send mail to parent
$message = (new \Swift_Message($mailTitle))
->setFrom($this->mailFrom)
->setTo($currentUser->getEmail())
->setBody(
$twig->render(
'emails/contact_confirmation.html.twig',
array(
'user' => $currentUser,
'establishment' => $establishment,
'contact_object' => $contactObject,
'contact_message' => $contactMessage,
'back_url' => $this->backUrl,
)
),
'text/html'
);
$mailer->send($message);
return $this->json(array('success' => true));
}
}```

Related

Add Pre default text in phalcon flash messages

In phalcon default flash messaging service only provide with default error div.
<div class="alert alert-warning">Our message</div>
But i want to add something inside div box like this.
<div class="alert alert-warning"> <button class="close">x</button> Our Message </div>
However, phalcon we are only allow to set only class of each message as per my knowledge.
$di->set('flash', function () {
return new FlashSession([
'error' => 'alert alert-danger alert-dismissible',
'success' => 'alert alert-success alert-dismissible',
'notice' => 'alert alert-info alert-dismissible',
'warning' => 'alert alert-warning alert-dismissible'
]);
});
Is there any configuration or any other way to add that close button on every message. I want something like
message = '<button class="close-btn">x</button>'+message
However i don't want to add this close button on every flash message because in future may be i need to change the class of close button so that in that case i need to change in all from the project.
You can do this by extending the Phalcon\FlashSession class and overriding the outputMessage() method, or by creating your own flash component to output the HTML you desire. Example of a custom flash component is below, we use a similar class when we develop with Falcon, this component assumes the existence of a session component in the DI.
This is untested but the code in principle would give you the ability to add a close button to the output HTML, or you can set specific HTML content for each message type in the relevant methods (error, success, warning, info).
Example usage:
// settings messages in your controllers / components
// 2nd param defines a position
$this->flashMessage->error('Something is bad!', 'form_top');
$this->flashMessage->success('Something is right!');
$this->flashMessage->info('Something is interesting!');
$this->flashMessage->warning('Something is worrying!');
// rendering messages in your views
// 1st param will render messages for a specific position if a position was set
$this->flashMessage->render();
$this->flashMessage->render('form_top');
Example class:
class FlashMessage extends Phalcon\Mvc\User\Component
{
/**
* #var array
**/
public $classmap = array();
/**
* Sets defaults for the class map (optional)
*
* #param array $classmap
**/
public function __construct($classmap = array()) {
// -- set the defaults
$this->classmap = array(
'error' => 'flash_message-error',
'success' => 'flash_message-success',
'info' => 'flash_message-info',
'warning' => 'flash_message-warning'
);
// -- set new class map options (also optional)
if (!empty($classmap)) {
foreach ($classmap as $key => $value) {
$this->classmap[$key] = $value;
}
}
}
/**
* error(), success(), info(), warning()
* Sets the flash messages
*
* #param string message
* #param string position
* #return string
**/
public function error($message, $position = '')
{
$this->session->flashMessage = array(
'position' => $position,
'message' => '<div class="' . $this->classmap['error'] . '">
' . $message . '
</div>
');
}
public function success($message, $position = '')
{
$this->session->flashMessage = array(
'position' => $position,
'message' => '<div class="' . $this->classmap['success'] . '">
' . $message . '
</div>
');
}
public function info($message, $position = '')
{
$this->session->flashMessage = array(
'position' => $position,
'message' => '<div class="' . $this->classmap['info'] . '">
' . $message . '
</div>
');
}
public function warning($message, $position = '')
{
$this->session->flashMessage = array(
'position' => $position,
'message' => '<div class="' . $this->classmap['warning'] . '">
' . $message . '
</div>
');
}
/**
* Check if theres messages in the session to render
*
* #param string $position
* #return bool
**/
public function hasMessage($position = null)
{
if (isset($this->session->flashMessage) && !empty($position)) {
return $this->session->flashMessage['position'] == $position ? true : false ;
} else {
return $this->session->flashMessage ? true : false ;
}
}
/**
* Renders the flash message
*
* #param string $position
* #return string
**/
public function render($position = null)
{
// -- store the message locally
$message = $this->session->flashMessage;
// -- check if there is in fact a flashed message
if (empty($message))
return;
// -- then remove from the session
$this->session->remove('FlashMessage');
// -- if no position the just return the message
if (is_null($position)) {
return $message['message'];
// -- else return the requested position
} elseif ($position == $message['position']) {
return $message['message'];
}
}
}
I am using something like this, you can extend it like you want. But this is just the gist of how it works:
class Messenger extends Component
{
protected static $_messageCloseHtml = '×';
/**
* #param array|string $messages
*/
public static function flashError($messages)
{
$messages = !is_array($messages) ? [$messages] : $messages;
foreach ($messages as $message) {
\Phalcon\Di::getDefault()->get('flashSession')->error(self::_getBody($message));
}
}
/**
* #param string $message
* #return string
*/
protected static function _getBody($message)
{
return self::$_messageCloseHtml . $message;
}
}
For every message, you can add some HTML code to the message.
My flashError is for the error messages. You can add the same method code for the warning, info and success.
So basically you extend the (existing) FlashSession and when assigning the messages you call a global method which adds additional text or html to your message.

Pass extra data to finder auth

My finder from Auth has conditions that I need to access $this->request but I don't have access for that on UsersTable.
AppController::initialize
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'finder' => 'auth',
]
]
]);
UsersTable
public function findAuth(Query $query, array $options)
{
$query
->select([
'Users.id',
'Users.name',
'Users.username',
'Users.password',
])
->where(['Users.is_active' => true]); // If I had access to extra data passed I would use here.
return $query;
}
I need pass extra data from AppController to finder auth since I don't have access to $this->request->data on UsersTable.
Update
People are saying on comments that is a bad design so I will explain exactly what I need.
I have a table users but each user belongs to a gym.
The username(email) is unique only to a particular gym so I can have a example#domain.comfrom gym_id 1 and another example#domain.com from gym_id 2.
On login page I have the gym_slug to tell to auth finder which gym the user username that I provided belongs.
To my knowledge, there is no way to do this by passing it into the configuration in 3.1. This might be a good idea submit on the cakephp git hub as a feature request.
There are ways to do it by creating a new authentication object that extends base authenticate and then override _findUser and _query. Something like this:
class GymFormAuthenticate extends BaseAuthenticate
{
/**
* Checks the fields to ensure they are supplied.
*
* #param \Cake\Network\Request $request The request that contains login information.
* #param array $fields The fields to be checked.
* #return bool False if the fields have not been supplied. True if they exist.
*/
protected function _checkFields(Request $request, array $fields)
{
foreach ([$fields['username'], $fields['password'], $fields['gym']] as $field) {
$value = $request->data($field);
if (empty($value) || !is_string($value)) {
return false;
}
}
return true;
}
/**
* Authenticates the identity contained in a request. Will use the `config.userModel`, and `config.fields`
* to find POST data that is used to find a matching record in the `config.userModel`. Will return false if
* there is no post data, either username or password is missing, or if the scope conditions have not been met.
*
* #param \Cake\Network\Request $request The request that contains login information.
* #param \Cake\Network\Response $response Unused response object.
* #return mixed False on login failure. An array of User data on success.
*/
public function authenticate(Request $request, Response $response)
{
$fields = $this->_config['fields'];
if (!$this->_checkFields($request, $fields)) {
return false;
}
return $this->_findUser(
$request->data[$fields['username']],
$request->data[$fields['password']],
$request->data[$fields['gym']],
);
}
/**
* Find a user record using the username,password,gym provided.
*
* Input passwords will be hashed even when a user doesn't exist. This
* helps mitigate timing attacks that are attempting to find valid usernames.
*
* #param string $username The username/identifier.
* #param string|null $password The password, if not provided password checking is skipped
* and result of find is returned.
* #return bool|array Either false on failure, or an array of user data.
*/
protected function _findUser($username, $password = null, $gym = null)
{
$result = $this->_query($username, $gym)->first();
if (empty($result)) {
return false;
}
if ($password !== null) {
$hasher = $this->passwordHasher();
$hashedPassword = $result->get($this->_config['fields']['password']);
if (!$hasher->check($password, $hashedPassword)) {
return false;
}
$this->_needsPasswordRehash = $hasher->needsRehash($hashedPassword);
$result->unsetProperty($this->_config['fields']['password']);
}
return $result->toArray();
}
/**
* Get query object for fetching user from database.
*
* #param string $username The username/identifier.
* #return \Cake\ORM\Query
*/
protected function _query($username, $gym)
{
$config = $this->_config;
$table = TableRegistryget($config['userModel']);
$options = [
'conditions' => [$table->aliasField($config['fields']['username']) => $username, 'gym' => $gym]
];
if (!empty($config['scope'])) {
$options['conditions'] = array_merge($options['conditions'], $config['scope']);
}
if (!empty($config['contain'])) {
$options['contain'] = $config['contain'];
}
$query = $table->find($config['finder'], $options);
return $query;
}
}
For more information see this: Creating Custom Authentication Objects
I know this is an old question but I thought I would post the finder I am using in one of our SaaS apps built on Cakephp 3. Does it follow DRY etc probably not. To say everything can be done X or Y way ..... you always have to bend the rules. In this case depending on the URL (xdomain.com or ydomain.com) our app figures out who the customer is and changes layouts etc. Also the user based is tied to Email & site_id much like yours
public function findAuth(\Cake\ORM\Query $query, array $options) {
$query
->select([
'Users.id',
'Users.email',
'Users.password',
'Users.site_id',
'Users.firstname',
'Users.lastname'])
->where([
'Users.active' => 1,
'Users.site_id'=> \Cake\Core\Configure::read('site_id')
]);
return $query;
}
Anyway hope it helps someone

ZF2 - init or something that is called in every module controller

I have a Module called "Backend" and in this module I want to check for valid authentication on all pages except the backend_login page. How do I do this? I tried to add it to the onBootstrap in the Backend/Module.php , but it turns out that is called in my other modules as well... which is of course not what I want.
So how do I do this?
Thanks in advance!
To get clear information about zf2 authentication you can follow:
ZF2 authentication
adapter auth
database table auth
LDAP auth
digest auth....These all are different methods here is an example of database table auth:
in every controller's action, where you need user auth something should like this:
use Zend\Authentication\Result;
use Zend\Authentication\AuthenticationService;
use Zend\Authentication\Adapter\AdapterInterface;
use Zend\Db\Adapter\Adapter as DbAdapter;
use Zend\Authentication\Adapter\DbTable as AuthAdapter;
public function login($credential)
{
$bcrypt = new Bcrypt();
$user = new User();
$auth = new AuthenticationService();
$user->exchangeArray($credential);
$password = $user->password;
$data = $this->getUserTable()->selectUser($user->username);
if (!$data){
$message = 'Username or password is not correct!';
}
elseif($auth->getIdentity() == $user->username){
$message = 'You have already logged in';
}
elseif($bcrypt->verify($password, $data->password)){
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$authAdapter = new AuthAdapter(
$dbAdapter,
'user',
'username',
'password'
);
$authAdapter -> setIdentity($user->username) -> setCredential($data->password);
$result = $auth->authenticate($authAdapter);
$message = "Login succesfull.Welcome ".$result->getIdentity();
} else {
$message = 'Username or password is not correct';
}
return new ViewModel(array("message" =>$message));
}
Like this in every action you can check whether it is authenticated or not
if($auth -> hasIdentity()){
//your stuff
}
else{
//redirected to your login route;
}
I had once a similar problem and figured it out within my Module.php in the onBootstrap() function. Try this, it worked for me:
class Module {
// white list to access with being non-authenticated
//the list may contain action names, controller names as well as route names
protected $whitelist = array('login');
//....
public function onBootstrap($e){
$app = $e->getApplication();
$em = $app->getEventManager();
$sm = $app->getServiceManager();
$list = $this->whitelist;
$auth = new AuthenticationService();
$em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($list, $auth) {
$match = $e->getRouteMatch();
// No route match, this is a 404
if (!$match instanceof RouteMatch) {
return;
}
// Route is whitelisted
$action = $match->getParam('action');
if (in_array($action, $list) ) {
return;
}
// User is authenticated
if ($auth->hasIdentity()){
return;
}
// the user isn't authenticated
// redirect to the user login page, as an example
$router = $e->getRouter();
$url = $router->assemble(array(
'controller' => 'auth',
'action'=>'login'
), array(
'name' => 'route_name',
));
$response = $e->getResponse();
$response->getHeaders()->addHeaderLine('Location', $url);
$response->setStatusCode(302);
return $response;
}, -100);
}
}
Or you may see bjyauthorize.

Magento product.create websites argument

I have a question about the websites argument in the magento api.
Nowhere can I find an explanation of what this variable is.
Does this variable represent a storeview? a store? a website?
Where in the api can I retrieve a list of available options?
If I cannot retrieve a list from the API, where in the backend menu can I find the static variable that I can use?
Do I need the website ID or storeID?
I use soap v1
function call($which,$vars=null)
{
// retourneer de output soap client api call
if($vars !== null)
{
return $this->soapclient->call($this->sessiontoken,$which,$vars);
}
else
{
return $this->soapclient->call($this->sessiontoken,$which);
}
}
function createProduct($productname,
$websites,
$shortdescription,
$description,
$status,
$weight,
$tax_class_id,
$categories,
$price,
$attributesetid,
$producttype,
$sku)
{
$attributeSets = $this->call('product_attribute_set.list');
$set = current($attributeSets);
try
{
$x = $this->call('product.create', array($producttype, $set['set_id'], $sku, array(
'name' => $productname,
// websites - Array of website ids to which you want to assign a new product
'websites' => $websites, // array(1,2,3,...)
'short_description' => $shortdescription,
'description' => $description,
'status' => $status,
'weight' => $weight,
'tax_class_id' => $tax_class_id,
'categories' => $categories, //3 is the category id(array(3))
'price' => $price
);));
}
catch(Exception $e)
{
$x = 0xABED + 0xCAFE + 0xBAD + 0xBED * 0xFACE;// abed went to a cafe... the alcohol went bad.... he stumbled into bed and fell face down...
}
return $x;
}
Looking at Mage_Catalog_Model_Product_Api::create():
public function create($type, $set, $sku, $productData, $store = null)
{
//[...]
$product = Mage::getModel('catalog/product');
$product->setStoreId($this->_getStoreId($store))
->setAttributeSetId($set)
->setTypeId($type)
->setSku($sku);
//[...]
$this->_prepareDataForSave($product, $productData);//this does some processing
Now, looking at Mage_Catalog_Model_Product_Api::_prepareDataForSave():
protected function _prepareDataForSave($product, $productData)
{
if (isset($productData['website_ids']) && is_array($productData['website_ids'])) {
$product->setWebsiteIds($productData['website_ids']);
}
//....
we see that website_ids (numeric array) are expected

How to let the user choose the upload directory?

I have a form used to upload images in my blog engine. The files are uploaded to web/uploads, but I'd like to add a "choice" widget to let the users pick from a list of folders, for instance 'photos', 'cliparts', 'logos'.
Here's my form
class ImageForm extends BaseForm
{
public function configure()
{
$this->widgetSchema->setNameFormat('image[%s]');
$this->setWidget('file', new sfWidgetFormInputFileEditable(
array(
'edit_mode'=>false,
'with_delete' => false,
'file_src' => '',
)
));
$this->setValidator('file', new mysfValidatorFile(
array(
'max_size' => 500000,
'mime_types' => 'web_images',
'path' => 'uploads',
'required' => true
)
));
$this->setWidget('folder', new sfWidgetFormChoice(array(
'expanded' => false,
'multiple' => false,
'choices' => array('photos', 'cliparts', 'logos')
)
));
$this->setValidator('folder', new sfValidatorChoice(array(
'choices' => array(0,1,2)
)));
}
}
and here is my action :
public function executeAjout(sfWebRequest $request)
{
$this->form = new ImageForm();
if ($request->isMethod('post'))
{
$this->form->bind(
$request->getParameter($this->form->getName()),
$request->getFiles($this->form->getName())
);
if ($this->form->isValid())
{
$this->form->getValue('file')->save();
$this->image = $this->form->getValue('file');
}
}
I'm using a custom file validator :
class mySfValidatorFile extends sfValidatorFile
{
protected function configure($options = array(), $messages =
array())
{
parent::configure();
$this->addOption('validated_file_class',
'sfValidatedFileFab');
}
}
class sfValidatedFileFab extends sfValidatedFile
{
public function generateFilename()
{
return $this->getOriginalName();
}
}
So how do I tell the file upload widget to save the image in a different folder ?
You can concatenate the directory names you said ('photos', 'cliparts', 'logos') to the sf_upload_dir as the code below shows, you will need to create those directories of course.
$this->validatorSchema['file'] = new sfValidatorFile(
array('path' => sfConfig::get('sf_upload_dir' . '/' . $path)
));
Also, you can have those directories detailes in the app.yml configuration file and get them calling to sfConfig::get() method.
I got it to work with the following code :
public function executeAdd(sfWebRequest $request)
{
$this->form = new ImageForm();
if ($request->isMethod('post'))
{
$this->form->bind(
$request->getParameter($this->form->getName()),
$request->getFiles($this->form->getName())
);
if ($this->form->isValid())
{
//quel est le dossier ?
switch($this->form->getValue('folder'))
{
case 0:
$this->folder = '/images/clipart/';
break;
case 1:
$this->folder = '/images/test/';
break;
case 2:
$this->folder = '/images/program/';
break;
case 3:
$this->folder = '/images/smilies/';
break;
}
$filename = $this->form->getValue('file')->getOriginalName();
$this->form->getValue('file')->save(sfConfig::get('sf_web_dir').$this->folder.$filename);
//path :
$this->image = $this->folder.$filename;
}
}