On enlève le repeat sur le background

This commit is contained in:
2020-04-10 19:42:04 +02:00
parent 6a785b781c
commit 50d80ab3fd
20 changed files with 1257 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,426 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace PhpList\Api;
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 18/07/2016 19:58
*/
/**
*
* example PHP client class to access the phpList Rest API.
* License: MIT, https://opensource.org/licenses/MIT
*
* To use this class, you need the restapi plugin for phpList, https://resources.phplist.com/plugin/restapi
* Set the parameters below to match your system:
*
* - url : URL of your phpList installation
* - loginName : admin login
* - password : matching password
* - remoteProcessingSecret : (optional) the secret as defined in your phpList settings
*
* v 1.01 Nov 26, 2015 added optional secret on instantiation
* v 1 * Michiel Dethmers, phpList Ltd, November 18, 2015
* Initial implementation of basic API calls
*/
class PhpListRESTApiClient
{
/*
* URL of the API to connect to including the path
* generally something like.
*
* https://website.com/lists/admin/?pi=restapi&page=call
*/
private $url;
/*
* login name for the phpList installation.
*/
private $loginName;
/*
* password to login.
*/
private $password;
/*
* the path where we can write our cookiejar.
*/
public $tmpPath;
/*
* optionally the remote processing secret of the phpList installation
* this will increase the security of the API calls.
*/
private $remoteProcessingSecret;
/**
* construct, provide the Credentials for the API location.
*
* @param string $url URL of the API
* @param string $loginName name to login with
* @param string $password password for the account
* @param string $secret
*/
public function __construct($url, $loginName, $password, $secret = '')
{
$this->tmpPath = sys_get_temp_dir();
$this->url = $url;
$this->loginName = $loginName;
$this->password = $password;
$this->remoteProcessingSecret = $secret;
}
/**
* Make a call to the API using cURL.
*
* @param string $command The command to run
* @param array $post_params Array for parameters for the API call
* @param bool $decode json_decode the result (defaults to true)
*
* @return string result of the CURL execution
*/
private function callApi($command, $post_params, $decode = true)
{
$post_params['cmd'] = $command;
// optionally add the secret to a call, if provided
if (!empty($this->remoteProcessingSecret)) {
$post_params['secret'] = $this->remoteProcessingSecret;
}
$post_params = http_build_query($post_params);
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $this->url);
curl_setopt($c, CURLOPT_HEADER, 0);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_POST, 1);
curl_setopt($c, CURLOPT_POSTFIELDS, $post_params);
curl_setopt($c, CURLOPT_COOKIEFILE, $this->tmpPath.'/phpList_RESTAPI_cookiejar.txt');
curl_setopt($c, CURLOPT_COOKIEJAR, $this->tmpPath.'/phpList_RESTAPI_cookiejar.txt');
curl_setopt($c, CURLOPT_HTTPHEADER, array('Connection: Keep-Alive', 'Keep-Alive: 60'));
// Execute the call
$result = curl_exec($c);
// Check if decoding of result is required
if ($decode === true) {
$result = json_decode($result);
}
return $result;
}
/**
* Use a real login to test login api call.
*
* @param none
*
* @return bool true if user exists and login successful
*/
public function login()
{
// Set the username and pwd to login with
$post_params = array(
'login' => $this->loginName,
'password' => $this->password,
);
// Execute the login with the credentials as params
$result = $this->callApi('login', $post_params);
return $result->status == 'success';
}
/**
* Create a list.
*
* @param string $listName Name of the list
* @param string $listDescription Description of the list
*
* @return int ListId of the list created
*/
public function listAdd($listName, $listDescription)
{
// Create minimal params for api call
$post_params = array(
'name' => $listName,
'description' => $listDescription,
'listorder' => '0',
'active' => '1',
);
// Execute the api call
$result = $this->callApi('listAdd', $post_params);
// get the ID of the list we just created
$listId = $result->data->id;
return $listId;
}
/**
* Get all lists.
*
* @return array|false All lists
*/
public function listsGet()
{
// Create minimal params for api call
$post_params = array(
);
// Execute the api call
$result = $this->callApi('listsGet', $post_params);
// Return all list as array
return $result !== null ? $result->data : false;
}
/**
* Find a subscriber by email address.
*
* @param string $emailAddress Email address to search
*
* @return int $subscriberID if found false if not found
*/
public function subscriberFindByEmail($emailAddress)
{
$params = array(
'email' => $emailAddress,
);
$result = $this->callApi('subscriberGetByEmail', $params);
if (!empty($result->data->id)) {
return $result->data->id;
} else {
return false;
}
}
/**
* Add a subscriber.
*
* This is the main method to use to add a subscriber. It will add the subscriber as
* a non-confirmed subscriber in phpList and it will send the Request-for-confirmation
* email as set up in phpList.
*
* The lists parameter will set the lists the subscriber will be added to. This has
* to be comma-separated list-IDs, eg "1,2,3,4".
*
* @param string $emailAddress email address of the subscriber to add
* @param string $lists comma-separated list of IDs of the lists to add the subscriber to
*
* @return int $subscriberId if added, or false if failed
*/
public function subscribe($emailAddress, $lists)
{
// Set the user details as parameters
$post_params = array(
'email' => $emailAddress,
'foreignkey' => '',
'htmlemail' => 1,
'subscribepage' => 0,
'lists' => $lists,
);
// Execute the api call
$result = $this->callApi('subscribe', $post_params);
if (!empty($result->data->id)) {
$subscriberId = $result->data->id;
return $subscriberId;
} else {
return false;
}
}
/**
* Fetch subscriber by ID.
*
* @param int $subscriberID ID of the subscriber
*
* @return the subscriber
*/
public function subscriberGet($subscriberId)
{
$post_params = array(
'id' => $subscriberId,
);
// Execute the api call
$result = $this->callApi('subscriberGet', $post_params);
if (!empty($result->data->id)) {
$fetchedSubscriberId = $result->data->id;
$this->assertEquals($fetchedSubscriberId, $subscriberId);
return $result->data;
} else {
return false;
}
}
/**
* Get a subscriber by Foreign Key.
*
* Note the difference with subscriberFindByEmail which only returns the SubscriberID
* Both API calls return the subscriber
*
* @param string $foreignKey Foreign Key to search
*
* @return subscriber object if found false if not found
*/
public function subscriberGetByForeignkey($foreignKey)
{
$post_params = array(
'foreignkey' => $foreignKey,
);
$result = $this->callApi('subscriberGetByForeignkey', $post_params);
if (!empty($result->data->id)) {
return $result->data;
} else {
return false;
}
}
/**
* Get the total number of subscribers.
*
* @param none
*
* @return int total number of subscribers in the system
*/
public function subscriberCount()
{
$post_params = array(
);
$result = $this->callApi('subscribersCount', $post_params);
return $result !== null ? $result->data->total : false;
}
/**
* Add a subscriber to an existing list.
*
* @param int $listId ID of the list
* @param int $subscriberId ID of the subscriber
*
* @return the lists this subscriber is member of
*/
public function listSubscriberAdd($listId, $subscriberId)
{
// Set list and subscriber vars
$post_params = array(
'list_id' => $listId,
'subscriber_id' => $subscriberId,
);
$result = $this->callApi('listSubscriberAdd', $post_params);
return $result !== null ? $result->data : false;
}
/**
* Add a subscriber
*
* @param int $listId ID of the list
* @param int $subscriberId ID of the subscriber
*
* @return the lists this subscriber is member of
*/
/**
* Add a subscriber
*
* @param $email
* @param $confirmed
* @param $password
* @return mixed
*/
public function subscriberAdd($email, $confirmed, $password)
{
// Set subscriber vars
$post_params = array(
'email' => $email,
'confirmed' => $confirmed ? 1 : 0,
'password' => $password,
'disabled' => 0,
'htmlemail' => 1,
'subscribepage' => 0,
'foreignkey' => '',
);
if (null !== $result = $this->callApi('subscriberAdd', $post_params)) {
return $result->data;
}
return false;
}
/**
* Get the lists a subscriber is member of.
*
* @param int $subscriberId ID of the subscriber
*
* @return the lists this subcriber is member of
*/
public function listsSubscriber($subscriberId)
{
$post_params = array(
'subscriber_id' => $subscriberId,
);
$result = $this->callApi('listsSubscriber', $post_params);
return $result !== null ? $result->data : false;
}
/**
* Get subscribers to a given list
*
* @param int $listId the list id
* @return a lust of subscribers
*/
public function listSubscribers($listId)
{
$post_params = array(
'list_id' => $listId,
);
$result = $this->callApi('listSubscribers', $post_params);
return $result !== null ? $result->data : false;
}
/**
* Remove a Subscriber from a list.
*
* @param int $listId ID of the list to remove
* @param int $subscriberId ID of the subscriber
*
* @return the lists this subcriber is member of
*/
public function listSubscriberDelete($listId, $subscriberId)
{
// Set list and subscriber vars
$post_params = array(
'list_id' => $listId,
'subscriber_id' => $subscriberId,
);
$result = $this->callApi('listSubscriberDelete', $post_params);
return $result !== null ? $result->data : false;
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 21/07/2016 09:14
*/
namespace PhpList\Command;
use PhpList\PhpList;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Thelia\Command\ContainerAwareCommand;
class Sync extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName("phplist:sync")
->setDescription("Synchronize local newsletter subscribers with phpList subscribers")
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->writeln("<info>Synchronizing...</info>");
$this->getDispatcher()->dispatch(PhpList::RESYNC_EVENT);
$output->writeln("<info>Synchronization done...</info>");
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<config xmlns="http://thelia.net/schema/dic/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/config http://thelia.net/schema/dic/config/thelia-1.0.xsd">
<commands>
<command class="PhpList\Command\Sync"/>
</commands>
<forms>
<form name="phplist.configuration.form" class="PhpList\Form\ConfigurationForm" />
</forms>
<services>
<service id="phplist.event_listener" class="PhpList\EventListeners\EventManager">
<tag name="kernel.event_subscriber" />
</service>
</services>
<hooks>
<hook id="phplist.product_edit" class="PhpList\Hook\HookManager" scope="request">
<tag name="hook.event_listener" event="module.configuration" type="back" method="onModuleConfigure" />
</hook>
</hooks>
</config>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="http://thelia.net/schema/dic/module"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://thelia.net/schema/dic/module http://thelia.net/schema/dic/module/module-2_2.xsd">
<fullnamespace>PhpList\PhpList</fullnamespace>
<descriptive locale="en_US">
<title>PhpList interface module</title>
</descriptive>
<descriptive locale="fr_FR">
<title>Module d'interface avec PhpList</title>
</descriptive>
<languages>
<language>en_US</language>
<language>fr_FR</language>
</languages>
<version>1.0.0</version>
<authors>
<author>
<name>Franck Allimant</name>
<company>CQFDev</company>
<email>thelia@cqfdev.fr</email>
<website>www.cqfdev.fr</website>
</author>
</authors>
<type>classic</type>
<thelia>2.3.0</thelia>
<stability>other</stability>
</module>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd">
<route id="phplist.configure" path="/admin/module/phplist/configure" methods="post">
<default key="_controller">PhpList\Controller\ConfigurationController::configure</default>
</route>
<route id="phplist.sync" path="/admin/module/phplist/sync">
<default key="_controller">PhpList\Controller\ConfigurationController::sync</default>
<default key="not-logged">1</default>
</route>
</routes>

View File

@@ -0,0 +1,110 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 20/07/2016 15:18
*/
namespace PhpList\Controller;
use PhpList\PhpList;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Thelia\Controller\Admin\BaseAdminController;
use Thelia\Core\Security\AccessManager;
use Thelia\Core\Security\Resource\AdminResources;
use Thelia\Form\Exception\FormValidationException;
use Thelia\Log\Tlog;
use Thelia\Tools\URL;
class ConfigurationController extends BaseAdminController
{
public function configure()
{
if (null !== $response = $this->checkAuth(AdminResources::MODULE, 'phpList', AccessManager::UPDATE)) {
return $response;
}
// Create the Form from the request
$configurationForm = $this->getTheliaFormFactory()->createForm('phplist.configuration.form');
try {
// Check the form against constraints violations
$form = $this->validateForm($configurationForm, "POST");
// Get the form field values
$data = $form->getData();
foreach ($data as $name => $value) {
if (is_array($value)) {
$value = implode(';', $value);
}
PhpList::setConfigValue($name, $value);
}
// Log configuration modification
$this->adminLogAppend(
"phplist.configuration.message",
AccessManager::UPDATE,
sprintf("PhpList configuration updated")
);
// Redirect to the success URL,
if ($this->getRequest()->get('save_mode') == 'stay') {
// If we have to stay on the same page, redisplay the configuration page/
$route = '/admin/module/PhpList';
} else {
// If we have to close the page, go back to the module back-office page.
$route = '/admin/modules';
}
return new RedirectResponse(URL::getInstance()->absoluteUrl($route));
} catch (FormValidationException $ex) {
// Form cannot be validated. Create the error message using
// the BaseAdminController helper method.
$error_msg = $this->createStandardFormValidationErrorMessage($ex);
Tlog::getInstance()->error($ex->getTraceAsString());
}
catch (\Exception $ex) {
// Any other error
$error_msg = $ex->getMessage();
Tlog::getInstance()->error($ex->getTraceAsString());
}
// At this point, the form has errors
$this->setupFormErrorContext(
$this->getTranslator()->trans("PhpList configuration", [], PhpList::DOMAIN_NAME),
$error_msg,
$configurationForm,
$ex
);
return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/PhpList'));
}
public function sync()
{
$this->getDispatcher()->dispatch(PhpList::RESYNC_EVENT);
return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/PhpList'));
}
public function bulkAdd()
{
$this->getDispatcher()->dispatch(PhpList::BULK_ADD);
return new RedirectResponse(URL::getInstance()->absoluteUrl('/admin/module/PhpList'));
}
}

View File

@@ -0,0 +1,239 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 18/07/2016 20:02
*/
namespace PhpList\EventListeners;
use PhpList\Api\PhpListRESTApiClient;
use PhpList\PhpList;
use Propel\Runtime\ActiveQuery\Criteria;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Thelia\Core\Event\Newsletter\NewsletterEvent;
use Thelia\Core\Event\TheliaEvents;
use Thelia\Core\Translation\Translator;
use Thelia\Exception\TheliaProcessException;
use Thelia\Log\Tlog;
use Thelia\Model\Lang;
use Thelia\Model\Newsletter;
use Thelia\Model\NewsletterQuery;
class EventManager implements EventSubscriberInterface
{
public function subscribe(NewsletterEvent $event)
{
$this->doSubscribe($event->getEmail(), PhpList::getConfigValue(PhpList::LIST_NAME));
}
public function unsubscribe(NewsletterEvent $event)
{
$this->doUnsubscribe($event->getEmail(), PhpList::getConfigValue(PhpList::LIST_NAME));
}
public function bulkAdd()
{
$theliaSubscribers = NewsletterQuery::create()->select('email')->find()->toArray();
foreach ($theliaSubscribers as $subscriber) {
$this->doSubscribe($subscriber, PhpList::getConfigValue(PhpList::LIST_NAME));
}
}
protected function doSubscribe($email, $list)
{
$api = $this->createApiClient();
try {
$subscriberId = $this->getSubscriberId($api, $email, true);
if ($api->listSubscriberAdd($list, $subscriberId)) {
Tlog::getInstance()->info(
sprintf(
"Email address %s successfully added to phpList ID %s.",
$email,
$list
)
);
} else {
throw new \Exception("Unknown error");
}
} catch (\Exception $ex) {
Tlog::getInstance()->error(
sprintf(
"Failed to add email address %s to phpList ID %s. Error is %s",
$email,
$list,
$ex->getMessage()
)
);
}
}
protected function doUnsubscribe($email, $list)
{
$api = $this->createApiClient();
try {
$subscriberId = $this->getSubscriberId($api, $email, true);
if ($api->listSubscriberDelete($list, $subscriberId)) {
Tlog::getInstance()->info(
sprintf(
"Email address %s successfully removed from phpList ID %s.",
$email,
$list
)
);
}
} catch (\Exception $ex) {
Tlog::getInstance()->error(
sprintf(
"Failed to remove email address %s from phpList ID %s. Error is %s",
$email,
$list,
$ex->getMessage()
)
);
}
}
/**
* @param PhpListRESTApiClient $api
* @param string $email
* @throws \Exception
*/
protected function getSubscriberId($api, $email, $createIfNotExists = false)
{
if (false !== $subscriberId = $api->subscriberFindByEmail($email)) {
return $subscriberId;
} elseif ($createIfNotExists) {
if (false !== $subscriberId = $api->subscriberAdd($email, true, $email . time())) {
return $subscriberId;
} else {
throw new \Exception("Failed to create customer with email $email");
}
} else {
throw new \Exception("Subscriber was not found in phpList");
}
}
/**
* @return PhpListRESTApiClient
*/
protected function createApiClient()
{
if (null === $url = PhpList::getConfigValue(PhpList::LIST_NAME, null)) {
throw new TheliaProcessException(
Translator::getInstance()->trans(
"Cannot create Php List REST client. Module is not initialized.",
[],
PhpList::DOMAIN_NAME
)
);
}
$api = new PhpListRESTApiClient(
PhpList::getConfigValue(PhpList::REST_URL),
PhpList::getConfigValue(PhpList::API_LOGIN_NAME),
PhpList::getConfigValue(PhpList::API_PASSWORD),
PhpList::getConfigValue(PhpList::API_SECRET)
);
if (false === $api->login()) {
throw new TheliaProcessException(
Translator::getInstance()->trans(
"Failed to login to phpList, please check credentials.",
[],
PhpList::DOMAIN_NAME
)
);
}
return $api;
}
public function resync()
{
$list = PhpList::getConfigValue(PhpList::LIST_NAME);
$api = $this->createApiClient();
if (false !== $subscribers = $api->listSubscribers($list)) {
$theliaSubscribers = NewsletterQuery::create()->select('email')->find()->toArray();
$locale = Lang::getDefaultLanguage()->getLocale();
$phpListSubscribers = [];
// Add to Thelia the subscribers which are not in the Newsletter table
foreach ($subscribers as $subscriber) {
if ($subscriber->confirmed) {
$phpListSubscribers[] = $subscriber->email;
if (!in_array($subscriber->email, $theliaSubscribers)) {
$newsletter = new Newsletter();
$newsletter
->setEmail($subscriber->email)
->setLocale($locale)
->save();
}
}
}
// Remove from Thelia the subscribers which are not in phpList
foreach ($theliaSubscribers as $theliaSubscriber) {
if (!in_array($theliaSubscriber, $phpListSubscribers)) {
NewsletterQuery::create()->findOneByEmail($theliaSubscriber)->delete();
}
}
// Add to phpList the missing Thelia subscribers, ignoring unsubscribed emails
$theliaSubscribers = NewsletterQuery::create()
->filterByUnsubscribed(false)
->select('email')
->find()
->toArray();
foreach ($theliaSubscribers as $theliaSubscriber) {
if (!in_array($theliaSubscriber, $phpListSubscribers)) {
$this->doSubscribe($theliaSubscriber, $list);
}
}
// Remove from phpList unsubscribed Thelia emails
$theliaSubscribers = NewsletterQuery::create()
->filterByUnsubscribed(true)
->select('email')
->find()
->toArray();
foreach ($theliaSubscribers as $theliaSubscriber) {
if (in_array($theliaSubscriber, $phpListSubscribers)) {
$this->doUnsubscribe($theliaSubscriber, $list);
}
}
}
}
public static function getSubscribedEvents()
{
return array(
TheliaEvents::NEWSLETTER_SUBSCRIBE => ["subscribe", 130],
TheliaEvents::NEWSLETTER_UNSUBSCRIBE => ["unsubscribe", 130],
PhpList::RESYNC_EVENT => ['resync', 128],
PhpList::BULK_ADD => ['bulkAdd', 128]
);
}
}

View File

@@ -0,0 +1,151 @@
<?php
/*************************************************************************************/
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/* For the full copyright and license information, please view the LICENSE */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace PhpList\Form;
use PhpList\Api\PhpListRESTApiClient;
use PhpList\PhpList;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
use Thelia\Form\BaseForm;
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 18/07/2016 20:10
*/
class ConfigurationForm extends BaseForm
{
protected function buildForm()
{
$this->formBuilder
->add(PhpList::REST_URL, "text", array(
"label" => $this->translator->trans("Php List REST API URL", [], PhpList::DOMAIN_NAME),
"required" => true,
"constraints" => array(
new NotBlank(),
),
"label_attr" => [
'help' => $this->translator->trans("The URL to the REST API, sometehing like http://your.phplist.domain/lists/admin/?page=call&pi=restapi", [], PhpList::DOMAIN_NAME),
]
))
->add(PhpList::API_LOGIN_NAME, "text", array(
"label" => $this->translator->trans("Login name", [], PhpList::DOMAIN_NAME),
"required" => true,
"constraints" => array(
new NotBlank(),
),
"label_attr" => [
'help' => $this->translator->trans("The username of an account with administration rights", [], PhpList::DOMAIN_NAME),
]
))
->add(PhpList::API_PASSWORD, "text", array(
"label" => $this->translator->trans("Password", [], PhpList::DOMAIN_NAME),
"required" => true,
"constraints" => array(
new NotBlank(),
new Callback(array(
"methods" => array(
array($this, "checkApiLogin")
),
)),
),
"label_attr" => [
'help' => $this->translator->trans("The password of the admin user above", [], PhpList::DOMAIN_NAME),
]
))
->add(PhpList::API_SECRET, "text", array(
"label" => $this->translator->trans("API secret key", [], PhpList::DOMAIN_NAME),
"required" => true,
"label_attr" => [
'help' => $this->translator->trans("This is the secret code defined in the PhpList settings. Enter this code only if \"Require the secret code for Rest API calls\" is set to \"Yes\".", [], PhpList::DOMAIN_NAME),
]
))
;
if (null !== PhpList::getConfigValue(PhpList::REST_URL)) {
$this->formBuilder->add(
PhpList::LIST_NAME,
"choice",
array(
"label" => $this->translator->trans("User list name", [], PhpList::DOMAIN_NAME),
"required" => true,
"choices" => $this->getListNames(),
"label_attr" => [
'help' => $this->translator->trans("The name of the list the users are added or removed", [], PhpList::DOMAIN_NAME),
]
)
);
}
}
public function checkApiLogin($value, ExecutionContextInterface $context)
{
$data = $context->getRoot()->getData();
$message = false;
try {
$api = new PhpListRESTApiClient(
$data[PhpList::REST_URL],
$data[PhpList::API_LOGIN_NAME],
$data[PhpList::API_PASSWORD],
$data[PhpList::API_SECRET]
);
if (! $api->login()) {
$message = $this->translator->trans(
"Failed to login to the phpList REST API. Please check credentials.",
[],
PhpList::DOMAIN_NAME
);
}
} catch (\Error $ex) {
$message = $this->translator->trans(
"Failed to login to the phpList REST API. Unexpected error occured: %err",
[ '%err' => $ex->getMessage() ],
PhpList::DOMAIN_NAME
);
}
if ($message) {
$context->addViolation($message);
}
}
private function getListNames()
{
$api = new PhpListRESTApiClient(
PhpList::getConfigValue(PhpList::REST_URL),
PhpList::getConfigValue(PhpList::API_LOGIN_NAME),
PhpList::getConfigValue(PhpList::API_PASSWORD),
PhpList::getConfigValue(PhpList::API_SECRET)
);
$result = ['(none)' => $this->translator->trans("No list found !", [], PhpList::DOMAIN_NAME)];
if ($api->login()) {
if (false !== $listsData = $api->listsGet()) {
$result = [];
foreach ($listsData as $item) {
$result[$item->id] = $item->name;
}
}
} else {
throw new \Exception($this->translator->trans(
"Failed to login to the phpList REST API. Please check credentials",
[],
PhpList::DOMAIN_NAME
));
}
return $result;
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*************************************************************************************/
/* */
/* Copyright (c) Franck Allimant, CQFDev */
/* email : thelia@cqfdev.fr */
/* web : http://www.cqfdev.fr */
/* */
/*************************************************************************************/
/**
* Created by Franck Allimant, CQFDev <franck@cqfdev.fr>
* Date: 05/03/2016 18:11
*/
namespace PhpList\Hook;
use PhpList\PhpList;
use RupturesDeStock\Model\RupturesDeStockQuery;
use RupturesDeStock\RupturesDeStock;
use Thelia\Core\Event\Hook\HookRenderBlockEvent;
use Thelia\Core\Event\Hook\HookRenderEvent;
use Thelia\Core\Hook\BaseHook;
use Thelia\Tools\URL;
class HookManager extends BaseHook
{
public function onModuleConfigure(HookRenderEvent $event)
{
$vars = [
PhpList::REST_URL => PhpList::getConfigValue(PhpList::REST_URL, ''),
PhpList::API_LOGIN_NAME => PhpList::getConfigValue(PhpList::API_LOGIN_NAME, ''),
PhpList::API_PASSWORD => PhpList::getConfigValue(PhpList::API_PASSWORD, ''),
PhpList::API_SECRET => PhpList::getConfigValue(PhpList::API_SECRET, ''),
PhpList::LIST_NAME => PhpList::getConfigValue(PhpList::LIST_NAME, '')
];
$event->add(
$this->render('phplist/module-configuration.html', $vars)
);
}
}

View File

@@ -0,0 +1,4 @@
<?php
return array(
// 'an english string' => 'The displayed english string',
);

View File

@@ -0,0 +1,4 @@
<?php
return array(
// 'an english string' => 'La traduction française de la chaine',
);

View File

@@ -0,0 +1,30 @@
<?php
/*************************************************************************************/
/* This file is part of the Thelia package. */
/* */
/* Copyright (c) OpenStudio */
/* email : dev@thelia.net */
/* web : http://www.thelia.net */
/* */
/* For the full copyright and license information, please view the LICENSE.txt */
/* file that was distributed with this source code. */
/*************************************************************************************/
namespace PhpList;
use Thelia\Module\BaseModule;
class PhpList extends BaseModule
{
/** @var string */
const DOMAIN_NAME = 'phplist';
const REST_URL = 'rest_url';
const API_LOGIN_NAME = 'api_login_name';
const API_PASSWORD = 'api_password';
const API_SECRET = 'api_secret';
const LIST_NAME = 'list_name';
const RESYNC_EVENT = 'PhpList.resync';
const BULK_ADD = 'PhpList.bulk_add';
}

View File

@@ -0,0 +1,34 @@
# PhpList interface
This module synchronize a [phpList](https://www.phplist.org/) contact list of your choice whith the newsletter
subscriptions and unsubscriptions on your shop :
- When a user subscribe to your newsletter on your shop, it is automatically added to the phpList contact list.
- When a user unsubscribe from your list, it is also deleted from the phpList contact list.
Author: Franck Allimant, [CQFDev](https://www.cqfdev.fr) <franck@cqfdev.fr>
## Prerequistites
For this module to work, you need a working phpList instance,. The [RESTAPI plugin](https://resources.phplist.com/plugin/restapi)
shoud be installed and configured on this instance.
## Installation
Install the module as usual, activate it, and go to the module configuration to define configuration parameters
To configure this module, please enter the required information, and click the "Save" button.
Once the proper crendentials have been entered, you'll have to choose the list that will be updated when a customer
subscribe or unsubscribe to the newsletter.
## phpList / Thelia synchronization
To get instant synchronization between phpList and Thelia, be sure to use in the various phpList messages and templates:
- https://yourshop.tld/newsletter instead of `[SUBSCRIBEURL]`
- https://yourshop.tld/newsletter-unsubscribe instead of `[UNSUBSCRIBEURL]`
You can also configure an automatic synchronisation :
- in your cron by running the command `Thelia phplist:sync`
- in your webcron by invoking the following URL: https://yourshop.tld/admin/module/phplist/sync

View File

@@ -0,0 +1,26 @@
{
"name": "cqfdev/php-list-module",
"description": "A Thelia 2 module to synchronize a phpList contact list of your choice with the newsletter subscriptions and unsubscriptions on your Thelia shop",
"keywords": [
"thelia",
"thelia-module",
"phplist",
"email",
"newsletter"
],
"authors": [
{
"name": "Franck Allimant",
"email": "franck@cqfdev.fr",
"role": "Developer"
}
],
"license": "LGPL-3.0+",
"type": "thelia-module",
"require": {
"thelia/installer": "~1.1"
},
"extra": {
"installer-name": "PhpList"
}
}

View File

@@ -0,0 +1,77 @@
<div class="row">
<div class="col-md-12 general-block-decorator">
<div class="row">
<div class="col-md-12 title title-without-tabs">
{intl d='phplist.bo.default' l="PHP List interface Configuration"}
</div>
</div>
<div class="form-container">
<div class="row">
<div class="col-md-12">
{form name="phplist.configuration.form"}
<form action="{url path="/admin/module/phplist/configure"}" method="post">
{form_hidden_fields form=$form}
{include file = "includes/inner-form-toolbar.html"
hide_flags = true
page_url = "{url path='/admin/module/PhpList'}"
close_url = "{url path='/admin/modules'}"
hide_save_and_close_button = true
}
{if $form_error}
<div class="row">
<div class="col-md-12">
<div class="alert alert-danger">{$form_error_message}</div>
</div>
</div>
{/if}
<div class="row">
<div class="col-md-6">
{render_form_field form=$form field='rest_url' value=$rest_url}
{render_form_field form=$form field='api_login_name' value=$api_login_name}
{render_form_field form=$form field='api_password' value=$api_password}
{render_form_field form=$form field='api_secret' value=$api_secret}
{if $rest_url}
{render_form_field form=$form field='list_name' value=$list_name}
{/if}
</div>
<div class="col-md-6">
<p class="title title-without-tabs">
{intl d='phplist.bo.default' l="Prerequistites"}
</p>
{intl d='phplist.bo.default' l='<p>For this module to work, the <a href="https://github.com/phpList/phplist-plugin-restapi" target="_blank">RESTAPI plugin</a> shoud be installed and configured on your PHP List instance.</p>
<p>To configure this module, please enter the required information, and click the "Save" button.</p>
<p>Once the proper crendentials have been entered, you\'ll have to choose the list that will be updated when a customer subscribe or unsubscribe to the newsletter.</p>'}
<p>&nbsp;</p> {* please kill me *}
<p class="title title-without-tabs">
{intl d='phplist.bo.default' l="phpList / Thelia synchronization"}
</p>
{intl d='phplist.bo.default' l='To get instant synchronization between phpList and Thelia, be sure to use in the various phpList messages and templates:'}
<ul>
<li>{intl d='phplist.bo.default' l='<strong>%sub</strong> instead of [SUBSCRIBEURL]' sub={url path="/newsletter"}}</li>
<li>{intl d='phplist.bo.default' l='<strong>%unsub</strong> instead of [UNSUBSCRIBEURL]' unsub={url path="/newsletter-unsubscribe"}}</li>
</ul>
<p>{intl d='phplist.bo.default' l='You can also configure an automatic synchronisation in your cron or webcron by invoking the following URL: %sync.' sync={url path='/admin/module/phplist/sync'}}</p>
{if $rest_url}
<p><a href="{url path='/admin/module/phplist/sync'}" class="btn btn-primary">{intl d='phplist.bo.default' l="Synchronize now"}</a></p>
{/if}
</div>
</div>
</form>
{/form}
</div>
</div>
</div>
</div>
</div>