Version: current

      1 <?php
      2
      3 /**
      4  * Newsletter administration section
      5  *
      6  * @package newsletter
      7  */
      8 class NewsletterAdmin extends LeftAndMain {
      9
     10     static $subitem_class = 'Member';
     11     static $most_recent_seperator = 5; // an int which will be used to seperator "send items" into 2 groups, e.g. "most recent number 5", "older".
     12     static $template_path = null; // deprecated, use template_paths instead.
     13     static $template_paths = null; //could be customised in _config
     14     static $allowed_actions = array(
     15         'adddraft',
     16         'addgroup',
     17         'addtype',
     18         'autocomplete',
     19         'displayfilefield',
     20         'exportrecipients',
     21         'getformcontent',
     22         'getsentstatusreport',
     23         'getsitetree',
     24         'memberblacklisttoggle',
     25         'newmember',
     26         'preview',
     27         'remove',
     28         'removebouncedmember',
     29         'removenewsletter',
     30         'save',
     31         'savemember',
     32         'savenewsletter',
     33         'sendnewsletter',
     34         'showdrafts',
     35         'showmailtype',
     36         'shownewsletter',
     37         'showrecipients',
     38         'showsent',
     39         'MailingListEditForm',
     40         'TypeEditForm',
     41         'UploadForm',
     42         'NewsletterEditForm',
     43     );
     44     static $url_segment = 'newsletter';
     45     static $url_rule = '/$Action/$ID/$OtherID';
     46     static $menu_title = 'Newsletter';
     47     protected static $makeSendNewslettersReadonly = true;
     48
     49     static function setSendNewslettersReadonly($val = true) {
     50         self::$makeSendNewslettersReadonly = $val;
     51     }
     52
     53     public function init() {
     54         parent::init();
     55
     56         Requirements::javascript(MCE_ROOT . 'tiny_mce_src.js');
     57         Requirements::javascript(THIRDPARTY_DIR . '/tiny_mce_improvements.js');
     58
     59         Requirements::javascript(THIRDPARTY_DIR . '/hover.js');
     60         Requirements::javascript(THIRDPARTY_DIR . '/scriptaculous/controls.js');
     61
     62         Requirements::javascript(CMS_DIR . '/javascript/SecurityAdmin.js');
     63
     64         Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain_left.js');
     65         Requirements::javascript(CMS_DIR . '/javascript/LeftAndMain_right.js');
     66         Requirements::javascript(CMS_DIR . '/javascript/CMSMain_left.js');
     67
     68         Requirements::javascript('newsletter/javascript/NewsletterAdmin_left.js');
     69         Requirements::javascript('newsletter/javascript/NewsletterAdmin_right.js');
     70         Requirements::javascript('newsletter/javascript/ProgressBar.js');
     71
     72         // We don't want this showing up in every ajax-response, it should always be present in a CMS-environment
     73         if (!Director::is_ajax()) {
     74             Requirements::javascript(MCE_ROOT . 'tiny_mce_src.js');
     75             HtmlEditorConfig::get('cms')->setOption('ContentCSS', project() . '/css/editor.css');
     76             HtmlEditorConfig::get('cms')->setOption('Lang', i18n::get_tinymce_lang());
     77         }
     78
     79         // Always block the HtmlEditorField.js otherwise it will be sent with an ajax request
     80         Requirements::block(SAPPHIRE_DIR . '/javascript/HtmlEditorField.js');
     81
     82         Requirements::css('newsletter/css/NewsletterAdmin.css');
     83     }
     84
     85     public function remove() {
     86         $ids = explode(',', $_REQUEST['csvIDs']);
     87
     88         $count = 0;
     89         foreach ($ids as $id) {
     90             if (preg_match('/^mailtype_(\d+)$/', $id, $matches))
     91                 $record = DataObject::get_by_id('NewsletterType', $matches[1]);
     92             else if (preg_match('/^[a-z]+_\d+_(\d+)$/', $id, $matches))
     93                 $record = DataObject::get_by_id('Newsletter', $matches[1]);
     94
     95             if ($record) {
     96                 $record->delete();
     97             }
     98
     99             FormResponse::add("removeTreeNodeByIdx(\$('sitetree'), '$id' );");
    100             // Don't allow a deleted draft to be edited
    101             FormResponse::add("$('Form_EditForm').closeIfSetTo('$matches[1]');");
    102             $count++;
    103         }
    104
    105         FormResponse::status_message('Deleted ' . $count . ' items', 'good');
    106
    107         return FormResponse::respond();
    108     }
    109
    110     // убираем из названия сессии для сохранения текущей страницы {$this->class}.  т.к. по всему модулю используется просто currentPage
    111     public function currentPageID() {
    112         if(isset($_REQUEST['ID']) && is_numeric($_REQUEST['ID']))   {
    113             return $_REQUEST['ID'];
    114         } elseif (isset($this->urlParams['ID']) && is_numeric($this->urlParams['ID'])) {
    115             return $this->urlParams['ID'];
    116         } elseif(Session::get("currentPage")) {
    117             return Session::get("currentPage");
    118         } else {
    119             return null;
    120         }
    121     }
    122
    123     public function getformcontent() {
    124         Session::set('currentPage', $_REQUEST['ID']);
    125         Session::set('currentType', $_REQUEST['type']);
    126
    127         if ($_REQUEST['otherID']) {
    128             Session::set('currentOtherID', $_REQUEST['otherID']);
    129         }
    130
    131         SSViewer::setOption('rewriteHashlinks', false);
    132
    133         $result = $this->renderWith($this->class . '_right');
    134
    135         return $this->getLastFormIn($result);
    136     }
    137
    138     /**
    139      * Top level call from ajax
    140      * Called when a mailing list is clicked on the left menu
    141      */
    142     public function showrecipients($params) {
    143         $params = $params->allParams();
    144         return $this->showWithEditForm($params, $this->getMailingListEditForm($params['ID']));
    145     }
    146
    147     /**
    148      * Top level call from ajax when click on the left manu
    149      * Second level call when create a draft
    150      * Called when a draft or sent newsletter is clicked on the left menu and when a new one is added
    151      */
    152     public function shownewsletter($params) {
    153         if ($params instanceof SS_HTTPRequest) {
    154             $params = $params->allParams();
    155         }
    156         if (is_numeric($params['ID'])) {
    157             return $this->showWithEditForm($params, $this->getNewsletterEditForm($params['ID']));
    158         }
    159         return null;
    160     }
    161
    162     /**
    163      * Preview a {@link Newsletter} draft.
    164      *
    165      * @param HTTPRequest $request Request parameters
    166      */
    167     public function preview($request) {
    168         $newsletterID = (int) $request->param('ID');
    169         $obj = DataObject::get_by_id('Newsletter', $newsletterID);
    170         $templateName = ($obj && ($obj->Parent()->Template)) ? $obj->Parent()->Template : 'GenericEmail';
    171
    172         // Block stylesheets and JS that are not required (email templates should have inline CSS/JS)
    173         Requirements::clear();
    174
    175         // Set template specific variables before passing it to the template
    176         $obj->Body = $obj->Content;
    177         $obj->NewsLetterData = $obj;
    178
    179         return $this->customise($obj)->renderWith($templateName);
    180     }
    181
    182     /**
    183      * Top level call from ajax
    184      * Called when a newsletter type is clicked on the left menu
    185      */
    186     public function showmailtype($params) {
    187         $params = $params->allParams();
    188         return $this->showWithEditForm($params, $this->getNewsletterTypeEditForm($params['ID']));
    189     }
    190
    191     /**
    192      * Top level call from ajax
    193      * Called when a 'Drafts' folder is clicked on the left menu
    194      */
    195     public function showdrafts($params) {
    196         $params = $params->allParams();
    197         return $this->ShowNewsletterFolder($params, 'Draft');
    198     }
    199
    200     /**
    201      * Top level call from ajax
    202      * Called when a 'Sent Items' folder is clicked on the left menu
    203      */
    204     public function showsent($params) {
    205         $params = $params->allParams();
    206         return $this->ShowNewsletterFolder($params, 'Sent');
    207     }
    208
    209     /**
    210      * Shows either the 'Sent' or 'Drafts' folder using the NewsletterList template
    211      * Didn't see anywhere it is called from top level ajax call or from templete,
    212      * it is only called internally from showdrafts and showsent.
    213      */
    214     public function ShowNewsletterFolder($params, $type) {
    215         $id = $params['ID'];
    216         if (!is_numeric($id)) {
    217             $id = Session::get('currentPage');
    218         }
    219         if (is_a($id, 'NewsletterType')) {
    220             $mailType = $id;
    221             $id = $mailType->ID;
    222         } else {
    223             if ($id && is_numeric($id)) {
    224                 $mailType = DataObject::get_by_id('NewsletterType', $id);
    225             }
    226         }
    227         $draftList = new NewsletterList($type, $mailType, $type);
    228         return $draftList->renderWith("NewsletterList");
    229     }
    230
    231     /**
    232      * This function is called only internally, so make sure that $params is not a HTTPRequest from caller.
    233      */
    234     private function showWithEditForm($params, $editForm) {
    235         if (isset($params['ID'])) {
    236             Session::set("currentPage", $params['ID']);
    237         }
    238         if (isset($params['OtherID'])) {
    239             Session::set('currentMember', $params['OtherID']);
    240         }
    241         if (Director::is_ajax()) {
    242             SSViewer::setOption('rewriteHashlinks', false);
    243             return $editForm->formHtmlContent();
    244         } else {
    245             return array();
    246         }
    247     }
    248
    249     public function getEditForm($id) {
    250         $form = $this->getNewsletterTypeEditForm($id);
    251         $form->disableDefaultAction();
    252         return $form;
    253     }
    254
    255     /**
    256      * Get the EditForm
    257      */
    258     public function EditForm() {
    259         // Include JavaScript to ensure HtmlEditorField works.
    260         HtmlEditorField::include_js();
    261
    262         if ((isset($_REQUEST['ID']) && isset($_REQUEST['Type']) && $_REQUEST['Type'] == 'Newsletter') || isset($_REQUEST['action_savenewsletter'])) {
    263             $form = $this->NewsletterEditForm();
    264         } else {
    265
    266             // If a mailing list member is being added to a group, then call the Recipient form
    267             if ((isset($_REQUEST['fieldName']) && 'Recipients' == $_REQUEST['fieldName']) || (!empty($_REQUEST['MemberSearch']))) {
    268                 $form = $this->MailingListEditForm();
    269             } else {
    270                 $form = $this->TypeEditForm();
    271             }
    272         }
    273         if ($form)
    274             $form->disableDefaultAction();
    275         return $form;
    276     }
    277
    278     public function NewsletterEditForm() {
    279         $id = isset($_REQUEST['ID']) ? $_REQUEST['ID'] : $this->currentPageID();
    280         if (!is_numeric($id)) {
    281             $id = 0;
    282         }
    283         return $this->getNewsletterEditForm($id);
    284     }
    285
    286     public function TypeEditForm() {
    287         $id = isset($_REQUEST['ID']) ? $_REQUEST['ID'] : $this->currentPageID();
    288         if (!is_numeric($id)) {
    289             $id = 0;
    290         }
    291         return $this->getNewsletterTypeEditForm($id);
    292     }
    293
    294     public function MailingListEditForm() {
    295         $id = isset($_REQUEST['ID']) ? $_REQUEST['ID'] : $this->currentPageID();
    296         return $this->getMailingListEditForm($id);
    297     }
    298
    299     public function getNewsletterTypeEditForm($id) {
    300         if (!is_numeric($id)) {
    301             $id = Session::get('currentPage');
    302         }
    303         if (is_a($id, 'NewsletterType')) {
    304             $mailType = $id;
    305             $id = $mailType->ID;
    306         } else {
    307             if ($id && is_numeric($id)) {
    308                 $mailType = DataObject::get_by_id('NewsletterType', $id);
    309             }
    310         }
    311
    312         if (isset($mailType) && is_object($mailType) && $mailType->GroupID) {
    313             $group = DataObject::get_one("Group", "ID = $mailType->GroupID");
    314         }
    315         if (isset($mailType) && $mailType) {
    316             $fields = $mailType->getCMSFields();
    317
    318             $fields->push($idField = new HiddenField("ID"));
    319             $fields->push(new HiddenField("executeForm", "", "TypeEditForm"));
    320             $idField->setValue($id);
    321
    322             $actions = new FieldSet(new FormAction('save', _t('NewsletterAdmin.SAVE', 'Save')));
    323
    324             $form = new Form($this, "TypeEditForm", $fields, $actions);
    325             $form->loadDataFrom($mailType);
    326             // This saves us from having to change all the JS in response to renaming this form to TypeEditForm
    327             $form->setHTMLID('Form_EditForm');
    328         } else {
    329             $form = false;
    330         }
    331
    332         return $form;
    333     }
    334
    335     public function getMailingListEditForm($id) {
    336         if (!is_numeric($id)) {
    337             $id = Session::get('currentPage');
    338         }
    339         if (is_a($id, 'NewsletterType')) {
    340             $mailType = $id;
    341             $id = $mailType->ID;
    342         } else {
    343             if ($id && is_numeric($id)) {
    344                 $mailType = DataObject::get_by_id('NewsletterType', $id);
    345             }
    346         }
    347         $group = null;
    348
    349         if (isset($mailType) && is_object($mailType) && $mailType->GroupID) {
    350             $group = DataObject::get_one("Group", "ID = $mailType->GroupID");
    351         }
    352
    353         if (isset($mailType) && is_object($mailType)) {
    354             $fields = new FieldSet(
    355                             new TabSet("Root",
    356                                     new Tab('Recipients', _t('NewsletterAdmin.RECIPIENTS', 'Recipients'),
    357                                             $recipients = new MemberTableField(
    358                                                     $this,
    359                                                     "Recipients",
    360                                                     $group
    361                                             ),
    362                                             $exportField = new RecipientExportField("ExportRecipients", _t('NewsletterAdmin.EXPORTRECIPIENTS', 'Export Newsletter Recipients'), $group)
    363                                     ),
    364                                     new Tab('Import', _t('NewsletterAdmin.IMPORT', 'Import'),
    365                                             $importField = new RecipientImportField("ImportFile", _t('NewsletterAdmin.IMPORTFROM', 'Import from file'), $group)
    366                                     ),
    367                                     new Tab('Unsubscribers', _t('NewsletterAdmin.UNSUBSCRIBERS', 'Unsubscribers'),
    368                                             $unsubscribedList = new UnsubscribedList("Unsubscribed", $mailType)
    369                                     ),
    370                                     new Tab('Bounced', _t('NewsletterAdmin.BOUNCED', 'Bounced'), $bouncedList = new BouncedList("Bounced", $mailType)
    371                                     )
    372                             )
    373             );
    374
    375             $recipients->setController($this);
    376             $importField->setController($this);
    377             $exportField->setController($this);
    378             $unsubscribedList->setController($this);
    379             $bouncedList->setController($this);
    380
    381             $importField->setTypeID($id);
    382             $exportField->setTypeID($id);
    383
    384             $fields->push($idField = new HiddenField("ID"));
    385             $fields->push(new HiddenField("executeForm", "", "MailingListEditForm"));
    386             $idField->setValue($id);
    387             // Save button is not used in Mailing List section
    388             $actions = new FieldSet(new HiddenField("save"));
    389
    390             $form = new Form($this, "MailingListEditForm", $fields, $actions);
    391             $form->loadDataFrom(array(
    392                 'Title' => $mailType->Title,
    393                 'FromEmail' => $mailType->FromEmail
    394             ));
    395             // This saves us from having to change all the JS in response to renaming this form to MailingListEditForm
    396             $form->setHTMLID('Form_EditForm');
    397         } else {
    398             $form = false;
    399         }
    400
    401         return $form;
    402     }
    403
    404     /**
    405      * Removes a bounced member from the mailing list
    406      * top level call from front-ajax
    407      * @return String
    408      */
    409     function removebouncedmember($params) {
    410         $params = $params->allParams();
    411
    412         // First remove the Bounce entry
    413         $id = Convert::raw2sql($params['ID']);
    414         if (is_numeric($id)) {
    415             $bounceObject = DataObject::get_by_id('Email_BounceRecord', $id);
    416             if ($bounceObject) {
    417                 // Remove this bounce record
    418                 $bounceObject->delete();
    419
    420                 $memberObject = DataObject::get_by_id('Member', $bounceObject->MemberID);
    421                 $groupID = Convert::raw2sql($_REQUEST['GroupID']);
    422                 if (is_numeric($groupID) && is_object($memberObject)) {
    423                     // Remove the member from the mailing list
    424                     $memberObject->Groups()->remove($groupID);
    425                 } else {
    426                     user_error("NewsletterAdmin::removebouncedmember: Bad parameters: Group=$groupID, Member=" . $bounceObject->MemberID, E_USER_ERROR);
    427                 }
    428                 FormResponse::status_message($memberObject->Email . ' ' . _t('NewsletterAdmin.REMOVEDSUCCESS', 'was removed from the mailing list'), 'good');
    429                 FormResponse::add("$('Form_EditForm').getPageFromServer($('Form_EditForm_ID').value, 'recipients');");
    430                 return FormResponse::respond();
    431             }
    432         } else {
    433             user_error("NewsletterAdmin::removebouncedmember: Bad parameters: Group=$groupID, Member=" . $bounceObject->MemberID, E_USER_ERROR);
    434         }
    435     }
    436
    437     /**
    438      * Reloads the "Sent Status Report" tab via ajax
    439      * top level call from ajax
    440      */
    441     function getsentstatusreport($params) {
    442         $params = $params->allParams();
    443         if (Director::is_ajax()) {
    444             $newsletter = DataObject::get_by_id('Newsletter', $params['ID']);
    445             $sent_status_report = $newsletter->renderWith("Newsletter_SentStatusReport");
    446             return $sent_status_report;
    447         }
    448     }
    449
    450     /**
    451      * this function is only used once and only works for the class TemplateteList DropdownField,
    452      * due to the TemplateList is also used only once and not necessarily be there, we will make this function
    453      * deprecated, meanwhile TemplateList.php will be removed.
    454      *
    455      * @deprecated 2.4 Please use NewsletterAdmin::template_paths() and NewsletterAdmin::templateSource(). @see NewsletterType::getCMSFields();
    456      */
    457     public static function template_path() {
    458         user_error("NewsletterAdmin::template_path() is deprecated; use NewsletterAdmin::template_paths() and NewsletterAdmin::templateSource()", E_USER_NOTICE);
    459         if (self::$template_path)
    460             return self::$template_path;
    461         else
    462             return self::$template_path = project() . '/templates/email';
    463     }
    464
    465     /**
    466      * looked-up the email template_paths.
    467      * if not set, will look up both theme folder and project folder
    468      * in both cases, email folder exsits or Email folder exists
    469      * return an array containing all folders pointing to the bunch of email templates
    470      *
    471      * @return array
    472      */
    473     public static function template_paths() {
    474         if (!isset(self::$template_paths)) {
    475             if (file_exists(BASE_PATH . "/" . THEMES_DIR . "/" . SSViewer::current_theme() . "/templates/email")) {
    476                 self::$template_paths[] = THEMES_DIR . "/" . SSViewer::current_theme() . "/templates/email";
    477             }
    478
    479             if (file_exists(BASE_PATH . "/" . THEMES_DIR . "/" . SSViewer::current_theme() . "/templates/Email")) {
    480                 self::$template_paths[] = THEMES_DIR . "/" . SSViewer::current_theme() . "/templates/Email";
    481             }
    482
    483             if (file_exists(BASE_PATH . "/" . project() . '/templates/email')) {
    484                 self::$template_paths[] = project() . '/templates/email';
    485             }
    486
    487             if (file_exists(BASE_PATH . "/" . project() . '/templates/Email')) {
    488                 self::$template_paths[] = project() . '/templates/Email';
    489             }
    490         }
    491
    492         return self::$template_paths;
    493     }
    494
    495     /**
    496      * return array containing all possible email templates file name
    497      * under the folders of both theme and project specific folder.
    498      * @return array
    499      */
    500     public function templateSource() {
    501         $paths = self::template_paths();
    502         $templates = array("" => _t('TemplateList.NONE', 'None'));
    503
    504         if (isset($paths) && count($paths)) {
    505             $absPath = Director::baseFolder();
    506             if ($absPath{strlen($absPath) - 1} != "/")
    507                 $absPath .= "/";
    508
    509             foreach ($paths as $path) {
    510                 $path = $absPath . $path;
    511                 if (is_dir($path)) {
    512                     $templateDir = opendir($path);
    513
    514                     // read all files in the directory
    515                     while (( $templateFile = readdir($templateDir) ) !== false) {
    516                         // *.ss files are templates
    517                         if (preg_match('/(.*)\.ss$/', $templateFile, $match)) {
    518                             $templates[$match[1]] = $match[1];
    519                         }
    520                     }
    521                 }
    522             }
    523         }
    524         return $templates;
    525     }
    526
    527     /* Does not seem to be used
    528       public function showdraft( $params ) {
    529       return $this->showWithEditForm( $params, $this->getNewsletterEditForm( $params['ID'] ) );
    530       }
    531      */
    532
    533     public function getNewsletterEditForm($myId) {
    534         $email = DataObject::get_by_id("Newsletter", $myId);
    535         if ($email) {
    536
    537             $fields = $email->getCMSFields($this);
    538             $fields->push($idField = new HiddenField("ID"));
    539             $idField->setValue($myId);
    540             $fields->push($ParentidField = new HiddenField("ParentID"));
    541             $ParentidField->setValue($email->ParentID);
    542             $fields->push($typeField = new HiddenField("Type"));
    543             $typeField->setValue('Newsletter');
    544             //$fields->push(new HiddenField("executeForm", "", "EditForm") );
    545
    546             $actions = new FieldSet();
    547
    548             if ($email->SentDate)
    549                 $actions->push(new FormAction('send', _t('NewsletterAdmin.RESEND', 'Resend')));
    550             else
    551                 $actions->push(new FormAction('send', _t('NewsletterAdmin.SEND', 'Send...')));
    552
    553             $actions->push(new FormAction('save', _t('NewsletterAdmin.SAVE')));
    554
    555             $form = new Form($this, "NewsletterEditForm", $fields, $actions);
    556             $form->loadDataFrom($email);
    557             // This saves us from having to change all the JS in response to renaming this form to NewsletterEditForm
    558             $form->setHTMLID('Form_EditForm');
    559
    560             if (self::$makeSendNewslettersReadonly && $email->Status != 'Draft') {
    561                 $readonlyFields = $form->Fields()->makeReadonly();
    562                 $form->setFields($readonlyFields);
    563             }
    564
    565             // user_error( $form->FormAction(), E_USER_ERROR );
    566
    567             return $form;
    568         } else {
    569             user_error('Unknown Email ID: ' . $myId, E_USER_ERROR);
    570         }
    571     }
    572
    573     public function SendProgressBar() {
    574         $progressBar = new ProgressBar('SendProgressBar', _t('NewsletterAdmin.SENDING', 'Sending emails...'));
    575         return $progressBar->FieldHolder();
    576     }
    577
    578     public function sendnewsletter(/* $data, $form = null */) {
    579
    580         $id = isset($_REQUEST['ID']) ? $_REQUEST['ID'] : $_REQUEST['NewsletterID'];
    581
    582         if (!$id) {
    583             FormResponse::status_message(_t('NewsletterAdmin.NONLSPECIFIED', 'No newsletter specified'), 'bad');
    584             return FormResponse::respond();
    585         }
    586
    587         $newsletter = DataObject::get_by_id("Newsletter", $id);
    588         $nlType = $newsletter->getNewsletterType();
    589
    590         $e = new Newsletter_Email($nlType);
    591         $e->Body = $body = $newsletter->Content;
    592         $e->Subject = $subject = $newsletter->Subject;
    593
    594         // TODO Make this dynamic
    595
    596         if ($nlType && $nlType->FromEmail)
    597             $e->From = $from = $nlType->FromEmail;
    598         else
    599             $e->From = $from = Email::getAdminEmail();
    600
    601         if (isset($_REQUEST['TestEmail']))
    602             $e->To = $_REQUEST['TestEmail'];
    603         $e->setTemplate($nlType->Template);
    604         $e->populateTemplate(array(
    605             'NewsLetterData'=> $newsletter
    606         ));
    607         $messageID = base64_encode($newsletter->ID . '_' . date('d-m-Y H:i:s'));
    608
    609         switch ($_REQUEST['SendType']) {
    610             case "Test":
    611                 if ($_REQUEST['TestEmail']) {
    612                     $e->To = $_REQUEST['TestEmail'];
    613                     $e->setTemplate($nlType->Template);
    614
    615                     self::sendToAddress($e, $_REQUEST['TestEmail'], $messageID);
    616                     FormResponse::status_message(_t('NewsletterAdmin.SENTTESTTO', 'Sent test to ') . $_REQUEST['TestEmail'], 'good');
    617                 } else {
    618                     FormResponse::status_message(_t('NewsletterAdmin.PLEASEENTERMAIL', 'Please enter an email address'), 'bad');
    619                 }
    620                 break;
    621             case "List":
    622                 // Send to the entire mailing list.
    623                 $groupID = $nlType->GroupID;
    624                 $group = DataObject::get_by_id('Group', $groupID);
    625                 if ($group) {
    626                     $members = $group->Members();
    627                     if ($members) {
    628                         echo self::sendToList($subject, $body, $from, $newsletter, $nlType, $messageID,$members);
    629                     }
    630                 }
    631                 break;
    632             case "Unsent":
    633                 // Send to only those who have not already been sent this newsletter.
    634                 $only_to_unsent = 1;
    635                 echo self::sendToList($subject, $body, $from, $newsletter, $nlType, $messageID, $newsletter->UnsentSubscribers());
    636                 break;
    637         }
    638
    639         return FormResponse::respond();
    640     }
    641
    642     static function sendToAddress($email, $address, $messageID = null) {
    643         $email->To = $address;
    644         $email->send();
    645     }
    646
    647     static function sendToList($subject, $body, $from, $newsletter, $nlType, $messageID = null, $recipients) {
    648         $emailProcess = new NewsletterEmailProcess($subject, $body, $from, $newsletter, $nlType, $messageID, $recipients);
    649         return $emailProcess->start();
    650     }
    651
    652     /**
    653      * Top level call, $param is a HTTPRequest Object
    654      *
    655      * @todo When is $params an object? Typically it's the form request
    656      * data as an array...
    657      */
    658     public function save($params, $form) {
    659         if (is_object($params))
    660             $params = $params->allParams();
    661
    662         // Both the Newsletter type and the Newsletter draft call save() when "Save" button is clicked
    663         // @todo this is a hack. It needs to be cleaned up. Two different classes shouldn't share the
    664         // same submit handler since they have different behaviour!
    665         if (isset($_REQUEST['Type']) && $_REQUEST['Type'] == 'Newsletter') {
    666             return $this->savenewsletter($params, $form);
    667         }
    668
    669         $id = $_REQUEST['ID'];
    670         $className = 'NewsletterType';
    671
    672         if (defined('DB::USE_ANSI_SQL')) {
    673             $record = DataObject::get_one($className, "\"$className\".ID = $id");
    674         } else {
    675             $record = DataObject::get_one($className, "`$className`.ID = $id");
    676         }
    677         // Is the template attached to the type, or the newsletter itself?
    678
    679         $record->Template = addslashes($_REQUEST['Template']);
    680
    681         $form->saveInto($record);
    682         $record->write();
    683
    684         FormResponse::set_node_title("mailtype_$id", $record->Title);
    685         FormResponse::status_message(_t('NewsletterAdmin.SAVED', 'Saved'), 'good');
    686         $result = $this->getActionUpdateJS($record);
    687         return FormResponse::respond();
    688     }
    689
    690     /*
    691      * Internal call found so far.
    692      */
    693
    694     public function savenewsletter($urlParams, $form) {
    695         $id = $_REQUEST['ID'];
    696
    697         $className = 'Newsletter';
    698         if (defined('DB::USE_ANSI_SQL')) {
    699             $record = DataObject::get_one($className, "\"$className\".ID = $id");
    700         } else {
    701             $record = DataObject::get_one($className, "`$className`.ID = $id");
    702         }
    703
    704         // Is the template attached to the type, or the newsletter itself?
    705         $type = $record->getNewsletterType();
    706
    707         $form->saveInto($record);
    708         $record->write();
    709
    710         $id = 'draft_' . $record->ParentID . '_' . $record->ID;
    711
    712         FormResponse::set_node_title($id, $record->Title);
    713         FormResponse::status_message('Saved', 'good');
    714         // Get the new action buttons
    715         $actionList = '';
    716         foreach ($form->Actions() as $action) {
    717             $actionList .= $action->Field() . ' ';
    718         }
    719         FormResponse::add("$('Form_EditForm').loadActionsFromString('" . Convert::raw2js($actionList) . "');");
    720         return FormResponse::respond();
    721     }
    722
    723     /*
    724      * Saves the settings on the 'Bounced' tab of the 'Mailing List' allowing members to be added to NewsletterEmailBlacklist
    725      *
    726      */
    727
    728     public function memberblacklisttoggle($urlParams) {
    729         $id = $urlParams->param('ID');
    730         if ($bounceObject = DataObject::get_by_id('Email_BounceRecord', $id)) {
    731             if ($memberObject = DataObject::get_by_id('Member', $bounceObject->MemberID)) {
    732                 // If the email is currently not blocked, block it
    733                 if (FALSE == $memberObject->BlacklistedEmail) {
    734                     $memberObject->setBlacklistedEmail(TRUE);
    735                     FormResponse::status_message($memberObject->Email . ' ' . _t('NewsletterAdmin.ADDEDTOBL', 'was added to blacklist'), 'good');
    736                 } else {
    737                     // Unblock the email
    738                     $memberObject->setBlacklistedEmail(FALSE);
    739                     FormResponse::status_message($memberObject->Email . ' ' . _t('NewsletterAdmin.REMOVEDFROMBL', 'was removed from blacklist'), 'good');
    740                 }
    741             }
    742         }
    743         return FormResponse::respond();
    744     }
    745
    746     function NewsletterAdminSiteTree() {
    747         return $this->getsitetree();
    748     }
    749
    750     function getsitetree() {
    751         return $this->renderWith('NewsletterAdmin_SiteTree');
    752     }
    753
    754     /**
    755      * This method is called when a user changes subsite in the dropdownfield.
    756      * It is added temporarily to prevent error when changing subsite in newsletter admin
    757      * TODO: fully implement it to display the newsletter tree
    758      */
    759     public function SiteTreeAsUL() {
    760         return "Please refresh the page";
    761     }
    762
    763     public function AddRecordForm() {
    764         $m = new MemberTableField($this, "Members", $this->currentPageID());
    765         return $m->AddRecordForm();
    766     }
    767
    768     /**
    769      * Ajax autocompletion
    770      */
    771     public function autocomplete() {
    772         $fieldName = $this->urlParams['ID'];
    773         $fieldVal = $_REQUEST[$fieldName];
    774
    775         $matches = DataObject::get("Member", "$fieldName LIKE '" . addslashes($fieldVal) . "%'");
    776         if ($matches) {
    777             echo "<ul>";
    778             foreach ($matches as $match) {
    779                 $data = $match->FirstName;
    780                 $data .= ",$match->Surname";
    781                 $data .= ",$match->Email";
    782                 $data .= ",$match->Password";
    783                 echo "<li>" . $match->$fieldName . "<span class=\"informal\">($match->FirstName $match->Surname, $match->Email)</span><span class=\"informal data\">$data</li>";
    784             }
    785             echo "</ul>";
    786         }
    787     }
    788
    789     function savemember() {
    790         $data = $_REQUEST;
    791
    792         $className = $this->stat('subitem_class');
    793
    794         $id = $_REQUEST['ID'];
    795         if ($id == 'new')
    796             $id = null;
    797
    798         if ($id) {
    799             if (defined('DB::USE_ANSI_SQL')) {
    800                 $record = DataObject::get_one($className, "\"$className\".ID = $id");
    801             } else {
    802                 $record = DataObject::get_one($className, "`$className`.ID = $id");
    803             }
    804         } else {
    805             // send out an email to notify the user that they have been subscribed
    806             $record = new $className();
    807         }
    808
    809         $record->update($data);
    810         $record->ID = $id;
    811         $record->write();
    812
    813         $record->Groups()->add($data['GroupID']);
    814
    815         $FirstName = Convert::raw2js($record->FirstName);
    816         $Surname = Convert::raw2js($record->Surname);
    817         $Email = Convert::raw2js($record->Email);
    818         $Password = Convert::raw2js($record->Password);
    819         $response = <<<JS
    820             $('MemberList').setRecordDetails($record->ID, {
    821                 FirstName : "$FirstName",
    822                 Surname : "$Surname",
    823                 Email : "$Email"
    824             });
    825             $('MemberList').clearAddForm();
    826 JS;
    827         FormResponse::add($response);
    828         FormResponse::status_message(_t('NewsletterAdmin.SAVED'), 'good');
    829
    830         return FormResponse::respond();
    831     }
    832
    833     public function NewsletterTypes() {
    834         return DataObject::get("NewsletterType", "");
    835     }
    836
    837     /**
    838      * Called by AJAX to create a new newsletter type
    839      * Top level call
    840      */
    841     public function addtype($params) {
    842         $params = $params->allParams();
    843         $params['ID'] = $typeid = $this->newNewsletterType();
    844
    845         $form = $this->getNewsletterTypeEditForm($typeid);
    846         return $this->showWithEditForm($params, $form);
    847     }
    848
    849     /**
    850      * Called by AJAX to create a new newsletter draft
    851      * Top level call
    852      */
    853     public function adddraft($params) {
    854         $params = $params->allParams();
    855
    856         $draftID = $this->newDraft($_REQUEST['ParentID']);
    857         // Needed for shownewsletter() to work
    858         $params['ID'] = $draftID;
    859         return $this->shownewsletter($params);
    860     }
    861
    862     /**
    863      * Create a new newsletter type
    864      */
    865     private function newNewsletterType() {
    866
    867         // create the new type
    868         $newsletterType = new NewsletterType();
    869         $newsletterType->Title = _t('NewsletterAdmin.NEWNEWSLTYPE', 'New newsletter type');
    870         $newsletterType->write();
    871
    872         // BUGFIX: Return only the ID of the new newsletter type
    873         return $newsletterType->ID;
    874     }
    875
    876     private function newDraft($parentID) {
    877         if (!$parentID || !is_numeric($parentID)) {
    878             $parent = DataObject::get_one("NewsletterType");
    879             if ($parent) {
    880                 $parentID = $parent->ID;
    881             } else {
    882                 // BUGFIX: It could be that no Newsletter types have been created, if so add one to prevent errors.
    883                 $parentID = $this->newNewsletterType();
    884             }
    885         }
    886         if ($parentID && is_numeric($parentID)) {
    887             $parent = DataObject::get_by_id("NewsletterType", $parentID);
    888             // BUGFIX: It could be that no Newsletter types have been created, if so add one to prevent errors.
    889             if (!$parent) {
    890                 $parentID = $this->newNewsletterType();
    891             }
    892             $newsletter = new Newsletter();
    893             $newsletter->Status = 'Draft';
    894             $newsletter->Title = $newsletter->Subject = _t('NewsletterAdmin.MEWDRAFTMEWSL', 'New draft newsletter');
    895             $newsletter->ParentID = $parentID;
    896             $newsletter->write();
    897         } else {
    898             user_error("You must first create a newsletter type before creating a draft", E_USER_ERROR);
    899         }
    900
    901         return $newsletter->ID;
    902     }
    903
    904     public function newmember() {
    905         Session::clear('currentMember');
    906         $newMemberForm = array(
    907             "MemberForm" => $this->getMemberForm('new'),
    908         );
    909
    910         if (Director::is_ajax()) {
    911             SSViewer::setOption('rewriteHashlinks', false);
    912             $customised = $this->customise($newMemberForm);
    913             $result = $customised->renderWith($this->class . "_rightbottom");
    914             $parts = split('</?form[^>]*>', $result);
    915             echo $parts[1];
    916         } else {
    917             return $newMemberForm;
    918         }
    919     }
    920
    921     public function EditedMember() {
    922         if (Session::get('currentMember'))
    923             return DataObject::get_by_id("Member", Session::get('currentMember'));
    924     }
    925
    926     public function Link($action = null) {
    927         return "admin/newsletter/";
    928     }
    929
    930     public function displayfilefield() {
    931
    932         $id = $this->urlParams['ID'];
    933
    934         return $this->customise(array('ID' => $id, "UploadForm" => $this->UploadForm()))->renderWith('Newsletter_RecipientImportField');
    935     }
    936
    937     public function exportrecipients() {
    938         if ($newsletter = DataObject::get_by_id('NewsletterType', (int)$this->urlParams['ID'])) {
    939             $csv = "FirstName;Surname;Email\n";
    940             foreach($newsletter->Recipients() as $recipient) {
    941                 $csv .= "{$recipient->FirstName};{$recipient->Surname};{$recipient->Email}\n";
    942             }
    943             $rs = Controller::curr()->getResponse();
    944             $rs->addHeader('Content-Type', 'application/csv');
    945             $rs->addHeader('Content-Disposition', 'attachment; filename=recipients.csv');
    946             //$rs->addHeader('Content-Transfer-Encoding', 'binary');
    947             $rs->addHeader('Cache-Control', 'must-revalidate');
    948             $rs->addHeader('Expires', '0');
    949             echo $csv;
    950             return;
    951         }
    952         return $this->customise(array('ID' => $id, "UploadForm" => $this->UploadForm()))->renderWith('Newsletter_RecipientImportField');
    953     }
    954
    955     function UploadForm($id = null) {
    956
    957         if (!$id)
    958             $id = $this->urlParams['ID'];
    959
    960         $fields = new FieldSet(
    961                         new FileField("ImportFile", ""),
    962                         //new HiddenField( "action_import", "", "1" ),
    963                         new HiddenField("ID", "", $id)
    964         );
    965
    966         $actions = new FieldSet(
    967                         new FormAction("action_import", _t('NewsletterAdmin.SHOWCONTENTS', 'Show contents'))
    968         );
    969
    970         $form = new RecipientImportField_UploadForm($this, "UploadForm", $fields, $actions);
    971         $form->disableSecurityToken();
    972         return $form;
    973     }
    974
    975     function getMenuTitle() {
    976         return _t('LeftAndMain.NEWSLETTERS', "Newsletters", PR_HIGH, "Menu title");
    977     }
    978
    979 }
    980
    981 ?>
    982

[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -