cforge-2.0.x-dev/modules/cforge_broadcast/cforge_broadcast.inc
modules/cforge_broadcast/cforge_broadcast.inc
<?php
/**
* @file
* Helper functions.
*/
use Drupal\user\Entity\User;
use Drupal\Core\Url;
use Drupal\Core\Link;
use Drupal\Core\Entity\ContentEntityInterface;
/**
* Compose the broadcast mail.
*/
function _cforge_broadcast_mail_broadcast(&$message, $params) {
$entity = $params['entity'];
$params[$entity->getEntityTypeId()] = $entity;
unset($params['entity']);
if (!isset($params['user'])) {
\Drupal::service('logger.channel.cforge')->error('No user parameter in broadcast mail');
}
$sender = $entity->getOwner();
$message['subject'] = t(
'%site_name: %entity_label',
[
'%site_name' => \Drupal::Config('system.site')->get('name'),
'%entity_label' => $entity->label(),
]
);
$bundleFieldName = $entity->getEntityType()->getKey('bundle');
$message['body'][] = t(
'@name [<a href=":contact-url">contact</a>] posted a new @type.',
[
'@name' => $sender->getDisplayName(),
':contact-url' => Url::fromRoute(
'entity.user.contact_form',
['user' => $sender->id()]
)->toString(),
'@type' => $entity->{$bundleFieldName}->entity->label(),
]
);
$renderable = \Drupal::entityTypeManager()
->getViewBuilder($entity->getEntityTypeId())
->view($entity, 'default');
$message['body'][] = render($renderable);
unset($mailing);
// Add a paragraph about opting out if settings allow.
if (\Drupal::config('cforge_broadcast.settings')->get('optout')) {
$message['body'][] = Link::fromTextAndUrl(
t("Opt-out of 'broadcast' messages"),
Url::fromRoute(
'entity.user.edit_form',
['user' => $params['user']->id()],
['absolute' => TRUE]
)
)->toString();
}
$message['headers']['From'] = $sender->getEmail();
if ($entity->getEntityTypeId() == 'smallad' and property_exists($entity, 'image')) {
mail('matslats@fastmail.com', 'broadcast attachments', 'somebody tried to email an image attachment');
}
// @todo handle file attachments?
/* this code from d7
if (isset($node->upload) && is_array($node->upload)) {
$items = (array)reset($node->upload);
foreach($items as $att) {
if (!$att['fid']) continue;
$file = file_load($att['fid']);
$message['params']['attachments'][] = array(
'uri' => $file->uri,
'filecontent' => file_get_contents($file->uri),
'filename' => $file->filename,
'filemime' => file_get_mimetype($file->uri)
);
}
}
*/
}
/**
* Helper function.
*
* @see cforge_broadcast_form_cforge_settings_form_alter()
*/
function _cforge_broadcast_form_cforge_settings_form_alter(&$form, &$form_state) {
$config = \Drupal::config('cforge_broadcast.settings');
$form['mail']['scope'] = [
'#title' => t('Broadcast scope'),
'#description' => t('How far can a normal trader broadcast?'),
'#type' => 'radios',
'#options' => array(
CFORGE_BROADCAST_ME => t('Traders cannot broadcast'),
CFORGE_BROADCAST_NEIGHBOURHOOD => t('Only to people in the same neighbourhood'),
CFORGE_BROADCAST_SITE => t('To all online users'),
),
'#default_value' => $config->get('scope'),
'#weight' => 1
];
$form['mail']['optout'] = [
'#title' => t('Broadcast opt-out'),
'#description' => t('Give each user a setting to opt-out of broadcasts'),
'#type' => 'checkbox',
'#default_value' => $config->get('optout'),
'#weight' => 2
];
$form['#submit'][] = 'broadcast_settings_submit';
}
/**
* Form submit callback.
*
* Save the broadcast settings.
*/
function broadcast_settings_submit($form, $form_state) {
$config = \Drupal::configFactory()->getEditable('cforge_broadcast.settings');
$config
->set('optout', $form_state->getValue('optout'))
->set('scope', $form_state->getValue('scope'))
->save();
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add broadcasting buttons to the node/smallad form.
*/
function _cforge_broadcast_entity_form_alter(&$form, &$form_state) {
$entity = $form_state->getFormObject()->getEntity();
$entityTypeId = $entity->getEntityTypeId();
$nodetypes = ['story', 'document', 'event'];
if ($entityTypeId == 'smallad' or in_array($entity->bundle(), $nodetypes)) {
if ($scopes = cforge_broadcast_options($entity)) {
$form['actions']['submit']['#dropbutton'] = 'save';
$sure_message = (string) t('Are you sure you want to email this?');
foreach ($scopes as $scope_id => $scope_name) {
$form['actions']["broadcast_$scope_id"] = [
'#type' => 'submit',
'#value' => t('Save and broadcast to @scope', ['@scope' => $scope_name]),
'#submit' => $form['actions']['submit']['#submit'] + ['broadcast' => 'entity_broadcast_submit'],
'#weight' => 100 + $scope_id,
'#dropbutton' => 'save',
'#attributes' => [
'onclick' => 'if(!confirm("' . $sure_message . '")){return false;}',
],
'#scope' => $scope_id,
];
if (isset($form['image'])) {
$form['image']['widget']['#description'] = t('Images cannot be included in broadcast mails');
}
}
}
else {
$form['actions'][] = [
'#markup' => '('.t('Already broadcast') .')',
'#weight' => 100
];
}
}
}
/**
* Utility to check to what scope the node can be broadcast.
*
* That means:
* - the user has permission to broadcast
* - the entity is of a broadcastable type
* - the entity has not been broadcast before.
*
* @param ContentEntityInterface $entity
* The broadcastable entity.
*
* @return array
* The #options for the broadcast scope.
*/
function cforge_broadcast_options(ContentEntityInterface $entity) : array {
$options = [];
$pairs = \Drupal::keyValue('cforge_broadcast');
$already = $pairs->get($entity->getEntityTypeId(), []);
if ($entity->isNew() or !in_array($entity->id(), $already)) {
$i = 0;
$trader_scope = \Drupal::currentUser()->hasPermission('administer nodes') ?
CFORGE_BROADCAST_SITE :
\Drupal::config('cforge_broadcast.settings')->get('scope');
// Increase options until it is as wide as the user allows.
while ($i <= $trader_scope) {
if ($name = cforge_broadcast_scope_name($i)) {
$options[$i] = $name;
}
$i++;
}
}
return $options;
}
/**
* Submit handler for node form.
*
* Check the scope, find the emails and batch send an email.
*/
function entity_broadcast_submit($form, $form_state) {
$entity = $form_state->getFormObject()->getEntity();
$submit_button = $form_state->getTriggeringElement();
switch ($submit_button['#scope']) {
case CFORGE_BROADCAST_ME:
$uids = [\Drupal::currentUser()->id()];
break;
case CFORGE_BROADCAST_NEIGHBOURHOOD:
$account = User::load(\Drupal::currentUser()->id());
$address = $account->address->getValue();
$uids = cforge_neighbour_uids($address[0]['dependent_locality']);
break;
// This can't happen.
case CFORGE_BROADCAST_OGS:
break;
case CFORGE_BROADCAST_SITE:
$uids = \Drupal::entityQuery('user')
->condition('status', 1)
->execute();
break;
default:
throw \Exception('Unknown broadcast audience');
}
if (\Drupal::config('cforge_broadcast.settings')->get('optout')) {
$opted_out = \Drupal::service('user.data')->get('cforge_broadcast', NULL, 'optout');
$uids = array_diff($uids, array_keys(array_filter($opted_out)));
}
cforge_batch_mail(
'cforge_broadcast',
'broadcast',
$uids,
['entity' => $entity]
);
// Prevent the entity from being broadcast again.
if (count($uids) > 1) {
cforge_broadcast_mark_entity($entity);
}
}
/**
* Add the broadcasted entity to the list of already broadcast entities.
*
* @param ContentEntityInterface $entity
* The entity which has been broadcast.
*/
function cforge_broadcast_mark_entity(ContentEntityInterface $entity) {
$type = $entity->getEntityTypeId();
$pairs = \Drupal::keyValue('cforge_broadcast');
$ids = $pairs->get($type);
$ids[] = $entity->id();
$pairs->set($type, array_unique($ids));
}
/**
* Helper to determine if an entity has already been broadcast.
* @param type $entity
* @return bool
*/
function cforge_broadcast_already(\Drupal\Core\Entity\ContentEntityBase $entity) : bool {
if ($entity->isNew()) return FALSE;
$type = $entity->getEntityTypeId();
$pairs = \Drupal::keyValue('cforge_broadcast');
return in_array($entity->id(), $pairs->get($type, []));
}
/**
* Get the name or names of the broadcast scopes.
*
* @param int $scope
* The code of the scope.
*
* @return string[]
* The name of the scope, or an array of scope names, keyed by scope code
*/
function cforge_broadcast_scope_name($scope = NULL) {
$scopes = [
CFORGE_BROADCAST_ME => t('Myself'),
CFORGE_BROADCAST_NEIGHBOURHOOD => User::load(\Drupal::currentUser()->id())->address->dependent_locality,
CFORGE_BROADCAST_SITE => t('Everyone in @site', ['@site' => \Drupal::Config('system.site')->get('name')]),
];
if (is_null($scope)) {
return $scopes;
}
return @$scopes[$scope];
}
