Merge 46deca697d into e172aa196e
This commit is contained in:
commit
d990c8075b
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Jaap Jansma <jaap.jansma@civicoop.org>
|
||||
* @license AGPL-3.0
|
||||
*/
|
||||
namespace Civi\CiviProxy;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
class CompilerPass implements CompilerPassInterface {
|
||||
|
||||
/**
|
||||
* You can modify the container here before it is dumped to PHP code.
|
||||
*/
|
||||
public function process(ContainerBuilder $container) {
|
||||
if (!$container->hasDefinition('data_processor_factory')) {
|
||||
return;
|
||||
}
|
||||
$factoryDefinition = $container->getDefinition('data_processor_factory');
|
||||
$factoryDefinition->addMethodCall('addOutputHandler', array('civiproxy_file_field', 'Civi\CiviProxy\DataProcessor\FileFieldOutputHandler', ts('CiviProxy File download link')));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
<?php
|
||||
/**
|
||||
* @author Jaap Jansma <jaap.jansma@civicoop.org>
|
||||
* @license AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Civi\CiviProxy\DataProcessor;
|
||||
|
||||
use Civi\DataProcessor\FieldOutputHandler\AbstractFieldOutputHandler;
|
||||
use Civi\DataProcessor\Source\SourceInterface;
|
||||
use Civi\DataProcessor\DataSpecification\FieldSpecification;
|
||||
use Civi\DataProcessor\FieldOutputHandler\FieldOutput;
|
||||
use Civi\DataProcessor\Exception\DataSourceNotFoundException;
|
||||
use Civi\DataProcessor\Exception\FieldNotFoundException;
|
||||
|
||||
class FileFieldOutputHandler extends AbstractFieldOutputHandler {
|
||||
|
||||
/**
|
||||
* Returns the data type of this field
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
protected function getType() {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the formatted value
|
||||
*
|
||||
* @param $rawRecord
|
||||
* @param $formattedRecord
|
||||
*
|
||||
* @return \Civi\DataProcessor\FieldOutputHandler\FieldOutput
|
||||
*/
|
||||
public function formatField($rawRecord, $formattedRecord) {
|
||||
$rawValue = $rawRecord[$this->inputFieldSpec->alias];
|
||||
$output = new FieldOutput($rawValue);
|
||||
if ($rawValue) {
|
||||
$proxy_base = \CRM_Core_BAO_Setting::getItem('CiviProxy Settings', 'proxy_url');
|
||||
$attachment = civicrm_api3('Attachment', 'getsingle', array('id' => $rawValue));
|
||||
if (!isset($attachment['is_error']) || $attachment['is_error'] == '0') {
|
||||
$fcs = \CRM_Core_BAO_File::generateFileHash($attachment['entity_id'], $attachment['id']);
|
||||
$output->formattedValue = $proxy_base.'/file.php?id='.$attachment['id'].'&eid='.$attachment['entity_id'].'&fcs='.$fcs;
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for determining whether this field could be handled by this output handler.
|
||||
*
|
||||
* @param \Civi\DataProcessor\DataSpecification\FieldSpecification $field
|
||||
* @return bool
|
||||
*/
|
||||
public function isFieldValid(FieldSpecification $field) {
|
||||
if ($field->type == 'File') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @var \Civi\DataProcessor\DataSpecification\FieldSpecification
|
||||
*/
|
||||
protected $inputFieldSpec;
|
||||
|
||||
/**
|
||||
* @var \Civi\DataProcessor\DataSpecification\FieldSpecification
|
||||
*/
|
||||
protected $outputFieldSpec;
|
||||
|
||||
/**
|
||||
* @var SourceInterface
|
||||
*/
|
||||
protected $dataSource;
|
||||
|
||||
/**
|
||||
* @return \Civi\DataProcessor\DataSpecification\FieldSpecification
|
||||
*/
|
||||
public function getOutputFieldSpecification() {
|
||||
return $this->outputFieldSpec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the processor
|
||||
*
|
||||
* @param String $alias
|
||||
* @param String $title
|
||||
* @param array $configuration
|
||||
* @param \Civi\DataProcessor\ProcessorType\AbstractProcessorType $processorType
|
||||
*/
|
||||
public function initialize($alias, $title, $configuration) {
|
||||
$this->dataSource = $this->dataProcessor->getDataSourceByName($configuration['datasource']);
|
||||
if (!$this->dataSource) {
|
||||
throw new DataSourceNotFoundException(ts("Field %1 requires data source '%2' which could not be found. Did you rename or deleted the data source?", array(1=>$title, 2=>$configuration['datasource'])));
|
||||
}
|
||||
$this->inputFieldSpec = $this->dataSource->getAvailableFields()->getFieldSpecificationByName($configuration['field']);
|
||||
if (!$this->inputFieldSpec) {
|
||||
throw new FieldNotFoundException(ts("Field %1 requires a field with the name '%2' in the data source '%3'. Did you change the data source type?", array(
|
||||
1 => $title,
|
||||
2 => $configuration['field'],
|
||||
3 => $configuration['datasource']
|
||||
)));
|
||||
}
|
||||
$this->dataSource->ensureFieldInSource($this->inputFieldSpec);
|
||||
|
||||
$this->outputFieldSpec = clone $this->inputFieldSpec;
|
||||
$this->outputFieldSpec->alias = $alias;
|
||||
$this->outputFieldSpec->title = $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when this handler has additional configuration.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When this handler has additional configuration you can add
|
||||
* the fields on the form with this function.
|
||||
*
|
||||
* @param \CRM_Core_Form $form
|
||||
* @param array $field
|
||||
*/
|
||||
public function buildConfigurationForm(\CRM_Core_Form $form, $field=array()) {
|
||||
$fieldSelect = $this->getFieldOptions($field['data_processor_id']);
|
||||
|
||||
$form->add('select', 'field', ts('Field'), $fieldSelect, true, array(
|
||||
'style' => 'min-width:250px',
|
||||
'class' => 'crm-select2 huge data-processor-field-for-name',
|
||||
'placeholder' => ts('- select -'),
|
||||
));
|
||||
if (isset($field['configuration'])) {
|
||||
$configuration = $field['configuration'];
|
||||
$defaults = array();
|
||||
if (isset($configuration['field']) && isset($configuration['datasource'])) {
|
||||
$defaults['field'] = $configuration['datasource'] . '::' . $configuration['field'];
|
||||
}
|
||||
$form->setDefaults($defaults);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When this handler has configuration specify the template file name
|
||||
* for the configuration form.
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public function getConfigurationTemplateFileName() {
|
||||
return "CRM/Dataprocessor/Form/Field/Configuration/RawFieldOutputHandler.tpl";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the submitted values and create a configuration array
|
||||
*
|
||||
* @param $submittedValues
|
||||
* @return array
|
||||
*/
|
||||
public function processConfiguration($submittedValues) {
|
||||
list($datasource, $field) = explode('::', $submittedValues['field'], 2);
|
||||
$configuration['field'] = $field;
|
||||
$configuration['datasource'] = $datasource;
|
||||
return $configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all possible fields
|
||||
*
|
||||
* @param $data_processor_id
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getFieldOptions($data_processor_id) {
|
||||
$fieldSelect = \CRM_Dataprocessor_Utils_DataSourceFields::getAvailableFieldsInDataSources($data_processor_id, array($this, 'isFieldValid'));
|
||||
return $fieldSelect;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
require_once 'civiproxy.civix.php';
|
||||
|
||||
use \Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* We will provide our own Mailer (wrapping the original one).
|
||||
* so we can mend all the URLs in outgoing emails
|
||||
|
|
@ -18,6 +20,15 @@ function civiproxy_civicrm_alterMailer(&$mailer, $driver, $params) {
|
|||
$mailer = new CRM_Civiproxy_Mailer($mailer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_civicrm_container()
|
||||
*
|
||||
* @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_container/
|
||||
*/
|
||||
function civiproxy_civicrm_container(ContainerBuilder $container) {
|
||||
$container->addCompilerPass(new Civi\CiviProxy\CompilerPass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of hook_civicrm_config
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -24,4 +24,7 @@
|
|||
<civix>
|
||||
<namespace>CRM/Civiproxy</namespace>
|
||||
</civix>
|
||||
<classloader>
|
||||
<psr4 prefix="Civi\" path="Civi" />
|
||||
</classloader>
|
||||
</extension>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ First thing you need to configure is the base URL of your CiviProxy server using
|
|||
```
|
||||
|
||||
!!! note
|
||||
This guide assumes a Drupal7 target CiviCRM with clean URLs enabled. If this is not the case for you, you might have to adjust the URLs and/or encounter issues. If so, please report on GitHub!
|
||||
This guide assumes a Drupal7 target CiviCRM with clean URLs enabled. If this is not the case for you, you might have to adjust the URLs and/or encounter issues. If so, please report on GitHub!
|
||||
|
||||
### Configuring the link to the secure target CiviCRM
|
||||
|
||||
|
|
@ -75,12 +75,16 @@ $target_open = $target_civicrm . '/civicrm/mailing/url/open.php';
|
|||
```
|
||||
If you set it to the value NULL this functionality will not be available on your CiviProxy server.
|
||||
### Setting for the location of images and included files in your mail(ing)
|
||||
CiviCRM stores images and attachments you include in your (bulk) mail in a specific folder. In CiviProxy the name of this folder is stored in variable `$target_file` in the `config.php` file:
|
||||
CiviCRM stores images and attachments you include in your (bulk) mail in a specific folder. In CiviProxy the name of this folder is stored in variable `$target_static_file` in the `config.php` file:
|
||||
```php
|
||||
$target_file = $target_civicrm . '/sites/default/files/civicrm/persist/';
|
||||
$target_download_file = $target_civicrm . '/civicrm/file';
|
||||
$target_static_file = $target_civicrm . '/sites/default/files/civicrm/persist/';
|
||||
```
|
||||
If you set it to the value NULL this functionality will not be available on your CiviProxy server.
|
||||
|
||||
The `$target_download_file` is used for downloading files from custom file fields (or the contact image).
|
||||
The `$target_static_file` is used for downloading images in mailings.
|
||||
|
||||
!!! note
|
||||
By default CiviProxy will cache the files so it does not have to file from CiviCRM for each individual mail that is part of a bulk mailing. The default settings can be found in the `config.php` file:
|
||||
```php
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ $target_civicrm = 'https://your.civicrm.installation.org';
|
|||
|
||||
// default paths, override if you want. Set to NULL to disable
|
||||
$target_rest = $target_civicrm . '/sites/all/modules/civicrm/extern/rest.php';
|
||||
$target_file = $target_civicrm . '/sites/default/files/civicrm/persist/';
|
||||
$target_download_file = $target_civicrm . '/civicrm/file';
|
||||
$target_static_file = $target_civicrm . '/sites/default/files/civicrm/persist/';
|
||||
$target_mosaico = NULL; // (disabled by default): $target_civicrm . '/civicrm/mosaico/img?src=';
|
||||
$target_mosaico_template_url = NULL; // (disabled by default): $target_civicrm . '/wp-content/uploads/civicrm/ext/uk.co.vedaconsulting.mosaico/packages/mosaico/templates/';
|
||||
$target_mail_view = $target_civicrm . '/civicrm/mailing/view';
|
||||
|
|
|
|||
|
|
@ -10,38 +10,51 @@
|
|||
require_once "config.php";
|
||||
require_once "proxy.php";
|
||||
|
||||
// see if file caching is enabled
|
||||
if (!$target_file) civiproxy_http_error("Feature disabled", 405);
|
||||
|
||||
// basic check
|
||||
civiproxy_security_check('file');
|
||||
|
||||
// basic restraints
|
||||
$valid_parameters = array( 'id' => 'string' );
|
||||
$valid_parameters = array(
|
||||
'id' => 'string',
|
||||
'eid' => 'int',
|
||||
'fcs' => 'string'
|
||||
);
|
||||
$parameters = civiproxy_get_parameters($valid_parameters);
|
||||
|
||||
// check if id specified
|
||||
if (empty($parameters['id'])) civiproxy_http_error("Resource not found");
|
||||
|
||||
// check restrictions
|
||||
if (!empty($file_cache_exclude)) {
|
||||
foreach ($file_cache_exclude as $pattern) {
|
||||
if (preg_match($pattern, $parameters['id'])) {
|
||||
$static_file = true;
|
||||
if (isset($parameters['eid']) && isset($parameters['fcs'])) {
|
||||
$static_file = false;
|
||||
// see if file caching is enabled
|
||||
if (!$target_download_file) civiproxy_http_error("Feature disabled", 405);
|
||||
} else {
|
||||
// see if file caching is enabled
|
||||
if (!$target_static_file && isset($target_file)) {
|
||||
$target_static_file = $target_file; // Backwards compatibility.
|
||||
}
|
||||
if (!$target_static_file) civiproxy_http_error("Feature disabled", 405);
|
||||
// check restrictions
|
||||
if (!empty($file_cache_exclude)) {
|
||||
foreach ($file_cache_exclude as $pattern) {
|
||||
if (preg_match($pattern, $parameters['id'])) {
|
||||
civiproxy_http_error("Invalid Resource", 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($file_cache_include)) {
|
||||
$accept_id = FALSE;
|
||||
foreach ($file_cache_include as $pattern) {
|
||||
if (preg_match($pattern, $parameters['id'])) {
|
||||
$accept_id = TRUE;
|
||||
}
|
||||
}
|
||||
if (!$accept_id) {
|
||||
civiproxy_http_error("Invalid Resource", 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($file_cache_include)) {
|
||||
$accept_id = FALSE;
|
||||
foreach ($file_cache_include as $pattern) {
|
||||
if (preg_match($pattern, $parameters['id'])) {
|
||||
$accept_id = TRUE;
|
||||
}
|
||||
}
|
||||
if (!$accept_id) {
|
||||
civiproxy_http_error("Invalid Resource", 403);
|
||||
}
|
||||
}
|
||||
|
||||
// load PEAR file cache
|
||||
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . 'libs');
|
||||
|
|
@ -52,6 +65,10 @@ $file_cache = new Cache_Lite($file_cache_options);
|
|||
// look up the required resource
|
||||
$header_key = 'header&' . $parameters['id'];
|
||||
$data_key = 'data&' . $parameters['id'];
|
||||
if (!$static_file) {
|
||||
$header_key .= '&eid='.$parameters['eid'];
|
||||
$data_key .= '&eid='.$parameters['eid'];
|
||||
}
|
||||
|
||||
$header = $file_cache->get($header_key);
|
||||
$data = $file_cache->get($data_key);
|
||||
|
|
@ -68,7 +85,10 @@ if ($header && $data) {
|
|||
}
|
||||
|
||||
// if we get here, we have a cache miss => load
|
||||
$url = $target_file . $parameters['id'];
|
||||
$url = $target_static_file . $parameters['id'];
|
||||
if (!$static_file) {
|
||||
$url = $target_download_file .'?reset=1&id='.$parameters['id'].'&eid='.$parameters['eid'].'&fcs='.$parameters['fcs'];
|
||||
}
|
||||
// error_log("CACHE MISS. LOADING $url");
|
||||
|
||||
$curlSession = curl_init();
|
||||
|
|
@ -100,12 +120,28 @@ $body = $content[1];
|
|||
|
||||
// extract headers
|
||||
$header_lines = explode(chr(10), $header);
|
||||
// Check whether the Content-Disposition header is available but only when it is
|
||||
// a dynamic file.
|
||||
$content_disposition_header_present = FALSE;
|
||||
foreach ($header_lines as $header_line) {
|
||||
if (stripos($header_line, 'Content-Disposition')===0) {
|
||||
$content_disposition_header_present = TRUE;
|
||||
}
|
||||
}
|
||||
if (!$static_file && !$content_disposition_header_present) {
|
||||
// check whether the content disposition header is available.
|
||||
// If not we are dealing with an invalid file.
|
||||
// And CiviCRM does a redirect to the login page however we
|
||||
// dont want to expose that through CiviProxy so we will return an error message instead.
|
||||
civiproxy_http_error("Invalid Resource", 403);
|
||||
}
|
||||
|
||||
// store the information in the cache
|
||||
$file_cache->save(json_encode($header_lines), $header_key);
|
||||
$file_cache->save($body, $data_key);
|
||||
|
||||
// and reply
|
||||
$content_disposition_header_present = FALSE;
|
||||
foreach ($header_lines as $header_line) {
|
||||
header($header_line);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ function civiproxy_redirect($url_requested, $parameters) {
|
|||
* so they will point to this proxy instead
|
||||
*/
|
||||
function civiproxy_mend_URLs(&$string) {
|
||||
global $target_rest, $target_url, $target_open, $target_file, $target_mail, $proxy_base, $target_mosaico, $target_civicrm;
|
||||
global $target_rest, $target_url, $target_open, $target_static_file, $target_mail, $proxy_base, $target_mosaico, $target_civicrm;
|
||||
|
||||
if ($target_rest) {
|
||||
$string = preg_replace("#{$target_rest}#", $proxy_base . '/rest.php', $string);
|
||||
|
|
@ -110,8 +110,8 @@ function civiproxy_mend_URLs(&$string) {
|
|||
if ($target_mail) {
|
||||
$string = preg_replace("#{$target_mail}#", $proxy_base . '/mail.php', $string);
|
||||
}
|
||||
if ($target_file) {
|
||||
$string = preg_replace("#{$target_file}#", $proxy_base . '/file.php?id=', $string);
|
||||
if ($target_static_file) {
|
||||
$string = preg_replace("#{$target_static_file}#", $proxy_base . '/file.php?id=', $string);
|
||||
// https://github.com/systopia/CiviProxy/issues/38
|
||||
// fix for relative
|
||||
if ($target_mosaico) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue