first import

This commit is contained in:
Bachir Soussi Chiadmi
2015-04-08 11:40:19 +02:00
commit 1bc61b12ad
8435 changed files with 1582817 additions and 0 deletions

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,248 @@
DESCRIPTION
-----------
Simplenews publishes and sends newsletters to lists of subscribers. Both
anonymous and authenticated users can opt-in to different mailing lists.
HTML email can be sent by adding Mime mail module.
REQUIREMENTS
------------
* For large mailing lists, cron is required.
* HTML-format newsletters and/or newsletters with file attachments require the
mime mail or HMTL mail module.
* When sending newsletters on regular cron (cron.php), it is important that
the base url (settings.php, variable $base_url) is set correctly or links
inside the newsletter will not work. See the Tips (13.) below.
* Additionally when using Drush to start cron, it is important to use the
argument --uri=http://www.example.com
INSTALLATION
------------
1. CREATE DIRECTORY
Create a new directory "simplenews" in the sites/all/modules directory and
place the entire contents of this simplenews folder in it.
2. ENABLE THE MODULE
Enable the module on the Modules admin page.
3. ACCESS PERMISSION
Grant the access at the Access control page:
People > Permissions.
4. CONFIGURE SIMPLENEWS
Configure Simplenews on the Simplenews admin pages:
Configuration > Simplenews.
Enable new content types to use as newsletter:
Structure > edit content type > Publishing options
Add and configure newsletter categories:
Structure > Web Services > Newsletters > Add newsletter category
Structure > Web Services > Newsletters > edit newsletter category
5. ENABLE SIMPLENEWS BLOCK
With the Simplenews block users can subscribe to a newsletter.
Enable a Simplenews block per Newsletter category:
Structure > Newsletters > edit newsletter category
6. CONFIGURE SIMPLENEWS BLOCK
Configure the Simplenews block on the Block configuration page. You reach
this page from Block admin page (Structure > Blocks).
Click the 'Configure' link of the appropriate simplenews block.
Permission "subscribe to newsletters" is required to view the subscription
form in the simplenews block or to view the link to the subscription form.
7. SIMPLENEWS BLOCK THEMING
More control over the content of simplenews blocks can be achieved using
the block theming. Theme your simplenews block by copying
simplenews-block.tpl.php into your theme directory and edit the content.
The file is self documented listing all available variables.
The newsletter block can be themed generally and per newsletter:
simplenews-block.tpl.php (for all newsletters)
simplenews-block.tpl--[tid].php (for newsletter series tid)
8. MULTILINGUAL SUPPORT
Simplenews supports multilingual newsletters for node translation,
multilingual taxonomy and url path prefixes.
When translated newsletter issues are available subscribers receive the
newsletter in their preferred language (according to account setting).
Translation module is required for newsletter translation.
Multilingual taxonomy of 'Localized terms' and 'per language terms' is
supported. 'per language vocabulary' is not supported.
I18n-taxonomy module is required.
Use 'Localized terms' for a multilingual newsletter. Taxonomy terms are
translated and translated newsletters are each tagged with the same
(translated) term. Subscribers receive the newsletter in the preferred
language set in their account settings or in the site default language.
Use 'per language terms' for mailing lists each with a different language.
Newsletters of different language each have their own tag and own list of
subscribers.
Path prefixes are added to footer message according to the subscribers
preferred language.
The preferred language of anonymous users is set based on the interface
language of the page they visit for subscription. Anonymous users can NOT
change their preferred language. Users with an account on the site will be
subscribed with the preferred language as set in their account settings.
The confirmation mails can be translated by enableding the Simplenews
variables at:
Home > Administration > Configuration > Regional and language > Multilingual settings > Variables
Afterwards, the mail subject and body can be entered for every enabled
language.
9. NEWSLETTER THEMING
You can customize the theming of newsletters. Copy any of the *.tpl.php
files from the simplenews module directory to your theme directory. Both
general and by-newsletter theming can be performed.
Theme newsletter body:
simplenews-newsletter-body.tpl.php (for all newsletters)
simplenews-newsletter-body--[tid].tpl.php
simplenews-newsletter-body--[view mode].tpl.php
simplenews-newsletter-body--[tid]--[view mode].tpl.php
[tid]: Machine readable name of the newsletter category
[view mode]: 'email-plain', 'email-html', 'email-textalt'
Example:
simplenews-newsletter-body--1--email-plain.tpl.php
Theme newsletter footer:
simplenews-newsletter-footer.tpl.php (for all newsletters)
simplenews-newsletter-footer--[tid].tpl.php
simplenews-newsletter-footer--[view mode].tpl.php
simplenews-newsletter-footer--[tid]--[view mode].tpl.php
[tid]: Machine readable name of the newsletter category
[view mode]: 'email-plain', 'email-html', 'email-textalt'
Example:
simplenews-newsletter-footer--1--email-plain.tpl.php
The template files are self documented listing all available variables.
Depending on how the mails are sent (e.g. how cron is triggered), either the
default or the admin theme might be used, if one has been configured.
To prevent this, Simplenews supports the mail theme setting from the
mailsystem module (http://drupal.org/project/mailsystem). Install it, choose
the mail theme and the newsletter templates from that theme will be used no
matter which other themes are enabled.
Using the fields Display settings each field of a simplenews newsletter can
be displayed or hidden in 'plain text', 'HTML' and 'HTML text alternative'
format. You find these settings at:
Structure > Content types > Manage display
Enable the view modes you want to configure and configure their display.
10. SEND MAILING LISTS
Cron is required to send large mailing lists.
If you have a medium or large size mailing list (i.e. more than 500
subscribers) always use cron to send the newsletters.
To use cron:
* Check the 'Use cron to send newsletters' checkbox.
* Set the 'Cron throttle' to the number of newsletters send per cron run.
Too high values may lead to mail server overload or you may hit hosting
restrictions. Contact your host.
Don't use cron:
* Uncheck the 'Use cron to send newsletters' checkbox.
All newsletters will be sent immediately when saving the node. If not
all emails can be sent within the available php execution time, the
remainder will be sent by cron. Therefore ALWAYS enable cron.
These settings are found on the Newsletter Settings page under
'Send mail' options at:
Administer > Configuration > Web Services > Newsletters > Settings > Send mail.
11. (UN)SUBSCRIBE CONFIRMATION
By default the unsubscribe link will direct the user to a confirmation page.
Upon confirmation the user is directed to the home page, where a message
will be displayed. On the Simplenews subscription admin page you can
specify an alternative destination page.
Structure > Configuration > Web Services > Newsletters > edit newsletter category > Subscription settings
To skip the confirmation page you can add parameters to the subscription URL.
Example: [simplenews-subscribe-url]/ok
When an alternative destination page has been defined the extra parameters
will be added to the destination URL.
Example: [simplenews-subscriber:subscribe-url]/ok
Destination: node/123
Destination URL: node/123/ok
12. SINGLE OR DOUBLE OPT-IN AND OPT-OUT
Every newsletter can be set to be double opt-in/out (default), single
opt-in/out, or hidden.
Double: A confirmation email is sent to confirm the (un)subscribe action.
No confirmation is sent when a user is (un)subscribed by the
administrator or when the user subscribes when creating an account.
Single: No confirmation email is sent. (un)subscribe is immediately.
Hidden: The newsletter is not listed in newsletter lists. Use this for
mandatory newsletters. Only administrators or modules can add a user to this
mailing list.
Note that single opt-in/out or hidden (forced) subscription is in some
countries forbidden by law.
SECURITY NOTICE: a newsletter set to be single opt-in or opt-out is
vulnerable to Cross Site Request Forgeries. Email addresses may be
(un)subscribed without a notice. Do not use this setting in uncontrolled
environments (like the internet!).
13. TIPS
A subscription page is available at: /newsletter/subscriptions
The Elysia Cron module (http://drupal.org/project/elysia_cron) can be used
to start the simplenews cron hook more often than others, so that newsletter
are sent faster without decreasing site performance due to long-running cron
hooks.
If your unsubscribe URL looks like:
http://newsletter/confirm/remove/8acd182182615t632
instead of:
http://www.example.com/newsletter/confirm/remove/8acd182182615t632
You should change the base URL in the settings.php file from
# $base_url = 'http://www.example.com'; // NO trailing slash!
to
$base_url = 'http://www.example.com'; // NO trailing slash!
RELATED MODULES
------------
* Elysia Cron
Allows fine grained control over cron tasks.
http://http://drupal.org/project/elysia_cron
* Mailsystem
Extends drupal core mailystem wirh Administrative UI and Developers API.
http://drupal.org/project/mailsystem
* Maillog
Captures outgoing mails, helps users debugging simplenews.
http://drupal.org/project/maillog
DOCUMENTATION
-------------
More help can be found on the help pages: example.com/admin/help/simplenews
and in the drupal.org handbook: http://drupal.org/node/197057

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,95 @@
<?php
/**
* @file
* Hooks provided by the Simplenews module.
*/
/**
* @todo
*/
function hook_simplenews_issue_operations() {
}
/**
* @todo
*/
function hook_simplenews_subscription_operations() {
}
/**
* @todo
*/
function hook_simplenews_category_insert($category) {
}
/**
* @todo
*/
function hook_simplenews_category_update($category) {
}
/**
* @todo
*/
function hook_simplenews_category_delete($category) {
}
/**
* @todo
*/
function hook_simplenews_mailing_list_insert($list) {
}
/**
* @todo
*/
function hook_simplenews_subscriber_update($subscriber) {
}
/**
* @todo
*/
function hook_simplenews_subscriber_insert($subscriber) {
}
/**
* @todo
*/
function hook_simplenews_subscriber_delete($subscriber) {
}
/**
* Invoked if a user is subscribed to a newsletter.
*
* @param $subscriber
* The subscriber object including all subscriptions of this user.
*
* @param $subscription
* The subscription object for this specific subscribe action.
*/
function hook_simplenews_subscribe_user($subscriber, $subscription) {
}
/**
* Invoked if a user is unsubscribed from a newsletter.
*
* @param $subscriber
* The subscriber object including all subscriptions of this user.
*
* @param $subscription
* The subscription object for this specific unsubscribe action.
*/
function hook_simplenews_unsubscribe_user($subscriber, $subscription) {
}

View File

@@ -0,0 +1,879 @@
<?php
/**
* @file
* Simplenews email send and spool handling
*
* @ingroup mail
*/
/**
* Add the newsletter node to the mail spool.
*
* @param $node
* The newsletter node to be sent.
*
* @ingroup issue
*/
function simplenews_add_node_to_spool($node) {
// To send the newsletter, the node id and target email addresses
// are stored in the spool.
// Only subscribed recipients are stored in the spool (status = 1).
$select = db_select('simplenews_subscriber', 's');
$select->innerJoin('simplenews_subscription', 't', 's.snid = t.snid');
$select->addField('s', 'mail');
$select->addField('s', 'snid');
$select->addField('t', 'tid');
$select->addExpression($node->nid, 'nid');
$select->addExpression(SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED, 'status');
$select->addExpression(REQUEST_TIME, 'timestamp');
$select->condition('t.tid', $node->simplenews->tid);
$select->condition('t.status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED);
$select->condition('s.activated', SIMPLENEWS_SUBSCRIPTION_ACTIVE);
db_insert('simplenews_mail_spool')
->from($select)
->execute();
// Update simplenews newsletter status to send pending.
simplenews_newsletter_update_sent_status($node);
}
/**
* Send mail spool immediatly if cron should not be used.
*
* @param $conditions
* (Optional) Array of spool conditions which are applied to the query.
*/
function simplenews_mail_attempt_immediate_send(array $conditions = array(), $use_batch = TRUE) {
if (variable_get('simplenews_use_cron', TRUE)) {
return FALSE;
}
if ($use_batch) {
// Set up as many send operations as necessary to send all mails with the
// defined throttle amount.
$throttle = variable_get('simplenews_throttle', 20);
$spool_count = simplenews_count_spool($conditions);
$num_operations = ceil($spool_count / $throttle);
$operations = array();
for ($i = 0; $i < $num_operations; $i++) {
$operations[] = array('simplenews_mail_spool', array($throttle, $conditions));
}
// Add separate operations to clear the spool and updat the send status.
$operations[] = array('simplenews_clear_spool', array());
$operations[] = array('simplenews_send_status_update', array());
$batch = array(
'operations' => $operations,
'title' => t('Sending mails'),
'file' => drupal_get_path('module', 'simplenews') . '/includes/simplenews.mail.inc',
);
batch_set($batch);
}
else {
// Send everything that matches the conditions immediatly.
simplenews_mail_spool(SIMPLENEWS_UNLIMITED, $conditions);
simplenews_clear_spool();
simplenews_send_status_update();
}
return TRUE;
}
/**
* Send test version of newsletter.
*
* @param mixed $node
* The newsletter node to be sent.
*
* @ingroup issue
*/
function simplenews_send_test($node, $test_addresses) {
// Prevent session information from being saved while sending.
if ($original_session = drupal_save_session()) {
drupal_save_session(FALSE);
}
// Force the current user to anonymous to ensure consistent permissions.
$original_user = $GLOBALS['user'];
$GLOBALS['user'] = drupal_anonymous_user();
// Send the test newsletter to the test address(es) specified in the node.
// Build array of test email addresses
// Send newsletter to test addresses.
// Emails are send direct, not using the spool.
$recipients = array('anonymous' => array(), 'user' => array());
foreach ($test_addresses as $mail) {
$mail = trim($mail);
if (!empty($mail)) {
$subscriber = simplenews_subscriber_load_by_mail($mail);
if (!$subscriber) {
// The source expects a subscriber object with mail and language set.
// @todo: Find a cleaner way to do this.
$subscriber = new stdClass();
$subscriber->uid = 0;
$subscriber->mail = $mail;
$subscriber->language = $GLOBALS['language']->language;
}
if (!empty($account->uid)) {
$recipients['user'][] = $account->name . ' <' . $mail . '>';
}
else {
$recipients['anonymous'][] = $mail;
}
$source = new SimplenewsSourceNode($node, $subscriber);
$source->setKey('test');
$result = simplenews_send_source($source);
}
}
if (count($recipients['user'])) {
$recipients_txt = implode(', ', $recipients['user']);
drupal_set_message(t('Test newsletter sent to user %recipient.', array('%recipient' => $recipients_txt)));
}
if (count($recipients['anonymous'])) {
$recipients_txt = implode(', ', $recipients['anonymous']);
drupal_set_message(t('Test newsletter sent to anonymous %recipient.', array('%recipient' => $recipients_txt)));
}
$GLOBALS['user'] = $original_user;
if ($original_session) {
drupal_save_session(TRUE);
}
}
/**
* Send a node to an email address.
*
* @param $source
* The source object.s
*
* @return boolean
* TRUE if the email was successfully delivered; otherwise FALSE.
*
* @ingroup source
*/
function simplenews_send_source(SimplenewsSourceInterface $source) {
$params['simplenews_source'] = $source;
// Send mail.
$message = drupal_mail('simplenews', $source->getKey(), $source->getRecipient(), $source->getLanguage(), $params, $source->getFromFormatted());
// Log sent result in watchdog.
if (variable_get('simplenews_debug', FALSE)) {
if ($message['result']) {
watchdog('simplenews', 'Outgoing email. Message type: %type<br />Subject: %subject<br />Recipient: %to', array('%type' => $source->getKey(), '%to' => $message['to'], '%subject' => $message['subject']), WATCHDOG_DEBUG);
}
else {
watchdog('simplenews', 'Outgoing email failed. Message type: %type<br />Subject: %subject<br />Recipient: %to', array('%type' => $source->getKey(), '%to' => $message['to'], '%subject' => $message['subject']), WATCHDOG_ERROR);
}
}
// Build array of sent results for spool table and reporting.
if ($message['result']) {
$result = array(
'status' => SIMPLENEWS_SPOOL_DONE,
'error' => FALSE,
);
}
else {
// This error may be caused by faulty mailserver configuration or overload.
// Mark "pending" to keep trying.
$result = array(
'status' => SIMPLENEWS_SPOOL_PENDING,
'error' => TRUE,
);
}
return $result;
}
/**
* Send simplenews newsletters from the spool.
*
* Individual newsletter emails are stored in database spool.
* Sending is triggered by cron or immediately when the node is saved.
* Mail data is retrieved from the spool, rendered and send one by one
* If sending is successful the message is marked as send in the spool.
*
* @todo: Redesign API to allow language counter in multilingual sends.
*
* @param $limit
* (Optional) The maximum number of mails to send. Defaults to
* unlimited.
* @param $conditions
* (Optional) Array of spool conditions which are applied to the query.
*
* @return
* Returns the amount of sent mails.
*
* @ingroup spool
*/
function simplenews_mail_spool($limit = SIMPLENEWS_UNLIMITED, array $conditions = array()) {
$check_counter = 0;
// Send pending messages from database cache.
$spool_list = simplenews_get_spool($limit, $conditions);
if ($spool_list) {
// Switch to the anonymous user.
simplenews_impersonate_user(drupal_anonymous_user());
$count_fail = $count_success = 0;
_simplenews_measure_usec(TRUE);
$spool = new SimplenewsSpool($spool_list);
while ($source = $spool->nextSource()) {
$source->setKey('node');
$result = simplenews_send_source($source);
// Update spool status.
// This is not optimal for performance but prevents duplicate emails
// in case of PHP execution time overrun.
foreach ($spool->getProcessed() as $msid => $row) {
$row_result = isset($row->result) ? $row->result : $result;
simplenews_update_spool(array($msid), $row_result);
if ($row_result['status'] == SIMPLENEWS_SPOOL_DONE) {
$count_success++;
}
if ($row_result['error']) {
$count_fail++;
}
}
// Check every n emails if we exceed the limit.
// When PHP maximum execution time is almost elapsed we interrupt
// sending. The remainder will be sent during the next cron run.
if (++$check_counter >= SIMPLENEWS_SEND_CHECK_INTERVAL && ini_get('max_execution_time') > 0) {
$check_counter = 0;
// Break the sending if a percentage of max execution time was exceeded.
$elapsed = _simplenews_measure_usec();
if ($elapsed > SIMPLENEWS_SEND_TIME_LIMIT * ini_get('max_execution_time')) {
watchdog('simplenews', 'Sending interrupted: PHP maximum execution time almost exceeded. Remaining newsletters will be sent during the next cron run. If this warning occurs regularly you should reduce the !cron_throttle_setting.', array('!cron_throttle_setting' => l(t('Cron throttle setting'), 'admin/config/simplenews/mail')), WATCHDOG_WARNING);
break;
}
}
// It is possible that all or at the end some results failed to get
// prepared, report them separately.
foreach ($spool->getProcessed() as $msid => $row) {
$row_result = isset($row->result) ? $row->result : $result;
simplenews_update_spool(array($msid), $row_result);
if ($row_result['status'] == SIMPLENEWS_SPOOL_DONE) {
$count_success++;
}
if ($row_result['error']) {
$count_fail++;
}
}
}
// Report sent result and elapsed time. On Windows systems getrusage() is
// not implemented and hence no elapsed time is available.
if (function_exists('getrusage')) {
watchdog('simplenews', '%success emails sent in %sec seconds, %fail failed sending.', array('%success' => $count_success, '%sec' => round(_simplenews_measure_usec(), 1), '%fail' => $count_fail));
}
else {
watchdog('simplenews', '%success emails sent, %fail failed.', array('%success' => $count_success, '%fail' => $count_fail));
}
variable_set('simplenews_last_cron', REQUEST_TIME);
variable_set('simplenews_last_sent', $count_success);
simplenews_revert_user();
return $count_success;
}
}
/**
* Save mail message in mail cache table.
*
* @param array $spool
* The message to be stored in the spool table, as an array containing the
* following keys:
* - mail
* - nid
* - tid
* - status: (optional) Defaults to SIMPLENEWS_SPOOL_PENDING
* - time: (optional) Defaults to REQUEST_TIME.
*
* @ingroup spool
*/
function simplenews_save_spool($spool) {
$status = isset($spool['status']) ? $spool['status'] : SIMPLENEWS_SPOOL_PENDING;
$time = isset($spool['time']) ? $spool['time'] : REQUEST_TIME;
db_insert('simplenews_mail_spool')
->fields(array(
'mail' => $spool['mail'],
'nid' => $spool['nid'],
'tid' => $spool['tid'],
'snid' => $spool['snid'],
'status' => $status,
'timestamp' => $time,
'data' => serialize($spool['data']),
))
->execute();
}
/*
* Returns the expiration time for IN_PROGRESS status.
*
* @return int
* A unix timestamp. Any IN_PROGRESS messages with a timestamp older than
* this will be re-allocated and re-sent.
*/
function simplenews_get_expiration_time() {
$timeout = variable_get('simplenews_spool_progress_expiration', 3600);
$expiration_time = REQUEST_TIME - $timeout;
return $expiration_time;
}
/**
* This function allocates messages to be sent in current run.
*
* Drupal acquire_lock guarantees that no concurrency issue happened.
* If the message status is SIMPLENEWS_SPOOL_IN_PROGRESS but the maximum send
* time has expired, the message id will be returned as a message which is not
* allocated to another process.
*
* @param $limit
* (Optional) The maximum number of mails to load from the spool. Defaults to
* unlimited.
* @param $conditions
* (Optional) Array of conditions which are applied to the query. If not set,
* status defaults to SIMPLENEWS_SPOOL_PENDING, SIMPLENEWS_SPOOL_IN_PROGRESS.
*
* @return
* An array of message ids to be sent in the current run.
*
* @ingroup spool
*/
function simplenews_get_spool($limit = SIMPLENEWS_UNLIMITED, $conditions = array()) {
$messages = array();
// Add default status condition if not set.
if (!isset($conditions['status'])) {
$conditions['status'] = array(SIMPLENEWS_SPOOL_PENDING, SIMPLENEWS_SPOOL_IN_PROGRESS);
}
// Special case for the status condition, the in progress actually only
// includes spool items whose locking time has expired. So this need to build
// an OR condition for them.
$status_or = db_or();
$statuses = is_array($conditions['status']) ? $conditions['status'] : array($conditions['status']);
foreach ($statuses as $status) {
if ($status == SIMPLENEWS_SPOOL_IN_PROGRESS) {
$status_or->condition(db_and()
->condition('status', $status)
->condition('s.timestamp', simplenews_get_expiration_time(), '<')
);
}
else {
$status_or->condition('status', $status);
}
}
unset($conditions['status']);
$query = db_select('simplenews_mail_spool', 's')
->fields('s')
->condition($status_or)
->orderBy('s.timestamp', 'ASC');
// Add conditions.
foreach ($conditions as $field => $value) {
$query->condition($field, $value);
}
/* BEGIN CRITICAL SECTION */
// The semaphore ensures that multiple processes get different message ID's,
// so that duplicate messages are not sent.
if (lock_acquire('simplenews_acquire_mail')) {
// Get message id's
// Allocate messages
if ($limit > 0) {
$query->range(0, $limit);
}
foreach ($query->execute() as $message) {
if (strlen($message->data)) {
$message->data = unserialize($message->data);
}
else {
$message->data = simplenews_subscriber_load_by_mail($message->mail);
}
$messages[$message->msid] = $message;
}
if (count($messages) > 0) {
// Set the state and the timestamp of the messages
simplenews_update_spool(
array_keys($messages),
array('status' => SIMPLENEWS_SPOOL_IN_PROGRESS)
);
}
lock_release('simplenews_acquire_mail');
}
/* END CRITICAL SECTION */
return $messages;
}
/**
* Update status of mail data in spool table.
*
* Time stamp is set to current time.
*
* @param array $msids
* Array of Mail spool ids to be updated
* @param array $data
* Array containing email sent results, with the following keys:
* - status: An integer indicating the updated status. Must be one of:
* - 0: hold
* - 1: pending
* - 2: send
* - 3: in progress
* - error: (optional) The error id. Defaults to 0 (no error).
*
* @ingroup spool
*/
function simplenews_update_spool($msids, $data) {
db_update('simplenews_mail_spool')
->condition('msid', $msids)
->fields(array(
'status' => $data['status'],
'error' => isset($result['error']) ? (int)$data['error'] : 0,
'timestamp' => REQUEST_TIME,
))
->execute();
}
/**
* Count data in mail spool table.
*
* @param $conditions
* (Optional) Array of conditions which are applied to the query. Defaults
*
* @return
* Count of mail spool elements of the passed in arguments.
*
* @ingroup spool
*/
function simplenews_count_spool(array $conditions = array()) {
// Add default status condition if not set.
if (!isset($conditions['status'])) {
$conditions['status'] = array(SIMPLENEWS_SPOOL_PENDING, SIMPLENEWS_SPOOL_IN_PROGRESS);
}
$query = db_select('simplenews_mail_spool');
// Add conditions.
foreach ($conditions as $field => $value) {
$query->condition($field, $value);
}
$query->addExpression('COUNT(*)', 'count');
return (int)$query
->execute()
->fetchField();
}
/**
* Remove old records from mail spool table.
*
* All records with status 'send' and time stamp before the expiration date
* are removed from the spool.
*
* @return
* Number of deleted spool rows.
*
* @ingroup spool
*/
function simplenews_clear_spool() {
$expiration_time = REQUEST_TIME - variable_get('simplenews_spool_expire', 0) * 86400;
return db_delete('simplenews_mail_spool')
->condition('status', SIMPLENEWS_SPOOL_DONE)
->condition('timestamp', $expiration_time, '<=')
->execute();
}
/**
* Remove records from mail spool table according to the conditions.
*
* @return Count deleted
*
* @ingroup spool
*/
function simplenews_delete_spool(array $conditions) {
$query = db_delete('simplenews_mail_spool');
foreach ($conditions as $condition => $value) {
$query->condition($condition, $value);
}
return $query->execute();
}
/**
* Update newsletter sent status.
*
* Set newsletter sent status based on email sent status in spool table.
* Translated and untranslated nodes get a different treatment.
*
* The spool table holds data for emails to be sent and (optionally)
* already send emails. The simplenews_newsletter table contains the overall
* sent status of each newsletter issue (node).
* Newsletter issues get the status pending when sending is initiated. As
* long as unsend emails exist in the spool, the status of the newsletter remains
* unsend. When no pending emails are found the newsletter status is set 'send'.
*
* Translated newsletters are a group of nodes that share the same tnid ({node}.tnid).
* Only one node of the group is found in the spool, but all nodes should share
* the same state. Therefore they are checked for the combined number of emails
* in the spool.
*
* @ingroup issue
*/
function simplenews_send_status_update() {
$counts = array(); // number pending of emails in the spool
$sum = array(); // sum of emails in the spool per tnid (translation id)
$send = array(); // nodes with the status 'send'
// For each pending newsletter count the number of pending emails in the spool.
$query = db_select('simplenews_newsletter', 's');
$query->innerJoin('node', 'n', 's.nid = n.nid');
$query->fields('s', array('nid', 'tid'))
->fields('n', array('tnid'))
->condition('s.status', SIMPLENEWS_STATUS_SEND_PENDING);
foreach ($query->execute() as $newsletter) {
$counts[$newsletter->tnid][$newsletter->nid] = simplenews_count_spool(array('nid' => $newsletter->nid));
}
// Determine which nodes are send per translation group and per individual node.
foreach ($counts as $tnid => $node_count) {
// The sum of emails per tnid is the combined status result for the group of translated nodes.
// Untranslated nodes have tnid == 0 which will be ignored later.
$sum[$tnid] = array_sum($node_count);
foreach ($node_count as $nid => $count) {
// Translated nodes (tnid != 0)
if ($tnid != '0' && $sum[$tnid] == '0') {
$send[] = $nid;
}
// Untranslated nodes (tnid == 0)
elseif ($tnid == '0' && $count == '0') {
$send[] = $nid;
}
}
}
// Update overall newsletter status
if (!empty($send)) {
foreach ($send as $nid) {
db_update('simplenews_newsletter')
->condition('nid', $nid)
->fields(array('status' => SIMPLENEWS_STATUS_SEND_READY))
->execute();
}
}
}
/**
* Build formatted from-name and email for a mail object.
*
* @return Associative array with (un)formatted from address
* 'address' => From address
* 'formatted' => Formatted, mime encoded, from name and address
*/
function _simplenews_set_from() {
$address_default = variable_get('site_mail', ini_get('sendmail_from'));
$name_default = variable_get('site_name', 'Drupal');
$address = variable_get('simplenews_from_address', $address_default);
$name = variable_get('simplenews_from_name', $name_default);
// Windows based PHP systems don't accept formatted emails.
$formatted_address = substr(PHP_OS, 0, 3) == 'WIN' ? $address : '"' . $name . '" <' . $address . '>';
return array(
'address' => $address,
'formatted' => $formatted_address,
);
}
/**
* HTML to text conversion for HTML and special characters.
*
* Converts some special HTML characters in addition to drupal_html_to_text()
*
* @param string $text
* The source text with HTML and special characters.
* @param boolean $inline_hyperlinks
* TRUE: URLs will be placed inline.
* FALSE: URLs will be converted to numbered reference list.
* @return string
* The target text with HTML and special characters replaced.
*/
function simplenews_html_to_text($text, $inline_hyperlinks = TRUE) {
// By replacing <a> tag by only its URL the URLs will be placed inline
// in the email body and are not converted to a numbered reference list
// by drupal_html_to_text().
// URL are converted to absolute URL as drupal_html_to_text() would have.
if ($inline_hyperlinks) {
$pattern = '@<a[^>]+?href="([^"]*)"[^>]*?>(.+?)</a>@is';
$text = preg_replace_callback($pattern, '_simplenews_absolute_mail_urls', $text);
}
// Replace some special characters before performing the drupal standard conversion.
$preg = _simplenews_html_replace();
$text = preg_replace(array_keys($preg), array_values($preg), $text);
// Perform standard drupal html to text conversion.
return drupal_html_to_text($text);
}
/**
* Helper function for simplenews_html_to_text().
*
* Replaces URLs with absolute URLs.
*/
function _simplenews_absolute_mail_urls($match) {
global $base_url, $base_path;
$regexp = &drupal_static(__FUNCTION__);
$url = $label = '';
if ($match) {
if (empty($regexp)) {
$regexp = '@^' . preg_quote($base_path, '@') . '@';
}
list(, $url, $label) = $match;
$url = strpos($url, '://') ? $url : preg_replace($regexp, $base_url . '/', $url);
// If the link is formed by Drupal's URL filter, we only return the URL.
// The URL filter generates a label out of the original URL.
if (strpos($label, '...') === strlen($label) - 3) {
// Remove ellipsis from end of label.
$label = substr($label, 0, strlen($label) - 3);
}
if (strpos($url, $label) !== FALSE) {
return $url;
}
return $label . ' ' . $url;
}
}
/**
* Helper function for simplenews_html_to_text().
*
* List of preg* regular expression patterns to search for and replace with
*/
function _simplenews_html_replace() {
return array(
'/&quot;/i' => '"',
'/&gt;/i' => '>',
'/&lt;/i' => '<',
'/&amp;/i' => '&',
'/&copy;/i' => '(c)',
'/&trade;/i' => '(tm)',
'/&#8220;/' => '"',
'/&#8221;/' => '"',
'/&#8211;/' => '-',
'/&#8217;/' => "'",
'/&#38;/' => '&',
'/&#169;/' => '(c)',
'/&#8482;/' => '(tm)',
'/&#151;/' => '--',
'/&#147;/' => '"',
'/&#148;/' => '"',
'/&#149;/' => '*',
'/&reg;/i' => '(R)',
'/&bull;/i' => '*',
'/&euro;/i' => 'Euro ',
);
}
/**
* Helper function to measure PHP execution time in microseconds.
*
* @param bool $start
* If TRUE, reset the time and start counting.
*
* @return float
* The elapsed PHP execution time since the last start.
*/
function _simplenews_measure_usec($start = FALSE) {
// Windows systems don't implement getrusage(). There is no alternative.
if (!function_exists('getrusage')) {
return;
}
$start_time = &drupal_static(__FUNCTION__);
$usage = getrusage();
$now = (float)($usage['ru_stime.tv_sec'] . '.' . $usage['ru_stime.tv_usec']) + (float)($usage['ru_utime.tv_sec'] . '.' . $usage['ru_utime.tv_usec']);
if ($start) {
$start_time = $now;
return;
}
return $now - $start_time;
}
/**
* Build subject and body of the test and normal newsletter email.
*
* @param array $message
* Message array as used by hook_mail().
* @param array $source
* The SimplenewsSource instance.
*
* @ingroup source
*/
function simplenews_build_newsletter_mail(&$message, SimplenewsSourceInterface $source) {
// Get message data from source.
$message['headers'] = $source->getHeaders($message['headers']);
$message['subject'] = $source->getSubject();
$message['body']['body'] = $source->getBody();
$message['body']['footer'] = $source->getFooter();
// Optional params for HTML mails.
if ($source->getFormat() == 'html') {
$message['params']['plain'] = NULL;
$message['params']['plaintext'] = $source->getPlainBody() . "\n" . $source->getPlainFooter();
$message['params']['attachments'] = $source->getAttachments();
}
else {
$message['params']['plain'] = TRUE;
}
}
/**
* Build subject and body of the subscribe confirmation email.
*
* @param array $message
* Message array as used by hook_mail().
* @param array $params
* Parameter array as used by hook_mail().
*/
function simplenews_build_subscribe_mail(&$message, $params) {
$context = $params['context'];
$langcode = $message['language'];
// Use formatted from address "name" <mail_address>
$message['headers']['From'] = $params['from']['formatted'];
$message['subject'] = simplenews_subscription_confirmation_text('subscribe_subject', $langcode);
$message['subject'] = token_replace($message['subject'], $context, array('sanitize' => FALSE));
if (simplenews_user_is_subscribed($context['simplenews_subscriber']->mail, $context['category']->tid)) {
$body = simplenews_subscription_confirmation_text('subscribe_subscribed', $langcode);
}
else {
$body = simplenews_subscription_confirmation_text('subscribe_unsubscribed', $langcode);
}
$message['body'][] = token_replace($body, $context, array('sanitize' => FALSE));
}
/**
* Build subject and body of the subscribe confirmation email.
*
* @param array $message
* Message array as used by hook_mail().
* @param array $params
* Parameter array as used by hook_mail().
*/
function simplenews_build_combined_mail(&$message, $params) {
$context = $params['context'];
$changes = $context['changes'];
$langcode = $message['language'];
// Use formatted from address "name" <mail_address>
$message['headers']['From'] = $params['from']['formatted'];
$message['subject'] = simplenews_subscription_confirmation_text('combined_subject', $langcode);
$message['subject'] = token_replace($message['subject'], $context, array('sanitize' => FALSE));
$changes_list = '';
$actual_changes = 0;
foreach (simplenews_confirmation_get_changes_list($context['simplenews_subscriber'], $changes, $langcode) as $tid => $change) {
$changes_list .= ' - ' . $change . "\n";
// Count the actual changes.
$subscribed = simplenews_user_is_subscribed($context['simplenews_subscriber']->mail, $tid);
if ($changes[$tid] == 'subscribe' && !$subscribed || $changes[$tid] == 'unsubscribe' && $subscribed) {
$actual_changes++;
}
}
// If there are actual changes, use the combined_body key otherwise use the
// one without a confirmation link.
$body_key = $actual_changes ? 'combined_body' : 'combined_body_unchanged';
$body = simplenews_subscription_confirmation_text($body_key, $langcode);
// The changes list is not an actual token.
$body = str_replace('[changes-list]', $changes_list, $body);
$message['body'][] = token_replace($body, $context, array('sanitize' => FALSE));
}
/**
* Build subject and body of the unsubscribe confirmation email.
*
* @param array $message
* Message array as used by hook_mail().
* @param array $params
* Parameter array as used by hook_mail().
*/
function simplenews_build_unsubscribe_mail(&$message, $params) {
$context = $params['context'];
$langcode = $message['language'];
// Use formatted from address "name" <mail_address>
$message['headers']['From'] = $params['from']['formatted'];
$message['subject'] = simplenews_subscription_confirmation_text('subscribe_subject', $langcode);
$message['subject'] = token_replace($message['subject'], $context, array('sanitize' => FALSE));
if (simplenews_user_is_subscribed($context['simplenews_subscriber']->mail, $context['category']->tid)) {
$body = simplenews_subscription_confirmation_text('unsubscribe_subscribed', $langcode);
$message['body'][] = token_replace($body, $context, array('sanitize' => FALSE));
}
else {
$body = simplenews_subscription_confirmation_text('unsubscribe_unsubscribed', $langcode);
$message['body'][] = token_replace($body, $context, array('sanitize' => FALSE));
}
}
/**
* A mail sending implementation that captures sent messages to a variable.
*
* This class is for running tests or for development and does not convert HTML
* to plaintext.
*/
class SimplenewsHTMLTestingMailSystem implements MailSystemInterface {
/**
* Implements MailSystemInterface::format().
*/
public function format(array $message) {
// Join the body array into one string.
$message['body'] = implode("\n\n", $message['body']);
// Wrap the mail body for sending.
$message['body'] = drupal_wrap_mail($message['body']);
return $message;
}
/**
* Implements MailSystemInterface::mail().
*/
public function mail(array $message) {
$captured_emails = variable_get('drupal_test_email_collector', array());
$captured_emails[] = $message;
// @todo: This is rather slow when sending 100 and more mails during tests.
// Investigate in other methods like APC shared memory.
variable_set('drupal_test_email_collector', $captured_emails);
return TRUE;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,818 @@
<?php
/**
* @file
* (Un)subscription and (un)subscription confirmation
*
* FAPI subscription form cases:
* - ACCOUNT
* self/admin action: authenticated user
* via hook_user form: category=newsletter
*
* - BLOCK
* self action: anonymous / authenticated user
* via hook_block: block
*
* - PAGE
* self action: anonymous / authenticated user
* callback: newsletter/subscriptions
*
* - MULTI BLOCK
* self action: anonymous / authenticated user
* authenticated user
* via hook_block: multi_block
* using PAGE handlers
*
* - ADMIN
* admin action: authenticated user
* via hook_menu: admin
*
* FAPI additional form cases:
* - CONFIRM ADD
* - CONFIRM REMOVAL
*
* @ingroup simplenews
*/
/**
* FAPI ACCOUNT subscription form.
*
* Finally _account_ cases inject into hook_user and won't work on its own.
* Note that our basis is:
* drupal_get_form('user_profile_form', ...);
* and NOT:
* drupal_get_form('simplenews_subscriptions_account', ...);
*
* see also user/user.module and user/user.pages.inc
*
* @see simplenews_subscriptions_account_form_validate()
* @see simplenews_subscriptions_account_form_submit()
*/
function simplenews_subscriptions_account_form(&$form, &$form_state, $subscriber) {
$options = array();
$default_value = array();
// Get newsletters for subscription form checkboxes.
// Newsletters with opt-in/out method 'hidden' will not be listed.
foreach (simplenews_category_get_visible() as $newsletter) {
$options[$newsletter->tid] = check_plain(_simplenews_newsletter_name($newsletter));
$default_value[$newsletter->tid] = FALSE;
}
if ($subscriber) {
$default_value = array_merge($default_value, $subscriber->tids);
}
$form['subscriptions'] = array(
'#type' => 'fieldset',
'#description' => t('Select your newsletter subscriptions.'),
);
$form['subscriptions']['newsletters'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $default_value,
);
$form['subscriptions']['#title'] = t('Current newsletter subscriptions');
// if we don't override #validate, see user_profile_form_validate
// adding an own #submit leads to the situation where drupal omits execution of user_profile_form_submit completely
$form['#submit'][] = 'simplenews_subscriptions_account_form_submit';
}
/**
* FAPI ACCOUNT subscription form_submit.
*/
function simplenews_subscriptions_account_form_submit($form, &$form_state) {
global $user;
$account = $form['#user'];
// We first subscribe, then unsubscribe. This prevents deletion of subscriptions
// when unsubscribed from the
arsort($form_state['values']['newsletters'], SORT_NUMERIC);
foreach ($form_state['values']['newsletters'] as $tid => $checked) {
if ($checked) {
simplenews_subscribe_user($account->mail, $tid, FALSE, 'website');
}
else {
simplenews_unsubscribe_user($account->mail, $tid, FALSE, 'website');
}
}
if ($user->uid == $account->uid) {
drupal_set_message(t('Your newsletter subscriptions have been updated.'));
}
else {
drupal_set_message(t('The newsletter subscriptions for user %account have been updated.', array('%account' => $account->name)));
}
}
/**
* FAPI BLOCK subscription form.
*
* @param $tid term id of selected newsletter.
*
* @see simplenews_block_form_validate()
* @see simplenews_block_form_submit()
*/
function simplenews_block_form($form, &$form_state, $tid) {
global $user;
$form = array();
$submit_text = t('Subscribe');
if ($user->uid) {
if (simplenews_user_is_subscribed($user->mail, $tid)) {
$submit_text = t('Unsubscribe');
$form['action'] = array('#type' => 'value', '#value' => 'unsubscribe');
$form['#attributes'] = array('class' => array('simplenews-unsubscribe'));
}
else {
$form['action'] = array('#type' => 'value', '#value' => 'subscribe');
$form['#attributes'] = array('class' => array('simplenews-subscribe'));
}
$form['mail'] = array('#type' => 'value', '#value' => $user->mail);
}
else {
$form['mail'] = array(
'#type' => 'textfield',
'#title' => t('E-mail'),
'#size' => 20,
'#maxlength' => 128,
'#required' => TRUE,
);
$form['action'] = array('#type' => 'value', '#value' => 'subscribe');
$form['#attributes'] = array('class' => array('simplenews-subscribe'));
}
// All block forms use the same validate and submit function.
// #tid carries the tid for processing of the right newsletter issue term.
$form['#tid'] = $tid;
$form['#validate'][] = 'simplenews_block_form_validate';
$form['#submit'][] = 'simplenews_block_form_submit';
$form['submit'] = array(
'#type' => 'submit',
'#value' => $submit_text,
);
return $form;
}
/*
* FAPI BLOCK subscription form_validate.
*/
function simplenews_block_form_validate($form, &$form_state) {
if (!valid_email_address($form_state['values']['mail'])) {
form_set_error('mail', t("The e-mail address you supplied is not valid."));
}
}
/*
* FAPI BLOCK subscription form_submit.
*/
function simplenews_block_form_submit($form, &$form_state) {
$tid = $form['#tid'];
$account = simplenews_load_user_by_mail($form_state['values']['mail']);
$confirm = simplenews_require_double_opt_in($tid, $account);
switch ($form_state['values']['action']) {
case 'subscribe':
simplenews_subscribe_user($form_state['values']['mail'], $tid, $confirm, 'website');
if ($confirm) {
drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.'));
}
else {
drupal_set_message(t('You have been subscribed.'));
}
break;
case 'unsubscribe':
simplenews_unsubscribe_user($form_state['values']['mail'], $tid, $confirm, 'website');
if ($confirm) {
drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to cancel your subscription.'));
}
else {
drupal_set_message(t('You have been unsubscribed.'));
}
break;
}
}
/**
* FAPI PAGE subscription form.
*
* @see simplenews_subscriptions_page_form_validate()
* @see simplenews_subscriptions_page_form_submit()
*/
function simplenews_subscriptions_page_form($form, &$form_state, $code = NULL) {
global $user;
$subscriber = $mail = FALSE;
if (!empty($user->mail)) {
$subscriber = simplenews_subscriber_load_by_mail($user->mail);
$mail = $user->mail;
}
// If a hash is provided, try to load the corresponding subscriber.
else if ($code) {
if (!$subscriber = simplenews_subscriber_load_by_hash($code)) {
drupal_not_found();
return;
}
$mail = $subscriber->mail;
}
$form = array();
$options = array();
$default_value = array();
// Get newsletters for subscription form checkboxes.
// Newsletters with opt-in/out method 'hidden' will not be listed.
foreach (simplenews_category_get_visible() as $newsletter) {
$options[$newsletter->tid] = check_plain($newsletter->name);
$default_value[$newsletter->tid] = FALSE;
}
if ($subscriber) {
// If there is an existing subscriber object, use the existing settings.
$default_value = array_merge($default_value, $subscriber->tids);
}
$form['subscriptions'] = array(
'#type' => 'fieldset',
);
$form['subscriptions']['newsletters'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $default_value
);
// If we have a mail address, which is either from a logged in user or a
// subscriber identified through the hash code, display the mail address
// instead of a textfield. Anonymous uses will still have to confirm any
// changes.
if ($mail) {
$form['subscriptions']['#title'] = t('Subscriptions for %mail', array('%mail' => $mail));
$form['subscriptions']['#description'] = t('Check the newsletters you want to subscribe to. Uncheck the ones you want to unsubscribe from.');
$form['subscriptions']['mail'] = array('#type' => 'value', '#value' => $mail);
$form['update'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#weight' => 20,
// @todo: add clean submit handler
);
}
else {
$form['subscriptions']['#title'] = t('Manage your newsletter subscriptions');
$form['subscriptions']['#description'] = t('Select the newsletter(s) to which you want to subscribe or unsubscribe.');
$form['subscriptions']['mail'] = array(
'#type' => 'textfield',
'#title' => t('E-mail'),
'#size' => 20,
'#maxlength' => 128,
'#weight' => 10,
'#required' => TRUE,
);
$form['subscribe'] = array(
'#type' => 'submit',
'#value' => t('Subscribe'),
'#weight' => 20,
// @todo: add clean submit handler
);
$form['unsubscribe'] = array(
'#type' => 'submit',
'#value' => t('Unsubscribe'),
'#weight' => 30,
// @todo: add clean submit handler
);
}
$form['#validate'][] = 'simplenews_subscriptions_page_form_validate';
$form['#submit'][] = 'simplenews_subscriptions_page_form_submit';
return $form;
}
/**
* FAPI PAGE subscription form_validate.
*/
function simplenews_subscriptions_page_form_validate($form, &$form_state) {
$valid_email = valid_email_address($form_state['values']['mail']);
if (!$valid_email) {
form_set_error('mail', t('The e-mail address you supplied is not valid.'));
}
$checked_newsletters = array_filter($form_state['values']['newsletters']);
// Unless we're in update mode, at least one checkbox must be checked.
if (!count($checked_newsletters) && $form_state['values']['op'] != t('Update')) {
form_set_error('newsletters', t('You must select at least one newsletter.'));
}
}
/**
* FAPI PAGE subscription form_submit.
*/
function simplenews_subscriptions_page_form_submit($form, &$form_state) {
$mail = $form_state['values']['mail'];
$account = simplenews_load_user_by_mail($mail);
// Group confirmation mails as necessary and configured.
simplenews_confirmation_combine(TRUE);
switch ($form_state['values']['op']) {
case t('Update'):
// We first subscribe, then unsubscribe. This prevents deletion of subscriptions
// when unsubscribed from the
arsort($form_state['values']['newsletters'], SORT_NUMERIC);
foreach ($form_state['values']['newsletters'] as $tid => $checked) {
$confirm = simplenews_require_double_opt_in($tid, $account);
if ($checked) {
simplenews_subscribe_user($mail, $tid, $confirm, 'website');
}
else {
simplenews_unsubscribe_user($mail, $tid, $confirm, 'website');
}
}
if (simplenews_confirmation_send_combined()) {
drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.'));
}
else {
drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_state['values']['mail'])));
}
break;
case t('Subscribe'):
foreach ($form_state['values']['newsletters'] as $tid => $checked) {
if ($checked) {
$confirm = simplenews_require_double_opt_in($tid, $account);
simplenews_subscribe_user($mail, $tid, $confirm, 'website');
}
}
if (simplenews_confirmation_send_combined()) {
drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to complete your subscription.'));
}
else {
drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_state['values']['mail'])));
}
break;
case t('Unsubscribe'):
foreach ($form_state['values']['newsletters'] as $tid => $checked) {
if ($checked) {
$confirm = simplenews_require_double_opt_in($tid, $account);
simplenews_unsubscribe_user($mail, $tid, $confirm, 'website');
}
}
if (simplenews_confirmation_send_combined()) {
drupal_set_message(t('You will receive a confirmation e-mail shortly containing further instructions on how to cancel your subscription.'));
}
else {
drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_state['values']['mail'])));
}
break;
}
}
/**
* FAPI MULTI BLOCK subscription form.
*
* Menu callback: Generates the subscription form for users for the multisignup block.
*
* @see simplenews_subscriptions_multi_block_form_validate()
* @see simplenews_subscriptions_multi_block_form_submit()
*/
function simplenews_subscriptions_multi_block_form($form, &$form_state) {
global $user;
$subscriber = !empty($user->mail) ? simplenews_subscriber_load_by_mail($user->mail) : FALSE;
// If someone not authorized to edit their subscription, return empty form.
if (!user_access('subscribe to newsletters')) {
return;
}
$form = array();
$options = array();
$default_value = array();
// Get newsletters for subscription form checkboxes.
// Newsletters with opt-in/out method 'hidden' will not be listed.
foreach (simplenews_category_get_visible() as $newsletter) {
$options[$newsletter->tid] = check_plain($newsletter->name);
$default_value[$newsletter->tid] = FALSE;
}
if ($subscriber) {
// If there is an existing subscriber object, use the existing settings.
$default_value = array_merge($default_value, $subscriber->tids);
}
$form['newsletters'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => $default_value,
);
// If current user is logged in, just display email.
// Anonymous users see an email box and will receive confirmations
if (user_is_logged_in()) {
// @todo why not simply Manage your subscriptions?
$form['mail'] = array('#type' => 'value', '#value' => $user->mail);
$form['update'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#weight' => 20,
// @todo: add clean submit handler
);
}
else {
$form['mail'] = array(
'#type' => 'textfield',
'#title' => t('E-mail'),
'#size' => 20,
'#maxlength' => 128,
'#weight' => 10,
'#required' => TRUE,
);
$form['subscribe'] = array(
'#type' => 'submit',
'#value' => t('Subscribe'),
'#weight' => 20,
// @todo: add clean submit handler
);
$form['unsubscribe'] = array(
'#type' => 'submit',
'#value' => t('Unsubscribe'),
'#weight' => 30,
// @todo: add clean submit handler
);
}
$form['#validate'][] = 'simplenews_subscriptions_page_form_validate';
$form['#submit'][] = 'simplenews_subscriptions_page_form_submit';
return $form;
}
/**
* Menu callback: confirm the user's (un)subscription request
*
* This function is called by clicking the confirm link in the confirmation
* email or the unsubscribe link in the footer of the newsletter. It handles
* both subscription addition and subscription removal.
*
* Calling URLs are:
* newsletter/confirm/add
* newsletter/confirm/add/$HASH
* newsletter/confirm/remove
* newsletter/confirm/remove/$HASH
*
* @see simplenews_confirm_add_form()
* @see simplenews_confirm_removal_form()
*/
/**
* Menu callback: confirm the user's (un)subscription request
*
* This function is called by clicking the confirm link in the confirmation
* email or the unsubscribe link in the footer of the newsletter. It handles
* both subscription addition and subscription removal.
*
* @see simplenews_confirm_add_form()
* @see simplenews_confirm_removal_form()
*
* @todo Add parameter description here.
*/
function simplenews_confirm_subscription() {
$arguments = func_get_args();
$op = array_shift($arguments);
$code = array_shift($arguments);
if ($subscriber = simplenews_subscriber_load_by_hash($code)) {
// Extract the category id.
list($snid, $tid) = explode('t', drupal_substr($code, 10));
if ($tid > 0) {
$category = simplenews_category_load($tid);
}
// The confirmation page called with two arguments will display a confirmation question.
// When called with three of more arguments the user will be directed to the
// (un)subscribe confirmation page. The additional arguments will be passed on
// to the confirmation page.
if (empty($arguments)) {
if ($op == 'remove') {
return drupal_get_form('simplenews_confirm_removal_form', $subscriber->mail, $category);
}
elseif ($op == 'add') {
return drupal_get_form('simplenews_confirm_add_form', $subscriber->mail, $category);
}
elseif ($op == 'combined' && !empty($subscriber->changes)) {
return drupal_get_form('simplenews_confirm_multi_form', $subscriber);
}
}
else {
if ($op == 'remove') {
simplenews_unsubscribe_user($subscriber->mail, $tid, FALSE, 'website');
if ($path = variable_get('simplenews_confirm_unsubscribe_page', '')) {
$path = $path . '/' . implode('/', $arguments);
drupal_goto($path);
}
drupal_set_message(t('%user was unsubscribed from the %newsletter mailing list.', array('%user' => $subscriber->mail, '%newsletter' => _simplenews_newsletter_name($category))));
drupal_goto(variable_get('site_frontpage', 'node'));
}
else if ($op == 'add') {
simplenews_subscribe_user($subscriber->mail, $tid, FALSE, 'website');
if ($path = variable_get('simplenews_confirm_subscribe_page', '')) {
$path = $path . '/' . implode('/', $arguments);
drupal_goto($path);
}
drupal_set_message(t('%user was added to the %newsletter mailing list.', array('%user' => $subscriber->mail, '%newsletter' => _simplenews_newsletter_name($category))));
drupal_goto(variable_get('site_frontpage', 'node'));
}
else if ($op == 'combined' && !empty($subscriber->changes)) {
foreach ($subscriber->changes as $tid => $action) {
if ($action == 'subscribe') {
simplenews_subscribe_user($subscriber->mail, $tid, FALSE, 'website');
}
else if ($action == 'subscribe') {
simplenews_unsubscribe_user($subscriber->mail, $tid, FALSE, 'website');
}
}
// Clear changes.
$subscriber->changes = array();
simplenews_subscriber_save($subscriber);
drupal_set_message(t('Subscription changes confirmed for %user.', array('%user' => $subscriberil)));
drupal_goto(variable_get('site_frontpage', 'node'));
}
}
}
// If md5 didn't match, do a not found.
drupal_not_found();
return;
}
/**
* Generate the confirm subscription form.
*
* @see simplenews_confirm_add_form_submit()
*/
function simplenews_confirm_add_form($form, &$form_state, $mail, $newsletter) {
$form = array();
$form['question'] = array(
'#markup' => '<p>' . t('Are you sure you want to add %user to the %newsletter mailing list?', array('%user' => $mail, '%newsletter' => _simplenews_newsletter_name($newsletter))) . "<p>\n",
);
$form['mail'] = array(
'#type' => 'value',
'#value' => $mail,
);
$form['newsletter'] = array(
'#type' => 'value',
'#value' => $newsletter,
);
return confirm_form($form,
t('Confirm subscription'),
'',
t('You can always unsubscribe later.'),
t('Subscribe'),
t('Cancel')
);
}
function simplenews_confirm_add_form_submit($form, &$form_state) {
simplenews_subscribe_user($form_state['values']['mail'], $form_state['values']['newsletter']->tid, FALSE, 'website');
if (!$path = variable_get('simplenews_confirm_subscribe_page', '')){
$path = variable_get('site_frontpage', 'node');
drupal_set_message(t('%user was added to the %newsletter mailing list.', array('%user' => $form_state['values']['mail'], '%newsletter' => _simplenews_newsletter_name($form_state['values']['newsletter']))));
}
$form_state['redirect'] = $path;
}
/**
* Generate the confirm subscription form.
*
* @see simplenews_confirm_add_form_submit()
*/
function simplenews_confirm_multi_form($form, &$form_state, $subscriber) {
$form = array();
$form['question'] = array(
'#markup' => '<p>' . t('Are you sure you want to confirm the following subscription changes for %user?', array('%user' => $subscriber->mail)) . "<p>\n",
);
$form['changes'] = array(
'#theme' => 'item_list',
'#items' => simplenews_confirmation_get_changes_list($subscriber),
);
$form['subscriber'] = array(
'#type' => 'value',
'#value' => $subscriber,
);
return confirm_form($form,
t('Confirm subscription'),
'',
t('You can always change your subscriptions later.'),
t('Confirm'),
t('Cancel')
);
}
function simplenews_confirm_multi_form_submit($form, &$form_state) {
$subscriber = $form_state['values']['subscriber'];
foreach ($subscriber->changes as $tid => $action) {
if ($action == 'subscribe') {
simplenews_subscribe_user($subscriber->mail, $tid, FALSE, 'website');
}
else if ($action == 'unsubscribe') {
simplenews_unsubscribe_user($subscriber->mail, $tid, FALSE, 'website');
}
}
// Clear changes.
$subscriber->changes = array();
simplenews_subscriber_save($subscriber);
drupal_set_message(t('Subscription changes confirmed for %user.', array('%user' => $subscriber->mail)));
$form_state['redirect'] = variable_get('site_frontpage', 'node');
}
/**
* Generate the confirm unsubscription form.
*
* @see simplenews_confirm_removal_form_submit()
*/
function simplenews_confirm_removal_form($form, &$form_state, $mail, $newsletter) {
$form = array();
$form['question'] = array(
'#markup' => '<p>' . t('Are you sure you want to remove %user from the %newsletter mailing list?', array('%user' => $mail, '%newsletter' => _simplenews_newsletter_name($newsletter))) . "<p>\n",
);
$form['mail'] = array(
'#type' => 'value',
'#value' => $mail,
);
$form['newsletter'] = array(
'#type' => 'value',
'#value' => $newsletter,
);
return confirm_form($form,
t('Confirm remove subscription'),
'',
t('This action will unsubscribe you from the newsletter mailing list.'),
t('Unsubscribe'),
t('Cancel')
);
}
function simplenews_confirm_removal_form_submit($form, &$form_state) {
simplenews_unsubscribe_user($form_state['values']['mail'], $form_state['values']['newsletter']->tid, FALSE, 'website');
if (!$path = variable_get('simplenews_confirm_unsubscribe_page', '')){
$path = variable_get('site_frontpage', 'node');
drupal_set_message(t('%user was unsubscribed from the %newsletter mailing list.', array('%user' => $form_state['values']['mail'], '%newsletter' => _simplenews_newsletter_name($form_state['values']['newsletter']))));
}
$form_state['redirect'] = $path;
}
/**
* FAPI ADMIN subscription form.
*
* Menu callback: handle the edit subscription page and a subscription
* page for anonymous users.
*
* @see simplenews_subscriptions_admin_form_validate()
* @see simplenews_subscriptions_admin_form_submit()
*/
function simplenews_subscriptions_admin_form($form, &$form_state, $snid) {
$subscriber = simplenews_subscriber_load($snid);
$form = array();
$options = array();
$default_value = array();
// Get newsletters for subscription form checkboxes.
// Newsletters with opt-in/out method 'hidden' will not be listed.
foreach (simplenews_category_get_visible() as $newsletter) {
$options[$newsletter->tid] = check_plain($newsletter->name);
$default_value[$newsletter->tid] = FALSE;
}
$form['subscriptions'] = array(
'#title' => t('Subscriptions for %mail', array('%mail' => $subscriber->mail)),
'#type' => 'fieldset',
'#description' => t('Select the newsletter(s) to add/remove from subscription.'),
);
$form['subscriptions']['newsletters'] = array(
'#type' => 'checkboxes',
'#options' => $options,
'#default_value' => array_merge($default_value, $subscriber->tids),
);
$form['activated'] = array(
'#title' => t('Activation'),
'#type' => 'fieldset',
'#description' => t('Activate or inactivate account.'),
);
$form['activated']['activated'] = array(
'#type' => 'checkbox',
'#title' => t('Activated'),
'#default_value' => $subscriber->activated,
);
if ((variable_get('language_count', 1) > 1)) {
// @todo we could allow to switch back to "default", but user_load
//$language_options[''] = t('Site default language');
$languages = language_list('enabled');
foreach ($languages[1] as $langcode => $item) {
$name = t($item->name);
$language_options[$langcode] = $name . ($item->native != $name ? ' ('. $item->native .')' : '');
}
// std users have language in profile. disable
$disabled = $subscriber->uid ? TRUE : FALSE;
$form['language'] = array(
'#type' => 'fieldset',
'#title' => 'Preferred language',
'#description' => t('The e-mails will be localized in language chosen. Real users have their preference in account settings.'),
'#disabled' => FALSE,
);
if ($subscriber->uid) {
// fapi error: disabled not supported for select type. workaround: output markup
$form['language']['language'] = array(
'#type' => 'markup',
'#value' => $language_options[$subscriber->language],
);
}
else {
$form['language']['language'] = array(
'#type' => 'select',
'#default_value' => $subscriber->language,
'#options' => $language_options,
);
}
}
$form['subscriptions']['mail'] = array('#type' => 'value', '#value' => $subscriber->mail);
$form['update'] = array(
'#type' => 'submit',
'#value' => t('Update'),
'#weight' => 20,
);
$form['#validate'][] = 'simplenews_subscriptions_admin_form_validate';
$form['#submit'][] = 'simplenews_subscriptions_admin_form_submit';
$form['#redirect'] = 'admin/content/simplenews/users';
return $form;
}
/**
* FAPI ADMIN subscription form_validate.
*/
function simplenews_subscriptions_admin_form_validate($form, &$form_state) {
$subscriber = simplenews_subscriber_load_by_mail($form_state['values']['mail']);
$valid_email = valid_email_address($form_state['values']['mail']);
if (!$valid_email) {
form_set_error('mail', t('The e-mail address you supplied is not valid.'));
}
$checked_newsletters = array_filter($form_state['values']['newsletters']);
if (!count($checked_newsletters) && !$subscriber) {
form_set_error('newsletters', t('You must select at least one newsletter.'));
}
$languages = language_list('enabled');
if (!empty($form_state['values']['language'])
&& !isset($languages[1][$form_state['values']['language']])) {
form_set_error('language', t('Please choose a language from the list.'));
}
}
/**
* FAPI ADMIN subscription form_submit.
*/
function simplenews_subscriptions_admin_form_submit($form, &$form_state) {
$subscriber = simplenews_subscriber_load_by_mail($form_state['values']['mail']);
// update subscriptions
arsort($form_state['values']['newsletters'], SORT_NUMERIC);
foreach ($form_state['values']['newsletters'] as $tid => $checked) {
if ($checked) {
simplenews_subscribe_user($form_state['values']['mail'], $tid, FALSE, 'website');
}
else {
simplenews_unsubscribe_user($form_state['values']['mail'], $tid, FALSE, 'website');
}
}
// update subscriber
$data = array();
$subscriber->activated = $form_state['values']['activated'];
if (!$subscriber->uid) {
if (isset($form_state['values']['language'])) {
$subscriber->language = $form_state['values']['language'];
}
}
simplenews_subscriber_save($subscriber);
drupal_set_message(t('The newsletter subscriptions for %mail have been updated.', array('%mail' => $form_state['values']['mail'])));
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* @file
* Views handler for simplenews field simplewnews_category.hyperlinks.
*/
/**
* Provide HTML Mail Hyperlinks position settings.
*/
class simplenews_handler_field_category_hyperlinks extends views_handler_field {
function render($values) {
switch ($values->{$this->field_alias}) {
case 0:
return t('Bottom');
case 1:
return t('Inline');
}
}
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* @file
* Views field handler for simplenews_category.opt_inout.
*/
/**
* Provide translatable simplenews_category.opt_inout Options.
*/
class simplenews_handler_field_category_new_account extends views_handler_field {
function render($values) {
$opt = array(
'none' => t('None'),
'on' => t('Default on'),
'off' => t('Default off'),
'silent' => t('invisible Subscrition'),
);
return check_plain($opt[$values->{$this->field_alias}]);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* @file
* Views field handler for simplenews_category.opt_inout.
*/
/**
* Provide translatable simplenews_category.opt_inout Options.
*/
class simplenews_handler_field_category_opt_inout extends views_handler_field {
function render($values) {
$opt = array(
'hidden' => t('Hidden'),
'single' => t('Single opt-in'),
'double' => t('Double opt-in'),
);
return check_plain($opt[$values->{$this->field_alias}]);
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* @file
* Views field handler for simplenews newsletter priority.
*/
/**
* Display simplenews newsletter priorities. See simplenews.admin.inc
* @ row 1427 for definition of the simplenews_get_priority() function
*/
class simplenews_handler_field_newsletter_priority extends views_handler_field {
function render($values) {
module_load_include('inc', 'simplenews', 'includes/simplenews.admin');
$p = simplenews_get_priority();
return check_plain($p[$values->{$this->field_alias}]);
}
}

View File

@@ -0,0 +1,26 @@
<?php
/**
* Field handler to present a link to close or open commenting on a node.
*/
class simplenews_handler_field_newsletter_send extends views_handler_field_node_link {
/**
* Renders the link.
*/
function render_link($node, $values) {
// Ensure user has access to delete this node.
if (!user_access('send newsletter')) {
return;
}
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['query'] = drupal_get_destination();
if ($node->simplenews->status == SIMPLENEWS_STATUS_SEND_NOT) {
$this->options['alter']['path'] = "node/$node->nid/simplenews";
$text = !empty($this->options['text']) ? $this->options['text'] : t('Send newsletter');
return $text;
}
else {
return;
}
}
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* @file
* Views handler for simplenews sent status.
*/
/**
* Display newsletter sent status.
*/
class simplenews_handler_field_newsletter_status extends views_handler_field {
function render($values) {
switch ($values->{$this->field_alias}) {
case SIMPLENEWS_STATUS_SEND_NOT:
default:
return t('Not sent');
case SIMPLENEWS_STATUS_SEND_PENDING:
return t('Pending');
case SIMPLENEWS_STATUS_SEND_READY:
return t('Sent');
}
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* @file
* Views handler for simplenews field simplewnews_category.hyperlinks.
*/
/**
* Display HTML Mail Hyperlinks position settings.
*/
class simplenews_handler_filter_category_hyperlinks extends views_handler_filter_in_operator {
function get_value_options() {
$this->value_options = array(
0 => t('Bottom'),
1 => t('Inline'),
);
}
}

View File

@@ -0,0 +1,20 @@
<?php
/**
* @file
* Views fiter handler for simplenews_category.new_account.
*/
/**
* Provide translatable simplenews_category.new_account Options.
*/
class simplenews_handler_filter_category_new_account extends views_handler_filter_in_operator {
function get_value_options() {
$this->value_options = array(
'none' => t('None'),
'on' => t('Default on'),
'off' => t('Default off'),
'silent' => t('invisible Subscrition'),
);
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* @file
* Views fiter handler for simplenews_category.opt_inout.
*/
/**
* Provide translatable simplenews_category.opt_inout Options.
*/
class simplenews_handler_filter_category_opt_inout extends views_handler_filter_in_operator {
function get_value_options() {
$this->value_options = array(
'hidden' => t('Hidden'),
'single' => t('Single opt-in'),
'double' => t('Double opt-in'),
);
}
}

View File

@@ -0,0 +1,18 @@
<?php
/**
* @file
* Views filter handler for simplenews newsletter priorities
*/
/*
* Display simplenews newsletter priorities. See simplenews.admin.inc
* @row 1427 for definition of the simplenews_get_priority() function
*/
class simplenews_handler_filter_newsletter_priority extends views_handler_filter_in_operator {
function get_value_options() {
module_load_include('inc', 'simplenews', 'includes/simplenews.admin');
$this->value_options = simplenews_get_priority();
}
}

View File

@@ -0,0 +1,19 @@
<?php
/**
* @file
* Views filter for simplenews sent status.
*/
/**
* Filter based on newsletter sent status.
*/
class simplenews_handler_filter_newsletter_status extends views_handler_filter_in_operator {
function get_value_options() {
$this->value_options = array(
SIMPLENEWS_STATUS_SEND_NOT => t('Not sent'),
SIMPLENEWS_STATUS_SEND_PENDING => t('Pending'),
SIMPLENEWS_STATUS_SEND_READY => t('Sent'),
);
}
}

View File

@@ -0,0 +1,805 @@
<?php
/**
* @file
* Views interface for simplenews.
*/
/**
* Implements hook_views_data().
*/
function simplenews_views_data() {
/* ------------ Definitions for Simplenews mailspool ----------------------*/
$data['simplenews_mail_spool']['table'] = array(
'base' => array(
'field' => 'msid',
'title' => t('Simplenews mailspool'),
'help' => t('Spool for temporary storage of newsletter emails.'),
'weight' => 10,
'database' => 'default',
),
'group' => t('Simplenews spool'),
);
$data['simplenews_mail_spool']['msid'] = array(
'title' => t('Ms ID'),
'help' => t('The primary identifier for a mail spool record.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_mail_spool']['mail'] = array(
'title' => t('Subscriber'),
'help' => t('The formatted email address of mail message receipient.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_mail_spool']['nid'] = array(
'title' => t('Node ID'),
'help' => t('The {node}.nid of this newsletter.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'node',
'base field' => 'nid',
'label' => t('Node'),
),
);
$data['simplenews_mail_spool']['tid'] = array(
'title' => t('Term ID'),
'help' => t('The {term_data}.tid this newsletter issue belongs to.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'taxonomy_term_data',
'base field' => 'tid',
'label' => t('Issue'),
),
);
$data['simplenews_mail_spool']['snid'] = array(
'title' => t('Subscriber ID'),
'help' => t('The {simplenews_subscriber}.snid foreign key for this spool'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'simplenews_subscriber',
'base field' => 'snid',
'label' => t('Subscriber'),
),
);
$data['simplenews_mail_spool']['status'] = array(
'title' => t('Sent status'),
'help' => t('The sent status of the email (0 = hold, 1 = pending, 2 = done).'),
'field' => array(
'handler' => 'simplenews_handler_field_newsletter_status',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'simplenews_handler_filter_newsletter_status',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_mail_spool']['error'] = array(
'title' => t('Error'),
'help' => t('A boolean indicating whether an error occured while sending the email.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean_operator',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_mail_spool']['timestamp'] = array(
'title' => t('Timestamp'),
'help' => t('The time status was set or changed.'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_date',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_date',
),
'sort' => array(
'handler' => 'views_handler_sort_date',
),
);
$data['simplenews_mail_spool']['data'] = array(
'title' => t('Data'),
'help' => t('A serialized array of name value pairs that are related to the email address.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
/* ------------ Definitions for Simplenews issue ----------------------*/
$data['simplenews_newsletter']['table'] = array(
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
'group' => t('Simplenews issue'),
);
// Joins
$data['simplenews_newsletter']['table']['join'] = array(
'node' => array(
'left_field' => 'nid',
'field' => 'nid',
),
'taxonomy_term_data' => array(
'left_field' => 'tid',
'field' => 'tid',
),
);
$data['simplenews_newsletter']['tid'] = array(
'title' => t('Term ID'),
'help' => t('The {term_data}.tid (= newsletter series) this issue belongs to.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'taxonomy_term_data',
'base field' => 'tid',
'label' => t('Newsletter'),
),
);
$data['simplenews_newsletter']['status'] = array(
'title' => t('Sent status'), // The item it appears as on the UI,
'help' => t('Newsletter sent status: 0: Not sent, 1: Pending (being sent or waiting for cron to run), 2: Sent.'), // The help that appears on the UI,
'field' => array(
'handler' => 'simplenews_handler_field_newsletter_status',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'simplenews_handler_filter_newsletter_status',
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_newsletter']['sent_subscriber_count'] = array(
'title' => t('Subscriber count'),
'help' => t('The count of subscribers of the newsletter at the time it was sent.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_newsletter']['send'] = array(
'field' => array(
'title' => t('Send newsletter'),
'help' => t('Provides a link to send the simplenews newsletter if not sent yet.'),
'handler' => 'simplenews_handler_field_newsletter_send',
),
);
/* ------------ Definitions for Simplenews subscriber ----------------------*/
$data['simplenews_subscriber']['table'] = array(
'base' => array(
'field' => 'snid',
'title' => t('Simplenews subscriber'),
'help' => t('Contains subscribers of Simplenews Newsletters.'),
'weight' => 10,
'database' => 'default',
),
'group' => t('Simplenews subscriber'),
);
// Joins
$data['simplenews_subscriber']['table']['join'] = array(
'users' => array(
'left_field' => 'uid',
'field' => 'uid',
),
);
$data['simplenews_subscriber']['snid'] = array(
'title' => t('Subscriber ID'),
'help' => t('Primary key: Unique subsciber ID.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_subscriber']['activated'] = array(
'title' => t('Activated'),
'help' => t('Boolean indicating the status of the subscription.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_subscriber']['mail'] = array(
'title' => t('Subscriber'),
'help' => t('The subscription email address.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_subscriber']['uid'] = array(
'title' => t('User'),
'help' => t('The {users}.uid that has the same email address.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'users',
'base field' => 'uid',
'label' => t('user'),
),
);
$data['simplenews_subscriber']['language'] = array(
'title' => t('Language'),
'help' => t('Anonymous subscriber preferred language. Empty for authenticated users.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_subscriber']['timestamp'] = array(
'title' => t('Timestamp'),
'help' => t('UNIX timestamp of when the user first subscribed to a newsletter.'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_date',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_date',
),
'sort' => array(
'handler' => 'views_handler_sort_date',
),
);
/* ------------ Definitions for Simplenews subscription ----------------------*/
$data['simplenews_subscription']['table'] = array(
'base' => array(
'field' => 'snid',
'title' => t('Simplenews subscription'),
'help' => t('Contains all Subscriptions of every Simplenews Newsletters.'),
'weight' => 10,
'database' => 'default',
),
'group' => t('Simplenews subscription'),
);
$data['simplenews_subscription']['table']['join'] = array(
'taxonomy_term_data' => array(
'left_field' => 'tid',
'field' => 'tid',
),
'simplenews_subscriber' => array(
'left_field' => 'snid',
'field' => 'snid',
),
);
$data['simplenews_subscription']['snid'] = array(
'title' => t('Subscriber ID'),
'help' => t('The {simplenews_subscriptions}.snid who is subscribed.'),
'field' => array(
'label' => 'TEST',
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'simplenews_subscriber',
'base field' => 'snid',
'label' => t('Subscriber'),
),
);
$data['simplenews_subscription']['tid'] = array(
'title' => t('Term ID'),
'help' => t('The newsletter series ({term_data}.tid) the subscriber is subscribed to.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'taxonomy_term_data',
'base field' => 'tid',
'label' => t('Term (Newsletter series)'),
),
);
$data['simplenews_subscription']['status'] = array(
'title' => t('Status'),
'help' => t('A flag indicating whether the user is subscribed (1) or unsubscribed (0).'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean_operator',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_subscription']['timestamp'] = array(
'title' => t('Timestamp'),
'help' => t('UNIX timestamp of when the user is (un)subscribed.'),
'field' => array(
'handler' => 'views_handler_field_date',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_date',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_date',
),
'sort' => array(
'handler' => 'views_handler_sort_date',
),
);
$data['simplenews_subscription']['source'] = array(
'title' => t('Source'),
'help' => t('The source via which the user is (un)subscribed.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
/* ------------ Definitions for Simplenews category ----------------------*/
// Define the base group of this table. Fields that don't
// have a group defined will go into this field by default.
$data['simplenews_category']['table'] = array(
'group' => t('Simplenews category'),
);
// Joins
$data['simplenews_category']['table']['join'] = array(
// Category links directly to taxonomy via tid.
'taxonomy_term_data' => array(
'left_field' => 'tid',
'field' => 'tid',
),
);
// Fields
$data['simplenews_category']['tid'] = array(
'title' => t('Term ID'),
'help' => t('The newsletter series ({term_data}.tid) the subscriber is subscribed to.'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
'relationship' => array(
'handler' => 'views_handler_relationship',
'base' => 'taxonomy_term_data',
'base field' => 'tid',
'label' => t('Term (Newsletter series)'),
),
);
$data['simplenews_category']['format'] = array(
'title' => t('Format'),
'help' => t('Format of the newsletter (plain or html).'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['priority'] = array(
'title' => t('Priority'),
'help' => t('Email priority according to RFC 2156 and RFC 5231 (0 = none; 1 = highest; 2 = high; 3 = normal; 4 = low; 5 = lowest).'),
'field' => array(
'handler' => 'simplenews_handler_field_newsletter_priority',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'simplenews_handler_filter_newsletter_priority',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_newsletter']['receipt'] = array(
'title' => t('Receipt'),
'help' => t('Boolean indicating request for email receipt confirmation according to RFC 2822.'),
'field' => array(
'handler' => 'views_handler_field_boolean',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_boolean_operator',
'allow empty' => TRUE,
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['from_name'] = array(
'title' => t('From name'),
'help' => t('Sender name for newsletter emails.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['email_subject'] = array(
'title' => t('Email Subject'),
'help' => t('Subject of newsletter email. May contain tokens.'),
'field' => array(
'handler' => 'views_handler_field',
'click sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string',
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['from_address'] = array(
'title' => t('From address'),
'help' => t('Sender address for newsletter emails'),
'field' => array(
'handler' => 'views_handler_field',
'click_sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_string'
),
'argument' => array(
'handler' => 'views_handler_argument_srting',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['hyperlinks'] = array(
'title' => t('Hyperlinks displaymode'),
'help' => t('Flag indicating type of hyperlink conversion (1 = hyperlinks are in-line; 0 = hyperlinks are placed at email bottom).'),
'field' => array(
'handler' => 'simplenews_handler_field_category_hyperlinks',
'click_sortable' => TRUE,
),
'filter' => array(
'handler' => 'simplenews_handler_filter_category_hyperlinks'
),
'argument' => array(
'handler' => 'views_handler_argument_numeric'
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['new_account'] = array(
'title' => t('New account'),
'help' => t('How to treat subscription at account creation (none = None; on = Default on; off = Default off; silent = Invisible subscription).'),
'field' => array(
'handler' => 'simplenews_handler_field_category_new_account',
'click_sortable' => TRUE,
),
'filter' => array(
'handler' => 'simplenews_handler_filter_category_new_account'
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['opt_inout'] = array(
'title' => t('Confirmation displaymode'),
'help' => t('How to treat subscription confirmation (hidden = Newsletter is hidden from the user; single = Single opt-in; double = Double opt-in).'),
'field' => array(
'handler' => 'simplenews_handler_field_category_opt_inout',
'click_sortable' => TRUE,
),
'filter' => array(
'handler' => 'simplenews_handler_filter_category_opt_inout'
),
'argument' => array(
'handler' => 'views_handler_argument_string',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
$data['simplenews_category']['block'] = array(
'title' => t('Block'),
'help' => t('Indicates wether a subscription block is available for this category'),
'field' => array(
'handler' => 'views_handler_field_numeric',
'click_sortable' => TRUE,
),
'filter' => array(
'handler' => 'views_handler_filter_numeric',
),
'argument' => array(
'handler' => 'views_handler_argument_numeric',
),
'sort' => array(
'handler' => 'views_handler_sort',
),
);
return $data;
}

View File

@@ -0,0 +1,200 @@
<?php
/**
* @file
* Hooks provided by the Simplenews module.
*/
/**
* @mainpage Simplenews API documentation.
*
* Simplenews builds on the following basic concepts.
*
* @link subscriber Subscribers @endlink subscribe to @link newsletter
* newsletters (categories) @endlink. That connection is called
* a @link subscription subscription @endlink. Nodes of enabled content types
* are @link issue newsletter issues @endlink. These are then sent to the
* subscribers of the newsletter the issue is attached to.
*
* Sending is done by first adding a row for each subscriber to the @link spool
* mail spool @endlink.
* Then they are processed either immediatly or during cron runs. The actual
* sending happens through a @link source source instance @endlink, which is
* first instanciated based on the mail spool and then used to generated the
* actual mail content.
*
*/
/**
* @defgroup subscriber Subscriber
*
* @todo
*/
/**
* @defgroup newsletter Newsletter (category)
*
* @todo
*/
/**
* @defgroup subscription Subscription
*
* @todo
*/
/**
* @defgroup issue Newsletter issue
*
* @todo
*/
/**
* @defgroup spool Mail spool
*
* @todo
*/
/**
* @defgroup source Source
*
* @todo
*/
/**
* Return operations to be applied to newsletter issues.
*
* @ingroup issue
*/
function hook_simplenews_issue_operations() {
$operations = array(
'activate' => array(
'label' => t('Send'),
'callback' => 'simplenews_issue_send',
),
);
return $operations;
}
/**
* Return operations to be applied to subscriptions.
*
* @ingroup issue
*/
function hook_simplenews_subscription_operations() {
$operations = array(
'activate' => array(
'label' => t('Activate'),
'callback' => 'simplenews_subscription_activate',
'callback arguments' => array(SIMPLENEWS_SUBSCRIPTION_ACTIVE),
),
'inactivate' => array(
'label' => t('Inactivate'),
'callback' => 'simplenews_subscription_activate',
'callback arguments' => array(SIMPLENEWS_SUBSCRIPTION_INACTIVE),
),
'delete' => array(
'label' => t('Delete'),
'callback' => 'simplenews_subscription_delete_multiple',
),
);
return $operations;
}
/**
* Act after a newsletter category has been saved.
*
* @ingroup newsletter
*/
function hook_simplenews_category_update($category) {
}
/**
* Act after a newsletter category has been deleted.
*
* @ingroup newsletter
*/
function hook_simplenews_category_delete($category) {
}
/**
* Act after a subscriber is updated.
*
* @ingroup subscriber
*/
function hook_simplenews_subscriber_update($subscriber) {
}
/**
* Act after a new subscriber has been created.
*
* @ingroup subscriber
*/
function hook_simplenews_subscriber_insert($subscriber) {
}
/**
* Act after a subscriber has been deleted.
*
* @ingroup subscriber
*/
function hook_simplenews_subscriber_delete($subscriber) {
}
/**
* Invoked if a user is subscribed to a newsletter.
*
* @param $subscriber
* The subscriber object including all subscriptions of this user.
*
* @param $subscription
* The subscription object for this specific subscribe action.
*
* @ingroup subscriber
*/
function hook_simplenews_subscribe_user($subscriber, $subscription) {
}
/**
* Invoked if a user is unsubscribed from a newsletter.
*
* @param $subscriber
* The subscriber object including all subscriptions of this user.
*
* @param $subscription
* The subscription object for this specific unsubscribe action.
*
* @ingroup subscriber
*/
function hook_simplenews_unsubscribe_user($subscriber, $subscription) {
}
/**
* Expose SimplenewsSource cache implementations.
*
* @return
* An array keyed by the name of the class that provides the implementation,
* the array value consists of another array with the keys label and
* description.
*
* @ingroup source
*/
function hook_simplenews_source_cache_info() {
return array(
'SimplenewsSourceCacheNone' => array(
'label' => t('No caching'),
'description' => t('This allows to theme each newsletter separately.'),
),
'SimplenewsSourceCacheBuild' => array(
'label' => t('Cached content source'),
'description' => t('This caches the rendered content to be sent for multiple recipients. It is not possible to use subscriber specific theming but tokens can be used for personalization.'),
),
);
}

View File

@@ -0,0 +1,29 @@
#simplenews-admin-filter .form-item {
clear: both;
line-height: 1.75em;
margin: 0pt 1em 0pt 0pt;
}
#simplenews-admin-filter .form-item label {
float: left;
width: 12em;
}
#simplenews-admin-filter .spacer {
margin-left: 12em;
}
#simplenews-admin-filter .form-select,
#simplenews-admin-filter .form-text {
width: 14em;
}
.block-simplenews .issues-link,
.block-simplenews .issues-list {
margin-top: 1em;
}
.block-simplenews .issues-list .newsletter-created {
display: none;
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* Implements hook_drush_command().
*/
function simplenews_drush_command() {
$items = array();
$items['simplenews-spool-count'] = array(
'description' => 'Print the current simplenews mail spool count',
'aliases' => array('sn-sc'),
'drupal dependencies' => array('simplenews'),
'options' => array(
'pipe' => dt('Just print the count value to allow parsing'),
)
);
$items['simplenews-spool-send'] = array(
'description' => 'Send the defined amount of mail spool entries.',
'examples' => array(
'drush sn-ss' => dt('Send the default amount of mails, as defined by the simplenews_throttle variable.'),
'drush sn-ss 0' => dt('Send all mails.'),
'drush sn-ss 100' => dt('Send 100 mails'),
),
'options' => array(
'pipe' => dt('Just print the sent and remaining count on separate lines to allow parsing'),
),
'aliases' => array('sn-ss'),
'drupal dependencies' => array('simplenews'),
);
return $items;
}
/**
* Drush command to count the mail spool queue.
*/
function drush_simplenews_spool_count() {
module_load_include('inc', 'simplenews', 'includes/simplenews.mail');
$count = simplenews_count_spool();
$no_description = drush_get_option('pipe');
if ($no_description) {
drush_print_pipe($count);
}
else {
drush_log(dt('Current simplenews mail spool count: @count', array('@count' => $count)), 'status');
}
}
/**
* Drush command to send the mail spool queue.
*/
function drush_simplenews_spool_send($limit = FALSE) {
module_load_include('inc', 'simplenews', 'includes/simplenews.mail');
if ($limit === FALSE) {
$limit = variable_get('simplenews_throttle');
}
elseif ($limit == 0) {
$limit = SIMPLENEWS_UNLIMITED;
}
$start_time = microtime(TRUE);
$sent = simplenews_mail_spool($limit);
simplenews_clear_spool();
simplenews_send_status_update();
$durance = round(microtime(TRUE) - $start_time, 2);
// Report the number of sent mails.
if ($sent > 0) {
$remaining = simplenews_count_spool();
if (drush_get_option('pipe')) {
// For pipe, print the sent first and then the remaining count, separated by a space.
drush_print_pipe($sent . " " . $remaining);
}
else {
drush_log(dt('Sent @count mails from the queue in @sec seconds.', array('@count' => $sent, '@sec' => $durance)), 'status');
drush_log(dt('Remaining simplenews mail spool count: @count', array('@count' => $remaining)), 'status');
}
}
}

View File

@@ -0,0 +1,29 @@
name = Simplenews
description = Send newsletters to subscribed email addresses.
package = Mail
core = 7.x
configure = admin/config/services/simplenews
dependencies[] = taxonomy
test_dependencies[] = i18n_taxonomy
files[] = tests/simplenews.test
files[] = includes/simplenews.source.inc
files[] = includes/views/handlers/simplenews_handler_field_newsletter_status.inc
files[] = includes/views/handlers/simplenews_handler_field_newsletter_priority.inc
files[] = includes/views/handlers/simplenews_handler_field_category_hyperlinks.inc
files[] = includes/views/handlers/simplenews_handler_field_category_new_account.inc
files[] = includes/views/handlers/simplenews_handler_field_category_opt_inout.inc
files[] = includes/views/handlers/simplenews_handler_field_newsletter_send.inc
files[] = includes/views/handlers/simplenews_handler_filter_newsletter_status.inc
files[] = includes/views/handlers/simplenews_handler_filter_newsletter_priority.inc
files[] = includes/views/handlers/simplenews_handler_filter_category_hyperlinks.inc
files[] = includes/views/handlers/simplenews_handler_filter_category_new_account.inc
files[] = includes/views/handlers/simplenews_handler_filter_category_opt_inout.inc
; Information added by drupal.org packaging script on 2012-02-23
version = "7.x-1.0-beta2"
core = "7.x"
project = "simplenews"
datestamp = "1329988254"

View File

@@ -0,0 +1,750 @@
<?php
/**
* @file
* Install, update and uninstall functions for the simplenews module
*/
/**
* Implements hook_schema().
*/
function simplenews_schema() {
$schema['simplenews_category'] = array(
'description' => 'Simplenews newsletter categories.',
'fields' => array(
'tid' => array(
'description' => '{taxonomy_term_data}.tid used as newsletter category.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'format' => array(
'type' => 'varchar',
'length' => 8,
'not null' => TRUE,
'default' => '',
'description' => 'Format of the newsletter email (plain, html).',
),
'priority' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'Email priority according to RFC 2156 and RFC 5231 (0 = none; 1 = highest; 2 = high; 3 = normal; 4 = low; 5 = lowest).',
),
'receipt' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'Boolean indicating request for email receipt confirmation according to RFC 2822.',
),
'from_name' => array(
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
'description' => 'Sender name for newsletter emails.',
),
'email_subject' => array(
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Subject of newsletter email. May contain tokens.',
),
'from_address' => array(
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
'description' => 'Sender address for newsletter emails',
),
'hyperlinks' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
'description' => 'Flag indicating type of hyperlink conversion (1 = hyperlinks are in-line; 0 = hyperlinks are placed at email bottom).',
),
'new_account' => array(
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
'description' => 'How to treat subscription at account creation (none = None; on = Default on; off = Default off; silent = Invisible subscription).',
),
'opt_inout' => array(
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
'description' => 'How to treat subscription confirmation (hidden = Newsletter is hidden from the user; single = Single opt-in; double = Double opt-in).',
),
'block' => array(
'description' => 'For this category a subscription block is available.',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('tid'),
);
$schema['simplenews_newsletter'] = array(
'description' => 'Simplenews newsletter data.',
'fields' => array(
'nid' => array(
'description' => '{node} that is used as newsletter.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'tid' => array(
'description' => 'The newsletter category {simplenews_category}.tid this newsletter belongs to.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'status' => array(
'description' => 'sent status of the newsletter issue (0 = not sent; 1 = pending; 2 = sent, 3 = send on publish).',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
),
'sent_subscriber_count' => array(
'description' => 'The count of subscribers to the newsletter when it was sent.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('nid'),
'foreign keys' => array(
'nid' => array(
'table' => 'node',
'columns' => array('nid' => 'nid'),
),
),
);
$schema['simplenews_subscriber'] = array(
'description' => 'Subscribers to {simplenews_category}. Many-to-many relation via {simplenews_subscription}',
'fields' => array(
'snid' => array(
'description' => 'Primary key: Unique subscriber ID.',
'type' => 'serial',
'not null' => TRUE,
),
'activated' => array(
'description' => 'Boolean indicating the status of the subscription.',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
),
'mail' => array(
'description' => "The subscriber's email address.",
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'uid' => array(
'description' => 'The {users}.uid that has the same email address.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'language' => array(
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
'description' => 'Subscriber preferred language.',
),
'timestamp' => array(
'description' => 'UNIX timestamp of when the user is (un)subscribed.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'changes' => array(
'description' => 'Contains the requested subscription changes',
'type' => 'text',
'serialize' => TRUE,
),
),
'primary key' => array('snid'),
'indexes' => array(
'mail' => array('mail'),
'uid' => array('uid'),
),
'foreign keys' => array(
'uid' => array(
'table' => 'users',
'columns' => array('uid' => 'uid'),
),
),
);
$schema['simplenews_subscription'] = array(
'description' => 'Newsletter subscription data. Which subscriber is subscribed to which mailing list.',
'fields' => array(
'snid' => array(
'description' => 'The {simplenews_subscriber}.snid who is subscribed.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'tid' => array(
'description' => 'The category ({simplenews_category}.tid) the subscriber is subscribed to.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'status' => array(
'description' => 'A flag indicating whether the user is subscribed (1) or unsubscribed (0).',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 1,
),
'timestamp' => array(
'description' => 'UNIX timestamp of when the user is (un)subscribed.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'source' => array(
'description' => 'The source via which the user is (un)subscription.',
'type' => 'varchar',
'length' => 24,
'not null' => TRUE,
'default' => '',
),
),
'primary key' => array('snid', 'tid'),
'foreign keys' => array(
'snid' => array(
'table' => 'simplenews_subscriber',
'columns' => array('snid' => 'snid'),
),
'tid' => array(
'table' => 'simplenews_category',
'columns' => array('tid' => 'tid'),
)
),
// @todo add foreign keys to other tables too?
);
$schema['simplenews_mail_spool'] = array(
'description' => 'Spool for temporary storage of newsletter emails.',
'fields' => array(
'msid' => array(
'description' => 'The primary identifier for a mail spool record.',
'type' => 'serial',
'unsigned' => TRUE,
'not null' => TRUE,
),
'mail' => array(
'description' => 'The formatted email address of mail message recipient.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'nid' => array(
'description' => 'The {node}.nid of this newsletter.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'tid' => array(
'description' => 'The {simplenews_category}.tid this newsletter belongs to.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'status' => array(
'description' => 'The sent status of the email (0 = hold, 1 = pending, 2 = done).',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
),
'error' => array(
'description' => 'A boolean indicating whether an error occured while sending the email.',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
),
'timestamp' => array(
'description' => 'The time status was set or changed.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'data' => array(
'type' => 'text',
'not null' => FALSE,
'size' => 'big',
'serialize' => TRUE,
'description' => 'A serialized array of name value pairs that are related to the email address.',
),
'snid' => array(
'description' => 'Foreign key for subscriber table ({simplenews_subscriptions}.snid)',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('msid'),
'indexes' => array(
'tid' => array('tid'),
'status' => array('status'),
'snid_tid' => array('snid', 'tid'),
),
'foreign keys' => array(
'nid' => array(
'table' => 'node',
'columns' => array('nid' => 'nid'),
),
'tid' => array(
'table' => 'simplenews_category',
'columns' => array('tid'),
),
'snid_tid' => array(
'table' => 'simplenews_subscription',
'columns' => array(
'snid' => 'snid',
'tid' => 'tid',
),
),
),
);
return $schema;
}
/**
* Implements hook_install().
*/
function simplenews_install() {
_simplenews_init_simplenews_vocabulary();
_simplenews_init_simplenews_category();
// add nodetype with newsletter vocabulary
_simplenews_install_nodetype();
}
/**
* Implements hook_uninstall().
*/
function simplenews_uninstall() {
db_query("DELETE FROM {variable} WHERE name LIKE 'simplenews_%%'");
}
/**
* Create simplenews node type.
*/
function _simplenews_install_nodetype() {
// Create a newsletter type if needed.
$type = node_type_get_type('simplenews');
if (!$type) {
$type = node_type_set_defaults(array(
'type' => 'simplenews',
'name' => t('Simplenews newsletter'),
'base' => 'node_content',
'description' => t('A newsletter issue to be sent to subscribed email addresses.'),
'locked' => 0,
'custom' => 1,
'modified' => 1,
));
node_type_save($type);
node_add_body_field($type);
}
if (!field_info_instance('node', 'field_simplenews_term', $type->type)) {
simplenews_add_term_field($type);
}
variable_set('simplenews_content_type_' . $type->type, TRUE);
}
/**
* Create simplenews vocabulary and initial term.
*/
function _simplenews_init_simplenews_vocabulary() {
// Create the simplenews vocabulary. If it exists, set simplenews_vid variable.
$vocabularies = taxonomy_vocabulary_load_multiple(array(), array('machine_name' => 'newsletter'));
$vocabulary = reset($vocabularies);
if (!$vocabulary) {
$vocabulary = new stdClass();
$vocabulary->name = t('Newsletter');
$vocabulary->machine_name = 'newsletter';
$vocabulary->description = t('Simplenews newsletter categories.');
$vocabulary->weight = '0';
$vocabulary->hierarchy = '0';
$vocabulary->module = 'simplenews';
}
taxonomy_vocabulary_save($vocabulary);
variable_set('simplenews_vid', $vocabulary->vid);
// Create a newsletter taxonomy term if none exists.
$tree = taxonomy_get_tree($vocabulary->vid);
if (count($tree) == 0) {
$term = new stdClass();
$term->name = t('@site_name newsletter', array('@site_name' => variable_get('site_name', 'Drupal')));
$term->description = t('@site_name newsletter categories.', array('@site_name' => variable_get('site_name', 'Drupal')));
$term->vid = $vocabulary->vid;
taxonomy_term_save($term);
}
}
/**
* Create initial simplenews categories.
*/
function _simplenews_init_simplenews_category() {
if ($tree = taxonomy_get_tree(variable_get('simplenews_vid', ''))) {
$categories = simplenews_categories_load_multiple();
$first = TRUE;
foreach ($tree as $term) {
// Create a newsletter category for each newsletter taxonomy term.
if (!isset($categories[$term->tid])) {
$category = new stdClass();
$category->tid = $term->tid;
// @todo use a function for category default values
$category->from_name = variable_get('site_name', 'Drupal');
$category->email_subject ='[[simplenews-category:name]] [node:title]';
$category->from_address = variable_get('site_mail', ini_get('sendmail_from'));
$category->format = 'plain';
$category->priority = SIMPLENEWS_PRIORITY_NONE;
$category->receipt = 0;
$category->hyperlinks = 1;
$category->new_account = 'none';
$category->opt_inout = 'double';
$category->block = 0;
if ($first) {
$category->block = 1;
$first = FALSE;
}
simplenews_category_save($category);
}
}
}
}
/**
* Helper function to get all activated simplenews blocks
*
* @return Keyed array of simplenews blocks.
*/
function _simplenews_get_blocks() {
$query = db_select('block', 'b');
$result = $query
->fields('b', array('delta'))
->condition('b.status', 1)
->condition('b.module', 'simplenews')
->execute();
return $result->fetchAllAssoc('delta');
}
/**
* Implements hook_update_last_removed().
*/
function simplenews_update_last_removed() {
// Support upgrades from 6.x-1.x and 6.x-2.x.
return 6101;
}
/**
* Implements hook_update_dependencies().
*/
function simplenews_update_dependencies() {
// Make sure that the taxonomy upgrade is run first.
$dependencies['simplenews'][7000] = array(
'taxonomy' => 7010,
);
return $dependencies;
}
/**
* Helper function to convert tokens in variables to D7 format.
*/
function _simplenews_convert_tokens_in_variable($variables) {
if (!is_array($variables)) {
$variables = array($variables);
}
$old = array('[site-name]', '[user-mail]', '[site-url]/user', '[site-url]', '[simplenews-subscribe-url]', '[simplenews-unsubscribe-url]', '[simplenews-newsletter-url]', '[simplenews-newsletters-name]', '[simplenews-newsletters-url]', '[simplenews-receiver-mail]');
$new = array('[site:name]', '[user:mail]', '[site:login-url]', '[site:url]', '[simplenews-subscriber:subscribe-url]', '[simplenews-subscriber:unsubscribe-url]', '[simplenews-newsletter:url]', '[simplenews-list:name]', '[simplenews-list:url]', '[simplenews-subscriber:mail]');
foreach ($variables as $variable) {
if ($text = variable_get($variable, FALSE)) {
$text = str_replace($old, $new, $text);
variable_set($variable, $text);
}
}
}
/**
* Create table {simplenews_category} to replace taxonomy terms.
* Migrate Newsletter taxonomy data to Newsletter categories.
*
* Rename table simplenews_subscriptions to simplenews_subscriber.
* Rename table simplenews_newsletters to simplenews_newsletter.
* Drop fields {simplenews_newsletter}.s_format, .priority and .receipt.
*
* Rename table simplenews_snid_tid to simplenews_subscription.
*
* Delete deprecated simplenews variables.
*/
function simplenews_update_7000() {
// Convert tokens in variables to D7 format.
$variables = array('simplenews_confirm_subscribe_subject', 'simplenews_confirm_subscribe_unsubscribed', 'simplenews_confirm_subscribe_subscribed', 'simplenews_confirm_unsubscribe_subscribed', 'simplenews_confirm_unsubscribe_unsubscribed');
_simplenews_convert_tokens_in_variable($variables);
// Create table 'simplenews_category'.
$schema['simplenews_category'] = array(
'description' => 'Simplenews newsletter categories.',
'fields' => array(
'tid' => array(
'description' => '{taxonomy_term_data}.tid used as newsletter category.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
),
'format' => array(
'description' => 'Format of the newsletter email (plain, html).',
'type' => 'varchar',
'length' => 8,
'not null' => TRUE,
'default' => '',
),
'priority' => array(
'description' => 'Email priority according to RFC 2156 and RFC 5231 (0 = none; 1 = highest; 2 = high; 3 = normal; 4 = low; 5 = lowest).',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
),
'receipt' => array(
'description' => 'Boolean indicating request for email receipt confirmation according to RFC 2822.',
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
),
'from_name' => array(
'description' => 'Sender name for newsletter emails.',
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'email_subject' => array(
'description' => 'Subject of newsletter email. May contain tokens.',
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
),
'from_address' => array(
'description' => 'Sender address for newsletter emails',
'type' => 'varchar',
'length' => 64,
'not null' => TRUE,
'default' => '',
),
'hyperlinks' => array(
'description' => 'Flag indicating type of hyperlink conversion (1 = hyperlinks are in-line; 0 = hyperlinks are placed at email bottom).',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
),
'new_account' => array(
'description' => 'How to treat subscription at account creation (none = None; on = Default on; off = Default off; silent = Invisible subscription).',
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
),
'opt_inout' => array(
'description' => 'How to treat subscription confirmation (hidden = Newsletter is hidden from the user; single = Single opt-in; double = Double opt-in).',
'type' => 'varchar',
'length' => 12,
'not null' => TRUE,
'default' => '',
),
'block' => array(
'description' => 'For this category a subscription block is available.',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
),
),
'primary key' => array('tid'),
);
db_create_table('simplenews_category', $schema['simplenews_category']);
// Migrate Newsletter taxonomy data to Newsletter categories.
// Query the database directly, to avoid triggering our own hooks.
$tids = db_query('SELECT tid FROM {taxonomy_term_data} where vid = :vid', array(':vid' => variable_get('simplenews_vid', '')))->fetchCol();
// @todo Check if simplenews blocks are still active after core update.
// If not, there is no purpose in migrating the block status ('block' => 0).
$blocks = _simplenews_get_blocks();
foreach ($tids as $tid) {
_simplenews_convert_tokens_in_variable('simplenews_email_subject_' . $tid);
db_insert('simplenews_category')
->fields(array(
'tid' => $tid,
'format' => 'plain',
'priority' => '0',
'receipt' => '0',
'from_name' => variable_get('simplenews_from_name_' . $tid, variable_get('simplenews_from_name', variable_get('site_name', 'Drupal'))),
'email_subject' => variable_get('simplenews_email_subject_' . $tid, '[[simplenews-newsletters-name]] [title-raw]'),
'from_address' => variable_get('simplenews_from_address_' . $tid, variable_get('simplenews_from_address', variable_get('site_mail', ini_get('sendmail_from')))),
'hyperlinks' => variable_get('simplenews_hyperlinks_' . $tid, 1),
'new_account' => variable_get('simplenews_new_account_' . $tid, 'none'),
'opt_inout' => variable_get('simplenews_opt_inout_' . $tid, 'double'),
'block' => isset($blocks[$tid]) ? 1 : 0,
))
->execute();
}
// Change table simplenews_subscriptions to simplenews_subscriber.
db_rename_table('simplenews_subscriptions', 'simplenews_subscriber');
// Change table simplenews_newsletters to simplenews_newsletter.
// Drop fields: s_format, priority, receipt (moved to simplenews_category).
db_rename_table('simplenews_newsletters', 'simplenews_newsletter');
db_change_field('simplenews_newsletter', 'tid', 'tid', array(
'description' => 'The newsletter category {simplenews_category}.tid this newsletter belongs to.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
));
db_drop_field('simplenews_newsletter', 's_format');
db_drop_field('simplenews_newsletter', 'priority');
db_drop_field('simplenews_newsletter', 'receipt');
// Change table simplenews_snid_tid to simplenews_subscription.
// Change field {simplenews_subscription}.tid description
db_drop_primary_key('simplenews_snid_tid');
db_rename_table('simplenews_snid_tid', 'simplenews_subscription');
// Add {simplenews_mail_spool}.data to store subscriber data.
db_add_field('simplenews_mail_spool', 'data', array(
'type' => 'text',
'not null' => FALSE,
'size' => 'big',
'serialize' => TRUE,
'description' => 'A serialized array of name value pairs that are related to the email address.',
));
// Rename field {simplenews_mail_spool}.s_status to "status".
db_change_field('simplenews_newsletter', 's_status', 'status', array(
'description' => 'sent status of the newsletter issue (0 = not sent; 1 = pending; 2 = sent). ',
'type' => 'int',
'size' => 'tiny',
'not null' => TRUE,
'default' => 0,
));
// Delete deprecated variables.
foreach ($tids as $tid) {
variable_del('simplenews_from_name_' . $tid);
variable_del('simplenews_email_subject_' . $tid);
variable_del('simplenews_from_address_' . $tid);
variable_del('simplenews_hyperlinks_' . $tid);
variable_del('simplenews_new_account_' . $tid);
variable_del('simplenews_opt_inout_' . $tid);
}
// @todo Add return text about checking of Newsletter Category settings.
// @todo Add return text about Block checkboxes
}
/**
* Create key snid_tid on simplenews_mail_spool table.
*/
function simplenews_update_7001() {
// Add the {simplenews_mail_spool}.snid field if it doesn't exist yet (added
// in 6.x-2.x).
if (!db_field_exists('simplenews_mail_spool', 'snid')) {
db_add_field('simplenews_mail_spool', 'snid', array(
'description' => 'Foreign key for subscriber table ({simplenews_subscriptions}.snid)',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
));
}
if (!db_index_exists('simplenews_mail_spool', 'snid_tid')) {
db_add_index('simplenews_mail_spool', 'snid_tid', array('snid', 'tid'));
}
}
/**
* Drop support for node revisioning.
*/
function simplenews_update_7002() {
if (db_field_exists('simplenews_newsletter', 'vid')) {
db_drop_field('simplenews_newsletter', 'vid');
}
if (db_field_exists('simplenews_mail_spool', 'vid')) {
db_drop_field('simplenews_mail_spool', 'vid');
}
}
/**
* [simplenews-newsletter] tokens have been removed in favor of [node] tokens.
*/
function simplenews_update_7003() {
drupal_set_message(t('The [simplenews-newsletter] tokens have been removed in favor of [node] tokens. Existing newsletters might need to be updated accordingly.'), 'warning');
}
/**
* Add the status field to {simplenews_subscription}.
*/
function simplenews_update_7004() {
if (!db_field_exists('simplenews_subscription', 'status')) {
db_add_field('simplenews_subscription', 'status', array(
'description' => 'A flag indicating whether the user is subscribed (1) or unsubscribed (0).',
'type' => 'int',
'size' => 'small',
'not null' => TRUE,
'default' => 1
)
);
}
}
/**
* Add support for combined confirmation mails.
*/
function simplenews_update_7005() {
db_add_field('simplenews_subscriber', 'changes', array(
'description' => 'Contains the requested subscription changes',
'type' => 'text',
'serialize' => TRUE,
));
// To keep existing installations consistent, disable combined confirmation
// mails.
variable_set('simplenews_use_combined', 'never');
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
name = Simplenews rules
description = Provides integration with Rules module for Simplenews.
dependencies[] = simplenews
dependencies[] = rules
package = Mail
core = 7.x
; Information added by drupal.org packaging script on 2012-02-23
version = "7.x-1.0-beta2"
core = "7.x"
project = "simplenews"
datestamp = "1329988254"

View File

@@ -0,0 +1,44 @@
<?php
/**
* @file
* Module file for Simpelnews rules integration.
*/
define('SIMPLENEWS_RULES_CONFIRMATION_DEFAULT', 0);
define('SIMPLENEWS_RULES_CONFIRMATION_YES', 1);
define('SIMPLENEWS_RULES_CONFIRMATION_NO', 2);
/**
* Returns the options for the confirmation paramter.
*/
function simplenews_rules_confirmation_list() {
return array(
SIMPLENEWS_RULES_CONFIRMATION_DEFAULT => t('Default'),
SIMPLENEWS_RULES_CONFIRMATION_YES => t('Yes'),
SIMPLENEWS_RULES_CONFIRMATION_NO => t('No'),
);
}
/**
* Implements hook_simplenews_unsubscribe_user().
*/
function simplenews_rules_simplenews_unsubscribe_user($subscriber, $subscription) {
$args = array(
'mail' => $subscriber->mail,
'tid' => $subscription->tid,
);
rules_invoke_event_by_args('simplenews_rules_event_unsubscribe', $args);
}
/**
* Implements hook_simplenews_unsubscribe_user().
*/
function simplenews_rules_simplenews_subscribe_user($subscriber, $subscription) {
$args = array(
'mail' => $subscriber->mail,
'tid' => $subscription->tid,
);
rules_invoke_event_by_args('simplenews_rules_event_subscribe', $args);
}

View File

@@ -0,0 +1,218 @@
<?php
/**
* @file
* Rules hooks for the Simplenews newsletter module.
*
* @addtogroup rules
* @{
*/
/**
* Implements hook_rules_action_info().
*/
function simplenews_rules_rules_action_info() {
return array(
'simplenews_rules_action_send' => array(
'label' => t('Send newsletter'),
'group' => t('Simplenews'),
'parameter' => array(
'node' => array(
'type' => 'node',
'label' => t('The newsletter node to be sent.'),
'description' => t('The newsletter node that should be sent.'),
)
)
),
'simplenews_rules_action_subscribe' => array(
'label' => t('Subscribe an e-mail adress to a newsletter'),
'group' => t('Simplenews'),
'named parameter' => TRUE,
'parameter' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that should be subscribed.'),
),
'tid' => array(
'type' => 'integer',
'label' => t('Simplenews category'),
'descrption' => t('For which newsletter category the subscription should happen.'),
'options list' => 'simplenews_category_list',
),
'confirmation' => array(
'type' => 'integer',
'label' => t('Confirmation required'),
'description' => t('Select if a confirmation is required. Default uses the default setting from the chosen newsletter category.'),
'options list' => 'simplenews_rules_confirmation_list',
'default value' => SIMPLENEWS_RULES_CONFIRMATION_DEFAULT,
),
'source' => array(
'type' => 'string',
'label' => t('Source'),
'description' => t('A string to identify the source of this subscription'),
'optional' => TRUE,
),
'source' => array(
'type' => 'text',
'label' => t('Source'),
'description' => t('A string to identify the source of this subscription'),
'optional' => TRUE,
'default value' => 'rules',
),
'language' => array(
'type' => 'token',
'label' => t('Language'),
'description' => t('If specified, the language to use for the subscription. Defaults to the default language.'),
'options list' => 'entity_metadata_language_list',
'optional' => TRUE,
'default value' => LANGUAGE_NONE,
),
),
),
'simplenews_rules_action_unsubscribe' => array(
'label' => t('Unsubscribe an e-mail adress from a newsletter'),
'group' => t('Simplenews'), 'named parameter' => TRUE,
'parameter' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that should be unsubscribed.'),
),
'tid' => array(
'type' => 'integer',
'label' => t('Simplenews category'),
'descrption' => t('For which newsletter category the unsubscription should happen.'),
'options list' => 'simplenews_category_list',
),
'confirmation' => array(
'type' => 'integer',
'label' => t('Confirmation required'),
'description' => t('Select if a confirmation is required. Default uses the default setting from the chosen newsletter category.'),
'options list' => 'simplenews_rules_confirmation_list',
'default value' => SIMPLENEWS_RULES_CONFIRMATION_DEFAULT,
),
'source' => array(
'type' => 'text',
'label' => t('Source'),
'description' => t('A string to identify the source of this subscription'),
'optional' => TRUE,
'default value' => 'rules',
),
'language' => array(
'type' => 'token',
'label' => t('Language'),
'description' => t('If specified, the language to use for the subscription. Defaults to the default language.'),
'options list' => 'entity_metadata_language_list',
'optional' => TRUE,
'default value' => LANGUAGE_NONE,
),
),
),
);
}
/**
* Implements hook_event_info().
*/
function simplenews_rules_rules_event_info() {
return array(
'simplenews_rules_event_subscribe' => array(
'label' => t('A user has been subscribed'),
'group' => t('Simplenews'),
'variables' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-Mail'),
'description' => t('The e-mail address that has been subscribed.'),
),
'tid' => array(
'type' => 'integer',
'label' => t('Simplenews category'),
'descrption' => t('The newsletter category of the subscription.'),
'options list' => 'simplenews_category_list',
),
),
),
'simplenews_rules_event_unsubscribe' => array(
'label' => t('A user has been unsubscribed'),
'group' => t('Simplenews'),
'variables' => array(
'mail' => array(
'type' => 'text',
'label' => t('E-mail'),
'description' => t('The e-mail address that has been subscribed.'),
),
'tid' => array(
'type' => 'integer',
'label' => t('Simplenews category'),
'descrption' => t('The newsletter category of the subscription.'),
'options list' => 'simplenews_category_list',
),
),
),
);
}
/**
* Action implementation, send a newsletter node.
*/
function simplenews_rules_action_send($node) {
$newsletter = simplenews_newsletter_load($node->nid);
if ($newsletter && ($newsletter->status != SIMPLENEWS_STATUS_SEND_PENDING || $newsletter->status != SIMPLENEWS_STATUS_SEND_PENDING)) {
module_load_include('inc', 'simplenews', 'includes/simplenews.mail');
simplenews_add_node_to_spool($node);
}
}
/**
* Action Implementation: Subscribe an e-mail adress to a Simplenews newsletter.
*/
function simplenews_rules_action_subscribe($args, $settings) {
if ($args['language'] == LANGUAGE_NONE) {
$args['language'] = NULL;
}
$confirmation = simplenews_rules_map_confirmation($args);
// Pass the call forward.
simplenews_subscribe_user($args['mail'], $args['tid'], $confirmation, $args['source'], $args['language']);
}
/**
* Action Implementation: Unsubscribe an e-mail adress to a Simplenews newsletter.
*/
function simplenews_rules_action_unsubscribe($args, $settings) {
if ($args['language'] == LANGUAGE_NONE) {
$args['language'] = NULL;
}
$confirmation = simplenews_rules_map_confirmation($args);
// Pass the call forward.
simplenews_unsubscribe_user($args['mail'], $args['tid'], $confirmation, $args['source'], $args['language']);
}
/**
* Map args to the confrmation argument for subscribing/unsubscribing.
*/
function simplenews_rules_map_confirmation($args) {
switch ($args['confirmation']) {
case SIMPLENEWS_RULES_CONFIRMATION_YES:
$confirmation = TRUE;
break;
case SIMPLENEWS_RULES_CONFIRMATION_NO:
$confirmation = FALSE;
break;
case SIMPLENEWS_RULES_CONFIRMATION_DEFAULT:
$account = simplenews_load_user_by_mail($args['mail']);
$confirmation = simplenews_require_double_opt_in($args['tid'], $account);
break;
}
return $confirmation;
}
/**
* @}
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 579 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,54 @@
<?php
/**
* @file
* Default theme implementation to display the simplenews block.
*
* Copy this file in your theme directory to create a custom themed block.
* Rename it to simplenews-block--<tid>.tpl.php to override it for a
* newsletter using the newsletter term's id.
*
* Available variables:
* - $subscribed: the current user is subscribed to the $tid newsletter
* - $user: the current user is authenticated
* - $tid: tid of the newsletter
* - $message: announcement message (Default: 'Stay informed on our latest news!')
* - $form: newsletter subscription form *1
* - $subscription_link: link to subscription form at 'newsletter/subscriptions' *1
* - $newsletter_link: link to taxonomy list of the newsletter issue *2
* - $issue_list: list of newsletter issues (of the $tid newsletter series) *2
* - $rssfeed: RSS feed of newsletter (series) *2
* Note 1: requires 'subscribe to newsletters' permission
* Note 2: requires 'view links in block' or 'administer newsletters' permission
*
* Simplenews module controls the display of the block content. The following
* variables are available for this purpose:
* - $use_form : TRUE = display the form; FALSE = display link to example.com/newsletter/subscriptions
* - $use_issue_link : TRUE = display link to newsletter issue list
* - $use_issue_list : TRUE = display list of the newsletter issue
* - $use_rss : TRUE = display RSS feed
*
* @see template_preprocess_simplenews_block()
*/
?>
<?php if ($message): ?>
<p><?php print $message; ?></p>
<?php endif; ?>
<?php if ($use_form): ?>
<?php print render($form); ?>
<?php elseif ($subscription_link): ?>
<p><?php print $subscription_link; ?></p>
<?php endif; ?>
<?php if ($use_issue_link && $newsletter_link): ?>
<div class="issues-link"><?php print $newsletter_link; ?></div>
<?php endif; ?>
<?php if ($use_issue_list && $issue_list): ?>
<div class="issues-list"><?php print $issue_list; ?></div>
<?php endif; ?>
<?php if ($use_rss): ?>
<?php print $rssfeed; ?>
<?php endif; ?>

View File

@@ -0,0 +1,24 @@
<?php
// $Id: simplenews-multi-block.tpl.php,v 1.6 2009/01/02 12:01:17 sutharsan Exp $
/**
* @file
* Default theme implementation to display the simplenews block.
*
* Copy this file in your theme directory to create a custom themed block.
*
* Available variables:
* - $subscribed: the current user is subscribed to the $tid newsletter
* - $user: the current user is authenticated
* - $message: announcement message (Default: 'Stay informed on our latest news!')
* - $form: newsletter subscription form
*
* @see template_preprocess_simplenews_multi_block()
*/
?>
<?php if ($message): ?>
<p><?php print $message; ?></p>
<?php endif; ?>
<?php print render($form); ?>

View File

@@ -0,0 +1,31 @@
<?php
/**
* @file
* Default theme implementation to format the simplenews newsletter body.
*
* Copy this file in your theme directory to create a custom themed body.
* Rename it to override it. Available templates:
* simplenews-newsletter-body--[tid].tpl.php
* simplenews-newsletter-body--[view mode].tpl.php
* simplenews-newsletter-body--[tid]--[view mode].tpl.php
* See README.txt for more details.
*
* Available variables:
* - $build: Array as expected by render()
* - $build['#node']: The $node object
* - $title: Node title
* - $language: Language code
* - $view_mode: Active view mode
* - $simplenews_theme: Contains the path to the configured mail theme.
* - $simplenews_subscriber: The subscriber for which the newsletter is built.
* Note that depending on the used caching strategy, the generated body might
* be used for multiple subscribers. If you created personalized newsletters
* and can't use tokens for that, make sure to disable caching or write a
* custom caching strategy implemention.
*
* @see template_preprocess_simplenews_newsletter_body()
*/
?>
<h2><?php print $title; ?></h2>
<?php print render($build); ?>

View File

@@ -0,0 +1,41 @@
<?php
/**
* @file
* Default theme implementation to format the simplenews newsletter footer.
*
* Copy this file in your theme directory to create a custom themed footer.
* Rename it to simplenews-newsletter-footer--[tid].tpl.php to override it for a
* newsletter using the newsletter term's id.
*
* @todo Update the available variables.
* Available variables:
* - $build: Array as expected by render()
* - $build['#node']: The $node object
* - $language: language code
* - $key: email key [node|test]
* - $format: newsletter format [plain|html]
* - $unsubscribe_text: unsubscribe text
* - $test_message: test message warning message
* - $simplenews_theme: path to the configured simplenews theme
*
* Available tokens:
* - [simplenews-subscriber:unsubscribe-url]: unsubscribe url to be used as link
*
* Other available tokens can be found on the node edit form when token.module
* is installed.
*
* @see template_preprocess_simplenews_newsletter_footer()
*/
?>
<?php if (!$opt_out_hidden): ?>
<?php if ($format == 'html'): ?>
<p class="newsletter-footer"><a href="[simplenews-subscriber:unsubscribe-url]"><?php print $unsubscribe_text ?></a></p>
<?php else: ?>
-- <?php print $unsubscribe_text ?>: [simplenews-subscriber:unsubscribe-url]
<?php endif ?>
<?php endif; ?>
<?php if ($key == 'test'): ?>
- - - <?php print $test_message ?> - - -
<?php endif ?>