simplenews.admin.inc 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986
  1. <?php
  2. /**
  3. * @file
  4. * Newsletter admin, subscription admin, simplenews settings
  5. *
  6. * @ingroup simplenews
  7. */
  8. /**
  9. * Menu callback: Admin form for sent and draft newsletters.
  10. *
  11. * @see simplenews_admin_newsletter_submit()
  12. */
  13. function simplenews_admin_newsletter_issues($form, &$form_state, $action = 'sent') {
  14. // @todo Fix the delete operation
  15. $form['filter'] = simplenews_issue_filter_form();
  16. $form['#submit'][] = 'simplenews_issue_filter_form_submit';
  17. $form['filter']['#theme'] = 'simplenews_filter_form';
  18. $form['admin'] = simplenews_admin_issues();
  19. return $form;
  20. }
  21. /**
  22. * Generate issue filters
  23. */
  24. function simplenews_issue_filters() {
  25. // Newsletter filter
  26. $filters['category'] = array(
  27. 'title' => t('Subscribed to'),
  28. 'options' => array(
  29. 'all' => t('All newsletters'),
  30. 'tid-0' => t('Unassigned newsletters'),
  31. ),
  32. );
  33. foreach (simplenews_category_list() as $tid => $name) {
  34. $filters['category']['options']['tid-' . $tid] = $name;
  35. }
  36. return $filters;
  37. }
  38. /**
  39. * Return form for issue filters.
  40. *
  41. * @see simplenews_issue_filter_form_submit()
  42. */
  43. function simplenews_issue_filter_form() {
  44. // Current filter selections in $session var; stored at form submission
  45. // Example: array('category' => 'all')
  46. $session = isset($_SESSION['simplenews_issue_filter']) ? $_SESSION['simplenews_issue_filter'] : _simplenews_issue_filter_default();
  47. $filters = simplenews_issue_filters();
  48. $form['filters'] = array(
  49. '#type' => 'fieldset',
  50. '#title' => t('Show only newsletters which'),
  51. );
  52. // Filter values are default
  53. $form['filters']['category'] = array(
  54. '#type' => 'select',
  55. '#title' => $filters['category']['title'],
  56. '#options' => $filters['category']['options'],
  57. '#default_value' => $session['category'],
  58. );
  59. $form['filters']['buttons']['submit'] = array(
  60. '#type' => 'submit',
  61. '#value' => t('Filter'),
  62. '#prefix' => '<span class="spacer" />',
  63. );
  64. // Add Reset button if filter is in use
  65. if ($session != _simplenews_issue_filter_default()) {
  66. $form['filters']['buttons']['reset'] = array(
  67. '#type' => 'submit',
  68. '#value' => t('Reset'),
  69. );
  70. }
  71. return $form;
  72. }
  73. /**
  74. * Helper function: returns issue filter default settings
  75. */
  76. function _simplenews_issue_filter_default() {
  77. return array(
  78. 'category' => 'all',
  79. );
  80. }
  81. /**
  82. * Form submit callback for the newsletter issue filter.
  83. */
  84. function simplenews_issue_filter_form_submit($form, &$form_state) {
  85. switch ($form_state['values']['op']) {
  86. case t('Filter'):
  87. $_SESSION['simplenews_issue_filter'] = array(
  88. 'category' => $form_state['values']['category'],
  89. );
  90. break;
  91. case t('Reset'):
  92. $_SESSION['simplenews_issue_filter'] = _simplenews_issue_filter_default();
  93. break;
  94. }
  95. }
  96. /**
  97. * Form builder: Builds a list of newsletters with operations.
  98. *
  99. * @see simplenews_admin_issues_validate()
  100. * @see simplenews_admin_issues_submit()
  101. */
  102. function simplenews_admin_issues() {
  103. // Build an 'Update options' form.
  104. $form['options'] = array(
  105. '#type' => 'fieldset',
  106. '#title' => t('Update options'),
  107. '#prefix' => '<div class="container-inline">',
  108. '#suffix' => '</div>',
  109. );
  110. $options = array();
  111. foreach (module_invoke_all('simplenews_issue_operations') as $operation => $array) {
  112. $options[$operation] = $array['label'];
  113. }
  114. $form['options']['operation'] = array(
  115. '#type' => 'select',
  116. '#options' => $options,
  117. '#default_value' => 'activate',
  118. );
  119. $form['options']['submit'] = array(
  120. '#type' => 'submit',
  121. '#value' => t('Update'),
  122. '#submit' => array('simplenews_admin_issues_submit'),
  123. '#validate' => array('simplenews_admin_issues_validate'),
  124. );
  125. if (variable_get('simplenews_last_cron', '')) {
  126. $form['last_sent'] = array(
  127. '#value' => '<p>' . format_plural(variable_get('simplenews_last_sent', 0),
  128. 'Last batch: 1 mail sent at !time.',
  129. 'Last batch: !count mails sent at !time.',
  130. array('!time' => format_date(variable_get('simplenews_last_cron', ''), 'small'), '!count' => variable_get('simplenews_last_sent', 0))) . "</p>\n",
  131. );
  132. }
  133. // Table header. Used as tablesort default
  134. $header = array(
  135. 'title' => array('data' => t('Title'), 'field' => 'n.title'),
  136. 'category' => array('data' => t('Newsletter category'), 'field' => 'sc.name'),
  137. 'created' => array('data' => t('Created'), 'field' => 'n.created', 'sort' => 'desc'),
  138. 'published' => array('data' => t('Published')),
  139. 'sent' => array('data' => t('Sent')),
  140. 'subscribers' => array('data' => t('Subscribers')),
  141. 'operations' => array('data' => t('Operations')),
  142. );
  143. $query = db_select('node', 'n')->extend('PagerDefault')->extend('TableSort');
  144. simplenews_build_issue_filter_query($query);
  145. $query->innerJoin('simplenews_newsletter', 'sn', 'n.nid = sn.nid');
  146. $query->leftJoin('simplenews_category', 'sc', 'sn.tid = sc.tid');
  147. $query->leftJoin('taxonomy_term_data', 't', 'sc.tid = t.tid');
  148. //$query->leftJoin('users', 'u', 'ss.uid = u.uid');
  149. $query->fields('n', array('nid', 'title', 'created', 'status'))
  150. ->fields('sn', array('tid'))
  151. ->fields('t', array('name'))
  152. ->limit(30)
  153. ->orderByHeader($header);
  154. $query->addField('sn', 'status', 'sent_status');
  155. $options = array();
  156. $destination = drupal_get_destination();
  157. module_load_include('inc', 'simplenews', 'includes/simplenews.mail');
  158. foreach ($query->execute() as $issue) {
  159. $categories = simplenews_category_list();
  160. $subscriber_count = simplenews_count_subscriptions($issue->tid);
  161. $pending_count = simplenews_count_spool(array('nid' => $issue->nid));
  162. $send_status = $issue->sent_status == SIMPLENEWS_STATUS_SEND_PENDING ? $subscriber_count - $pending_count : theme('simplenews_status', array('source' => 'sent', 'status' => $issue->sent_status));
  163. $options[$issue->nid] = array(
  164. 'title' => l($issue->title, 'node/' . $issue->nid),
  165. 'category' => $issue->tid ? $categories[$issue->tid] : t('- Unassigned -'),
  166. 'created' => format_date($issue->created, 'small'),
  167. 'published' => theme('simplenews_status', array('source' => 'published', 'status' => $issue->status)),
  168. 'sent' => $send_status,
  169. 'subscribers' => $subscriber_count,
  170. 'operations' => l(t('edit'), 'node/' . $issue->nid . '/edit', array('query' => drupal_get_destination())),
  171. );
  172. }
  173. $form['issues'] = array(
  174. '#type' => 'tableselect',
  175. '#header' => $header,
  176. '#options' => $options,
  177. '#empty' => t('No newsletters available.'),
  178. );
  179. $form['pager'] = array('#theme' => 'pager');
  180. return $form;
  181. }
  182. /**
  183. * Implements hook_simplenews_issue_operations().
  184. */
  185. function simplenews_simplenews_issue_operations() {
  186. // @todo: future ideas: 'pause' => t('Pause sending'), 'resume' => t('Resume sending'), 'cancel' => t('Cancel sending'), 'publish' => t('Publish'), 'unpublish' => t('Unpublish'));
  187. $operations = array(
  188. 'activate' => array(
  189. 'label' => t('Send'),
  190. 'callback' => 'simplenews_issue_send',
  191. ),
  192. );
  193. return $operations;
  194. }
  195. /**
  196. * Form vaidate callback for the issue list operations.
  197. */
  198. function simplenews_admin_issues_validate($form, &$form_state) {
  199. if (isset($form_state['input']['operation'])) {
  200. $nids = array_keys(array_filter($form_state['input']['issues']));
  201. if (empty($nids)) {
  202. form_set_error('', t('No items selected.'));
  203. }
  204. }
  205. }
  206. /**
  207. * Form submit callback for the issue operations.
  208. */
  209. function simplenews_admin_issues_submit($form, &$form_state) {
  210. // Call operation functions as defined in hook_simplenews_issue_operations().
  211. $operations = module_invoke_all('simplenews_issue_operations');
  212. $operation = $operations[$form_state['values']['operation']];
  213. // Filter out unchecked list issues
  214. $nids = array_filter($form_state['values']['issues']);
  215. if ($function = $operation['callback']) {
  216. // Add in callback arguments if present.
  217. if (isset($operation['callback arguments'])) {
  218. $args = array_merge(array($nids), $operation['callback arguments']);
  219. }
  220. else {
  221. $args = array($nids);
  222. }
  223. call_user_func_array($function, $args);
  224. }
  225. else {
  226. // We need to rebuild the form to go to a second step. For example, to
  227. // show the confirmation form for the deletion of nodes.
  228. $form_state['rebuild'] = TRUE;
  229. }
  230. }
  231. /**
  232. * Callback to send newsletters.
  233. */
  234. function simplenews_issue_send($nids) {
  235. $sent_nodes = array();
  236. foreach (node_load_multiple($nids) as $node) {
  237. $newsletter = simplenews_newsletter_load($node->nid);
  238. if ($newsletter->status != SIMPLENEWS_STATUS_SEND_NOT) {
  239. continue;
  240. }
  241. if ($node->status == NODE_NOT_PUBLISHED) {
  242. simplenews_newsletter_update_sent_status($node, SIMPLENEWS_COMMAND_SEND_PUBLISH);
  243. drupal_set_message(t('Newsletter %title is unpublished and will be sent on publish.', array('%title' => $node->title)));
  244. continue;
  245. }
  246. simplenews_add_node_to_spool($node);
  247. $sent_nodes[$node->nid] = $node->title;
  248. }
  249. // If there were any newsletters sent, display a message.
  250. if (!empty($sent_nodes)) {
  251. $conditions = array('nid' => array_keys($sent_nodes));
  252. // Attempt to send immediatly, if configured to do so.
  253. if (simplenews_mail_attempt_immediate_send($conditions)) {
  254. drupal_set_message(t('Sent the following newsletters: %titles.', array('%titles' => implode(', ', $sent_nodes))));
  255. }
  256. else {
  257. drupal_set_message(t('The following newsletter are now pending: %titles.', array('%titles' => implode(', ', $sent_nodes))));
  258. }
  259. }
  260. }
  261. /**
  262. * Apply filters for subscription filters based on session.
  263. *
  264. * @param $query
  265. * A SelectQuery to which the filters should be applied.
  266. */
  267. function simplenews_build_issue_filter_query(SelectQueryInterface $query) {
  268. if (isset($_SESSION['simplenews_issue_filter'])) {
  269. foreach ($_SESSION['simplenews_issue_filter'] as $key => $value) {
  270. switch ($key) {
  271. case 'list':
  272. case 'category':
  273. if ($value != 'all') {
  274. list($key, $value) = explode('-', $value, 2);
  275. $query->condition('sn.' . $key, $value);
  276. }
  277. break;
  278. }
  279. }
  280. }
  281. }
  282. /**
  283. * Menu callback: list admin form with list of available list categories.
  284. *
  285. * @ingroup forms
  286. * @see simplenews_admin_newsletter_categories_submit()
  287. * @see theme_simplenews_admin_newsletter_categories()
  288. */
  289. function simplenews_admin_categories() {
  290. $form['#tree'] = TRUE;
  291. if ($categories = simplenews_categories_load_multiple(array(), array('show_all' => TRUE))) {
  292. foreach ($categories as $category) {
  293. $form[$category->tid]['#category'] = $category;
  294. $form[$category->tid]['name'] = array('#markup' => check_plain(_simplenews_newsletter_name($category)));
  295. $form[$category->tid]['weight'] = array('#type' => 'weight', '#delta' => 10, '#default_value' => $category->weight);
  296. $form[$category->tid]['edit'] = array(
  297. '#type' => 'link',
  298. '#title' => t('edit newsletter category'),
  299. '#href' => "admin/config/services/simplenews/categories/$category->tid/edit",
  300. );
  301. }
  302. }
  303. // Only make this form include a submit button and weight if more than one
  304. // category exists.
  305. if (count($categories) > 1) {
  306. $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
  307. }
  308. elseif (!empty($categories)) {
  309. $form[$category->tid]['weight'] = array('#type' => 'value', '#value' => 0);
  310. }
  311. return $form;
  312. }
  313. /**
  314. * Form submit callback for the simplenews categories.
  315. */
  316. function simplenews_admin_categories_submit($form, &$form_state) {
  317. foreach ($form_state['values'] as $tid => $category) {
  318. if (is_numeric($tid) && $form[$tid]['#category']->weight != $category['weight']) {
  319. $form[$tid]['#category']->weight = $category['weight'];
  320. simplenews_category_save($form[$tid]['#category']);
  321. }
  322. }
  323. drupal_set_message(t('Your configuration has been saved.'));
  324. }
  325. /**
  326. * Form builder function, display a list of simplenews categories.
  327. *
  328. * @ingroup theming
  329. */
  330. function theme_simplenews_admin_categories($variables) {
  331. $form = $variables['form'];
  332. $rows = array();
  333. foreach (element_children($form) as $key) {
  334. if (isset($form[$key]['name'])) {
  335. $category = &$form[$key];
  336. $row = array();
  337. $row[] = drupal_render($category['name']);
  338. if (isset($category['weight'])) {
  339. $category['weight']['#attributes']['class'] = array('simplenews-category-weight');
  340. $row[] = drupal_render($category['weight']);
  341. }
  342. $row[] = drupal_render($category['edit']);
  343. $rows[] = array('data' => $row, 'class' => array('draggable'));
  344. }
  345. }
  346. $header = array(t('Newsletter category name'));
  347. if (isset($form['submit'])) {
  348. $header[] = t('Weight');
  349. drupal_add_tabledrag('newsletter-category', 'order', 'self', 'simplenews-category-weight');
  350. }
  351. $header[] = array('data' => t('Operations'), 'colspan' => '3');
  352. return theme('table', array('header' => $header, 'rows' => $rows, 'empty' => t('No newsletter categories. <a href="@link">Add category</a>.', array('@link' => url('admin/config/services/simplenews/add'))), 'attributes' => array('id' => 'newsletter-category'))) . drupal_render_children($form);
  353. }
  354. /**
  355. * Menu callback: newsletter admin form for newsletter add/edit.
  356. *
  357. * @see simplenews_admin_category_form_validate()
  358. * @see simplenews_admin_category_form_submit()
  359. */
  360. function simplenews_admin_category_form($form, &$form_state, $edit = array()) {
  361. if (!is_array($edit)) {
  362. $edit = (array)$edit;
  363. }
  364. $edit += array(
  365. 'tid' => 0,
  366. 'name' => '',
  367. 'description' => '',
  368. 'weight' => '0',
  369. 'new_account' => 'none',
  370. 'opt_inout' => 'double',
  371. 'block' => 1,
  372. 'format' => variable_get('simplenews_format', 'plain'),
  373. 'priority' => variable_get('simplenews_priority', SIMPLENEWS_PRIORITY_NONE),
  374. 'receipt' => variable_get('simplenews_receipt', 0),
  375. 'from_name' => variable_get('simplenews_from_name', variable_get('site_name', 'Drupal')),
  376. 'email_subject' => '[[simplenews-category:name]] [node:title]',
  377. 'from_address' => variable_get('simplenews_from_address', variable_get('site_mail', ini_get('sendmail_from'))),
  378. 'hyperlinks' => 1,
  379. );
  380. $form['#category'] = (object) $edit;
  381. // Check whether we need a deletion confirmation form.
  382. if (isset($form_state['confirm_delete']) && isset($form_state['values']['tid'])) {
  383. $category = simplenews_category_load($form_state['values']['tid']);
  384. return simplenews_admin_category_delete($form, $form_state, $category);
  385. }
  386. $form['tid'] = array(
  387. '#type' => 'value',
  388. '#value' => $edit['tid'],
  389. );
  390. $form['name'] = array(
  391. '#type' => 'textfield',
  392. '#title' => t('Name'),
  393. '#default_value' => $edit['name'],
  394. '#maxlength' => 255,
  395. '#required' => TRUE,
  396. );
  397. $form['description'] = array(
  398. '#type' => 'textfield',
  399. '#title' => t('Description'),
  400. '#default_value' => $edit['description'],
  401. );
  402. $form['weight'] = array(
  403. '#type' => 'hidden',
  404. '#value' => $edit['weight'],
  405. );
  406. $form['subscription'] = array(
  407. '#type' => 'fieldset',
  408. '#title' => t('Subscription settings'),
  409. '#collapsible' => FALSE,
  410. );
  411. // Subscribe at account registration time.
  412. $options = array(
  413. 'none' => t('None'),
  414. 'on' => t('Default on'),
  415. 'off' => t('Default off'),
  416. 'silent' => t('Silent'),
  417. );
  418. $form['subscription']['new_account'] = array(
  419. '#type' => 'select',
  420. '#title' => t('Subscribe new account'),
  421. '#options' => $options,
  422. '#default_value' => $edit['new_account'],
  423. '#description' => t('None: This newsletter is not listed on the user registration page.<br />Default on: This newsletter is listed on the user registion page and is selected by default.<br />Default off: This newsletter is listed on the user registion page and is not selected by default.<br />Silent: A new user is automatically subscribed to this newsletter. The newsletter is not listed on the user registration page.'),
  424. );
  425. // Type of (un)subsribe confirmation
  426. $options = array(
  427. SIMPLENEWS_OPT_INOUT_HIDDEN => t('Hidden'),
  428. SIMPLENEWS_OPT_INOUT_SINGLE => t('Single'),
  429. SIMPLENEWS_OPT_INOUT_DOUBLE => t('Double'),
  430. );
  431. $form['subscription']['opt_inout'] = array(
  432. '#type' => 'select',
  433. '#title' => t('Opt-in/out method'),
  434. '#options' => $options,
  435. '#default_value' => $edit['opt_inout'],
  436. '#description' => t('Hidden: This newsletter does not appear on subscription forms. No unsubscription footer in newsletter.<br /> Single: Users are (un)subscribed immediately, no confirmation email is sent.<br />Double: When (un)subscribing at a subscription form, anonymous users receive an (un)subscription confirmation email. Authenticated users are (un)subscribed immediately.'),
  437. );
  438. // Provide subscription block for this category.
  439. $form['subscription']['block'] = array(
  440. '#type' => 'checkbox',
  441. '#title' => t('Subscription block'),
  442. '#default_value' => $edit['block'],
  443. '#description' => t('A subscription block will be provided for this newsletter category. Anonymous and authenticated users can subscribe and unsubscribe using this block.'),
  444. );
  445. $form['email'] = array(
  446. '#type' => 'fieldset',
  447. '#title' => t('Email settings'),
  448. '#collapsible' => FALSE,
  449. );
  450. // Hide format selection if there is nothing to choose.
  451. // The default format is plain text.
  452. $format_options = simplenews_format_options();
  453. if (count($format_options) > 1) {
  454. $form['email']['format'] = array(
  455. '#type' => 'radios',
  456. '#title' => t('Email format'),
  457. '#default_value' => $edit['format'],
  458. '#options' => $format_options,
  459. );
  460. }
  461. else {
  462. $form['email']['format'] = array(
  463. '#type' => 'hidden',
  464. '#value' => key($format_options),
  465. );
  466. $form['email']['format_text'] = array(
  467. '#markup' => t('Newsletter emails will be sent in %format format.', array('%format' => $edit['format'])),
  468. );
  469. }
  470. $form['email']['priority'] = array(
  471. '#type' => 'select',
  472. '#title' => t('Email priority'),
  473. '#default_value' => $edit['priority'],
  474. '#options' => simplenews_get_priority(),
  475. );
  476. $form['email']['receipt'] = array(
  477. '#type' => 'checkbox',
  478. '#title' => t('Request receipt'),
  479. '#return_value' => 1,
  480. '#default_value' => $edit['receipt'],
  481. );
  482. // Email sender name
  483. $form['simplenews_sender_information'] = array(
  484. '#type' => 'fieldset',
  485. '#title' => t('Sender information'),
  486. '#collapsible' => FALSE,
  487. );
  488. $form['simplenews_sender_information']['from_name'] = array(
  489. '#type' => 'textfield',
  490. '#title' => t('From name'),
  491. '#size' => 60,
  492. '#maxlength' => 128,
  493. '#default_value' => $edit['from_name'],
  494. );
  495. // Email subject
  496. $form['simplenews_subject'] = array(
  497. '#type' => 'fieldset',
  498. '#title' => t('Newsletter subject'),
  499. '#collapsible' => FALSE,
  500. );
  501. if (module_exists('token')) {
  502. $form['simplenews_subject']['token_help'] = array(
  503. '#title' => t('Replacement patterns'),
  504. '#type' => 'fieldset',
  505. '#collapsible' => TRUE,
  506. '#collapsed' => TRUE,
  507. );
  508. $form['simplenews_subject']['token_help']['browser'] = array(
  509. '#theme' => 'token_tree',
  510. '#token_types' => array('simplenews-category', 'node', 'simplenews-subscriber'),
  511. );
  512. }
  513. $form['simplenews_subject']['email_subject'] = array(
  514. '#type' => 'textfield',
  515. '#title' => t('Email subject'),
  516. '#size' => 60,
  517. '#maxlength' => 128,
  518. '#required' => TRUE,
  519. '#default_value' => $edit['email_subject'],
  520. );
  521. // Email from address
  522. $form['simplenews_sender_information']['from_address'] = array(
  523. '#type' => 'textfield',
  524. '#title' => t('From email address'),
  525. '#size' => 60,
  526. '#maxlength' => 128,
  527. '#required' => TRUE,
  528. '#default_value' => $edit['from_address'],
  529. );
  530. // Type of hyperlinks
  531. $form['simplenews_hyperlinks'] = array(
  532. '#type' => 'fieldset',
  533. '#title' => t('HTML to text conversion'),
  534. '#collapsible' => FALSE,
  535. '#description' => t('When your newsletter is sent as plain text, these options will determine how the conversion to text is performed.'),
  536. );
  537. $form['simplenews_hyperlinks']['hyperlinks'] = array(
  538. '#type' => 'radios',
  539. '#title' => t('Hyperlink conversion'),
  540. '#options' => array(t('Append hyperlinks as a numbered reference list'), t('Display hyperlinks inline with the text')),
  541. '#default_value' => $edit['hyperlinks'],
  542. );
  543. $form['actions'] = array('#type' => 'actions');
  544. $form['actions']['submit'] = array(
  545. '#type' => 'submit',
  546. '#value' => t('Save'),
  547. '#weight' => 50,
  548. );
  549. if ($edit['tid']) {
  550. $form['actions']['delete'] = array(
  551. '#type' => 'submit',
  552. '#value' => t('Delete'),
  553. '#weight' => 55,
  554. );
  555. }
  556. return $form;
  557. }
  558. /**
  559. * Form validation callback for a newsletter category form.
  560. */
  561. function simplenews_admin_category_form_validate($form, &$form_state) {
  562. if ($form_state['clicked_button']['#value'] != t('Delete')) {
  563. // Check for valid email address.
  564. if (!valid_email_address($form_state['values']['from_address'])) {
  565. form_set_error('from_address', t("The sender's email address you supplied is not valid."));
  566. }
  567. }
  568. }
  569. /**
  570. * Form submit callback for a newsletter category form.
  571. */
  572. function simplenews_admin_category_form_submit($form, &$form_state) {
  573. //dpm($form_state);
  574. $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
  575. if ($op == t('Delete')) {
  576. $form_state['redirect'] = 'admin/config/services/simplenews/categories/' . $form_state['values']['tid'] . '/delete';
  577. return;
  578. }
  579. $category = (object)$form_state['values'];
  580. // Create or update taxonomy term.
  581. $term = new stdClass();
  582. $term->tid = $form_state['values']['tid'];
  583. $term->vid = variable_get('simplenews_vid', 0);
  584. $term->name = $form_state['values']['name'];
  585. $term->description = $form_state['values']['description'];
  586. $term->weight = $form_state['values']['weight'];
  587. taxonomy_term_save($term);
  588. $category->tid = $term->tid;
  589. switch (simplenews_category_save($category)) {
  590. case SAVED_NEW:
  591. drupal_set_message(t('Created new newsletter category %name.', array('%name' => _simplenews_newsletter_name($category))));
  592. watchdog('simplenews', 'Created new newsletter category %name.', array('%name' => _simplenews_newsletter_name($category), WATCHDOG_NOTICE, l(t('edit'), 'admin/config/services/simplenews/categories/' . $category->tid . '/edit')));
  593. break;
  594. case SAVED_UPDATED:
  595. drupal_set_message(t('Updated newsletter category %name.', array('%name' => _simplenews_newsletter_name($category))));
  596. watchdog('simplenews', 'Updated newsletter category %name.', array('%name' => _simplenews_newsletter_name($category)), WATCHDOG_NOTICE, l(t('edit'), 'admin/config/services/simplenews/categories/' . $category->tid . '/edit'));
  597. break;
  598. }
  599. $form_state['values']['tid'] = $category->tid;
  600. $form_state['tid'] = $category->tid;
  601. $form_state['redirect'] = 'admin/config/services/simplenews';
  602. }
  603. /**
  604. * Menu callback: Delete newsletter category.
  605. *
  606. * @see simplenews_admin_category_delete_submit()
  607. */
  608. function simplenews_admin_category_delete($form, &$form_state, $category) {
  609. // Store some category values for submit handling.
  610. $form = array();
  611. $form['tid'] = array('#type' => 'value', '#value' => $category->tid);
  612. $form['name'] = array('#type' => 'value', '#value' => _simplenews_newsletter_name($category));
  613. $form['notice'] = array(
  614. '#markup' => '<p><strong>' . t('Note: All subscriptions associated with this newsletter will be lost.') . '</strong></p>',
  615. );
  616. return confirm_form($form,
  617. t('Are you sure you want to delete category %name?', array('%name' => _simplenews_newsletter_name($category))),
  618. 'admin/config/services/simplenews',
  619. t('This action cannot be undone.'),
  620. t('Delete'),
  621. t('Cancel')
  622. );
  623. }
  624. /**
  625. * Form submit callback for deleting a simplenews category.
  626. */
  627. function simplenews_admin_category_delete_submit($form, &$form_state) {
  628. $tid = $form_state['values']['tid'];
  629. $name = $form_state['values']['name'];
  630. // Delete newsletter category and associated taxonomy term.
  631. // Subscriptions are deleted by simplenews_simplenews_category_delete()
  632. simplenews_category_delete($tid);
  633. taxonomy_term_delete($tid);
  634. drupal_set_message(t('Newsletter category %name has been deleted.', array('%name' => $name)));
  635. $form_state['redirect'] = 'admin/config/services/simplenews';
  636. return;
  637. }
  638. /**
  639. * Menu callback: Mass subscribe to newsletters.
  640. *
  641. * @see simplenews_subscription_list_add_submit()
  642. *
  643. * @todo Add 32char description field as subsription source
  644. */
  645. function simplenews_subscription_list_add($form, &$form_state) {
  646. global $language;
  647. $form['emails'] = array(
  648. '#type' => 'textarea',
  649. '#title' => t('Email addresses'),
  650. '#cols' => 60,
  651. '#rows' => 5,
  652. '#description' => t('Email addresses must be separated by comma, space or newline.'),
  653. );
  654. $form['newsletters'] = array(
  655. '#type' => 'fieldset',
  656. '#description' => t('Subscribe to'),
  657. '#tree' => TRUE,
  658. );
  659. foreach (simplenews_categories_load_multiple() as $list) {
  660. $form['newsletters'][$list->tid] = array(
  661. '#type' => 'checkbox',
  662. '#title' => check_plain(_simplenews_newsletter_name($list)),
  663. '#description' => _simplenews_newsletter_description($list),
  664. );
  665. }
  666. // Include language selection when the site is multilingual.
  667. // Default value is the empty string which will result in receiving emails
  668. // in the site's default language.
  669. if (variable_get('language_count', 1) > 1) {
  670. $options[''] = t('Site default language');
  671. $languages = language_list('enabled');
  672. foreach ($languages[1] as $langcode => $item) {
  673. $name = t($item->name);
  674. $options[$langcode] = $name . ($item->native != $name ? ' (' . $item->native . ')' : '');
  675. }
  676. $form['language'] = array(
  677. '#type' => 'radios',
  678. '#title' => t('Anonymous user preferred language'),
  679. '#default_value' => '',
  680. '#options' => $options,
  681. '#description' => t('New subscriptions will be subscribed with the selected preferred language. The language of existing subscribers is unchanged.'),
  682. );
  683. }
  684. else {
  685. $form['language'] = array(
  686. '#type' => 'value',
  687. '#value' => '',
  688. );
  689. }
  690. $form['submit'] = array(
  691. '#type' => 'submit',
  692. '#value' => t('Subscribe'),
  693. );
  694. return $form;
  695. }
  696. /**
  697. * @todo
  698. */
  699. function simplenews_subscription_list_add_submit($form, &$form_state) {
  700. $added = array();
  701. $invalid = array();
  702. $checked_categories = array_keys(array_filter($form_state['values']['newsletters']));
  703. $langcode = $form_state['values']['language'];
  704. $emails = preg_split("/[\s,]+/", $form_state['values']['emails']);
  705. foreach ($emails as $email) {
  706. $email = trim($email);
  707. if ($email == '') {
  708. continue;
  709. }
  710. if (valid_email_address($email)) {
  711. foreach (simplenews_categories_load_multiple($checked_categories) as $category) {
  712. simplenews_subscribe_user($email, $category->tid, FALSE, 'mass subscribe', $langcode);
  713. $added[] = $email;
  714. }
  715. }
  716. else {
  717. $invalid[] = $email;
  718. }
  719. }
  720. if ($added) {
  721. $added = implode(", ", $added);
  722. drupal_set_message(t('The following addresses were added or updated: %added.', array('%added' => $added)));
  723. $list_names = array();
  724. foreach (simplenews_categories_load_multiple($checked_categories) as $category) {
  725. $list_names[] = $category->name;
  726. }
  727. drupal_set_message(t('The addresses were subscribed to the following newsletters: %newsletters.', array('%newsletters' => implode(', ', $list_names))));
  728. }
  729. else {
  730. drupal_set_message(t('No addresses were added.'));
  731. }
  732. if ($invalid) {
  733. $invalid = implode(", ", $invalid);
  734. drupal_set_message(t('The following addresses were invalid: %invalid.', array('%invalid' => $invalid)), 'error');
  735. }
  736. // Return to the parent page.
  737. $form_state['redirect'] = 'admin/people/simplenews';
  738. }
  739. /**
  740. * Menu callback: Export email address of subscriptions.
  741. *
  742. * @see simplenews_admin_export_after_build()
  743. */
  744. function simplenews_subscription_list_export($form, &$form_state) {
  745. // Get sensible default values for the form elements in this form.
  746. $default['states'] = isset($_GET['states']) ? $_GET['states'] : array('active' => 'active');
  747. $default['subscribed'] = isset($_GET['subscribed']) ? $_GET['subscribed'] : array('subscribed' => 'subscribed');
  748. $default['newsletters'] = isset($_GET['newsletters']) ? $_GET['newsletters'] : array();
  749. $form['states'] = array(
  750. '#type' => 'checkboxes',
  751. '#title' => t('Status'),
  752. '#options' => array(
  753. 'active' => t('Active users'),
  754. 'inactive' => t('Inactive users'),
  755. ),
  756. '#default_value' => $default['states'],
  757. '#description' => t('Subscriptions matching the selected states will be exported.'),
  758. '#required' => TRUE,
  759. );
  760. $form['subscribed'] = array(
  761. '#type' => 'checkboxes',
  762. '#title' => t('Subscribed'),
  763. '#options' => array(
  764. 'subscribed' => t('Subscribed to the newsletter'),
  765. 'unsubscribed' => t('UnSubscribed from the newsletter'),
  766. ),
  767. '#default_value' => $default['subscribed'],
  768. '#description' => t('Subscriptions matching the selected subscription states will be exported.'),
  769. '#required' => TRUE,
  770. );
  771. $options = simplenews_category_list();
  772. $form['newsletters'] = array(
  773. '#type' => 'checkboxes',
  774. '#title' => t('Newsletter'),
  775. '#options' => $options,
  776. '#default_value' => $default['newsletters'],
  777. '#description' => t('Subscriptions matching the selected newsletters will be exported.'),
  778. '#required' => TRUE,
  779. );
  780. // Get export results and display them in a text area. Only get the results
  781. // if the form is build after redirect, not after submit.
  782. if (isset($_GET['states']) && empty($form_state['input'])) {
  783. $form['emails'] = array(
  784. '#type' => 'textarea',
  785. '#title' => t('Export results'),
  786. '#cols' => 60,
  787. '#rows' => 5,
  788. '#value' => _simplenews_subscription_list_export_get_emails($_GET['states'], $_GET['subscribed'], $_GET['newsletters']),
  789. );
  790. }
  791. $form['submit'] = array(
  792. '#type' => 'submit',
  793. '#value' => t('Export'),
  794. );
  795. return $form;
  796. }
  797. /**
  798. * @todo
  799. */
  800. function simplenews_subscription_list_export_submit($form, &$form_state) {
  801. $form_values = $form_state['values'];
  802. // Get data for query string and redirect back to the current page.
  803. $options['query']['states'] = array_filter($form_values['states']);
  804. $options['query']['subscribed'] = array_filter($form_values['subscribed']);
  805. $options['query']['newsletters'] = array_keys(array_filter($form_values['newsletters']));
  806. $form_state['redirect'] = array('admin/people/simplenews/export', $options);
  807. }
  808. /**
  809. * Helper function to get comma separated list of emails to be exported.
  810. *
  811. * @param $states
  812. * Array of subscriber states to filter on.
  813. * @param $subscribed
  814. * Array of subscription states to filter on.
  815. * @param $newsletters
  816. * Array of taxonomy ids to fitler on.
  817. * @return string
  818. * Comma separated list of email adresses.
  819. */
  820. function _simplenews_subscription_list_export_get_emails($states, $subscribed, $newsletters) {
  821. // Build conditions for active state, subscribed state and newsletter selection.
  822. if (isset($states['active'])) {
  823. $condition_active[] = 1;
  824. }
  825. if (isset($states['inactive'])) {
  826. $condition_active[] = 0;
  827. }
  828. if (isset($subscribed['subscribed'])) {
  829. $condition_subscribed[] = 1;
  830. }
  831. if (isset($subscribed['unsubscribed'])) {
  832. $condition_subscribed[] = 0;
  833. }
  834. // Get emails from the database.
  835. $query = db_select('simplenews_subscriber', 'ss');
  836. $query->innerJoin('simplenews_subscription', 'si', 'si.snid = ss.snid');
  837. $query->fields('ss', array('mail'))
  838. ->condition('ss.activated', $condition_active)
  839. ->condition('si.status', $condition_subscribed)
  840. ->condition('si.tid', $newsletters)
  841. ->distinct();
  842. $mails = $query->execute()->fetchCol(0);
  843. // Return comma separated array of emails or empty text.
  844. if ($mails) {
  845. return implode(", ", $mails);
  846. }
  847. return t('No addresses were found.');
  848. }
  849. /**
  850. * Menu callback: Mass subscribe to newsletters.
  851. *
  852. * @see simplenews_subscription_list_remove_submit()
  853. *
  854. * @todo Add 32char description field as unsubsription source
  855. */
  856. function simplenews_subscription_list_remove($form, &$form_state) {
  857. $form['emails'] = array(
  858. '#type' => 'textarea',
  859. '#title' => t('Email addresses'),
  860. '#cols' => 60,
  861. '#rows' => 5,
  862. '#description' => t('Email addresses must be separated by comma, space or newline.'),
  863. );
  864. $form['newsletters'] = array(
  865. '#type' => 'fieldset',
  866. '#description' => t('Unsubscribe from'),
  867. '#tree' => TRUE,
  868. );
  869. foreach (simplenews_categories_load_multiple() as $category) {
  870. $form['newsletters'][$category->tid] = array(
  871. '#type' => 'checkbox',
  872. '#title' => check_plain(_simplenews_newsletter_name($category)),
  873. '#description' => _simplenews_newsletter_description($category),
  874. );
  875. }
  876. $form['submit'] = array(
  877. '#type' => 'submit',
  878. '#value' => t('Unsubscribe'),
  879. );
  880. return $form;
  881. }
  882. /**
  883. * @todo
  884. */
  885. function simplenews_subscription_list_remove_submit($form, &$form_state) {
  886. $removed = array();
  887. $invalid = array();
  888. $checked_lists = array_keys(array_filter($form_state['values']['newsletters']));
  889. $emails = preg_split("/[\s,]+/", $form_state['values']['emails']);
  890. foreach ($emails as $email) {
  891. $email = trim($email);
  892. if (valid_email_address($email)) {
  893. foreach ($checked_lists as $tid) {
  894. simplenews_unsubscribe_user($email, $tid, FALSE, 'mass unsubscribe');
  895. $removed[] = $email;
  896. }
  897. }
  898. else {
  899. $invalid[] = $email;
  900. }
  901. }
  902. if ($removed) {
  903. $removed = implode(", ", $removed);
  904. drupal_set_message(t('The following addresses were unsubscribed: %removed.', array('%removed' => $removed)));
  905. $lists = simplenews_categories_load_multiple();
  906. $list_names = array();
  907. foreach ($checked_lists as $tid) {
  908. $list_names[] = _simplenews_newsletter_name($lists[$tid]);
  909. }
  910. drupal_set_message(t('The addresses were unsubscribed from the following newsletters: %newsletters.', array('%newsletters' => implode(', ', $list_names))));
  911. }
  912. else {
  913. drupal_set_message(t('No addresses were removed.'));
  914. }
  915. if ($invalid) {
  916. $invalid = implode(", ", $invalid);
  917. drupal_set_message(t('The following addresses were invalid: %invalid.', array('%invalid' => $invalid)), 'error');
  918. }
  919. // Return to the parent page.
  920. $form_state['redirect'] = 'admin/people/simplenews';
  921. }
  922. /**
  923. * Menu callback: subscription administration.
  924. */
  925. function simplenews_admin_subscription() {
  926. // @todo Fix the delete operation
  927. $form['filter'] = simplenews_subscription_filter_form();
  928. $form['#submit'][] = 'simplenews_subscription_filter_form_submit';
  929. $form['filter']['#theme'] = 'simplenews_filter_form';
  930. $form['admin'] = simplenews_subscription_list_form();
  931. return $form;
  932. }
  933. /**
  934. * Menu callback: subscription administration.
  935. *
  936. * @see simplenews_subscription_list_form_validate()
  937. * @see simplenews_subscription_list_form_submit()
  938. *
  939. * @todo Subscriber maintanance needs overhaul now we have more data availabale.
  940. */
  941. function simplenews_subscription_list_form() {
  942. // Build an 'Update options' form.
  943. $form['options'] = array(
  944. '#type' => 'fieldset',
  945. '#title' => t('Update options'),
  946. '#prefix' => '<div class="container-inline">',
  947. '#suffix' => '</div>',
  948. );
  949. $options = array();
  950. foreach (module_invoke_all('simplenews_subscription_operations') as $operation => $array) {
  951. $options[$operation] = $array['label'];
  952. }
  953. $form['options']['operation'] = array(
  954. '#type' => 'select',
  955. '#options' => $options,
  956. '#default_value' => 'activate',
  957. );
  958. $form['options']['submit'] = array(
  959. '#type' => 'submit',
  960. '#value' => t('Update'),
  961. '#submit' => array('simplenews_subscription_list_form_submit'),
  962. '#validate' => array('simplenews_subscription_list_form_validate'),
  963. );
  964. // Table header. Used as tablesort default
  965. $header = array(
  966. 'mail' => array('data' => t('Email'), 'field' => 'sn.mail', 'sort' => 'asc'),
  967. 'username' => array('data' => t('Username'), 'field' => 'u.name'),
  968. 'status' => array('data' => t('Status'), 'field' => 'sn.activated'),
  969. 'language' => array('data' => t('Language'), 'field' => 'sn.language'),
  970. 'operations' => array('data' => t('Operations')),
  971. );
  972. $query = db_select('simplenews_subscriber', 'sn')->extend('PagerDefault')->extend('TableSort');
  973. simplenews_build_subscription_filter_query($query);
  974. $query->leftJoin('users', 'u', 'sn.uid = u.uid');
  975. $query->innerJoin('simplenews_subscription', 'su', 'sn.snid = su.snid');
  976. $query->condition('su.status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED);
  977. $query->addField('u', 'name', 'name');
  978. $result = $query
  979. ->fields('sn', array('snid', 'activated', 'mail', 'uid', 'language'))
  980. ->limit(30)
  981. ->orderByHeader($header)
  982. ->execute();
  983. $options = array();
  984. $destination = drupal_get_destination();
  985. foreach ($result as $subscriber) {
  986. $options[$subscriber->snid] = array(
  987. 'mail' => $subscriber->mail,
  988. 'username' => isset($subscriber->uid) ? l($subscriber->name, 'user/' . $subscriber->uid) : check_plain($subscriber->name),
  989. 'status' => theme('simplenews_status', array('source' => 'activated', 'status' => $subscriber->activated)),
  990. 'language' => check_plain($subscriber->language),
  991. 'operations' => l(t('edit'), 'admin/people/simplenews/users/edit/' . $subscriber->snid, array(), $destination),
  992. );
  993. }
  994. $form['subscribers'] = array(
  995. '#type' => 'tableselect',
  996. '#header' => $header,
  997. '#options' => $options,
  998. '#empty' => t('No subscribers available.'),
  999. );
  1000. $form['pager'] = array(
  1001. // Calling theme('pager') directly so that it the first call after the
  1002. // pager query executed above.
  1003. '#markup' => theme('pager'),
  1004. );
  1005. return $form;
  1006. }
  1007. /**
  1008. * Implements hook_simplenews_subscription_operations().
  1009. */
  1010. function simplenews_simplenews_subscription_operations() {
  1011. $operations = array(
  1012. 'activate' => array(
  1013. 'label' => t('Activate'),
  1014. 'callback' => 'simplenews_subscription_activate',
  1015. 'callback arguments' => array(SIMPLENEWS_SUBSCRIPTION_ACTIVE),
  1016. ),
  1017. 'inactivate' => array(
  1018. 'label' => t('Inactivate'),
  1019. 'callback' => 'simplenews_subscription_activate',
  1020. 'callback arguments' => array(SIMPLENEWS_SUBSCRIPTION_INACTIVE),
  1021. ),
  1022. 'delete' => array(
  1023. 'label' => t('Delete'),
  1024. 'callback' => 'simplenews_subscription_delete_multiple',
  1025. ),
  1026. );
  1027. return $operations;
  1028. }
  1029. /**
  1030. * @todo
  1031. */
  1032. function simplenews_subscription_list_form_validate($form, &$form_state) {
  1033. if (isset($form_state['values']['operation'])) {
  1034. $snids = array_keys(array_filter($form_state['values']['subscribers']));
  1035. if (empty($snids)) {
  1036. form_set_error('', t('No items selected.'));
  1037. }
  1038. }
  1039. }
  1040. /**
  1041. * @todo
  1042. */
  1043. function simplenews_subscription_list_form_submit($form, &$form_state) {
  1044. // Call operation functions as defined in hook_simplenews_subscription_operations().
  1045. $operations = module_invoke_all('simplenews_subscription_operations');
  1046. $operation = $operations[$form_state['values']['operation']];
  1047. // Filter out unchecked subscribers
  1048. $snids = array_filter($form_state['values']['subscribers']);
  1049. if ($function = $operation['callback']) {
  1050. // Add in callback arguments if present.
  1051. if (isset($operation['callback arguments'])) {
  1052. $args = array_merge(array($snids), $operation['callback arguments']);
  1053. }
  1054. else {
  1055. $args = array($snids);
  1056. }
  1057. call_user_func_array($function, $args);
  1058. drupal_set_message(t('The update has been performed.'));
  1059. }
  1060. else {
  1061. // We need to rebuild the form to go to a second step. For example, to
  1062. // show the confirmation form for the deletion of nodes.
  1063. $form_state['rebuild'] = TRUE;
  1064. }
  1065. }
  1066. /**
  1067. * Callback function to (de-)activate subscriptions.
  1068. *
  1069. * @param $snids
  1070. * Array of snid's to be activated.
  1071. * @param $status
  1072. * Status of the subscription (0, 1).
  1073. */
  1074. function simplenews_subscription_activate($snids, $status) {
  1075. foreach ($snids as $snid) {
  1076. $subscriber = simplenews_subscriber_load($snid);
  1077. $subscriber->activated = $status;
  1078. simplenews_subscriber_save($subscriber);
  1079. }
  1080. }
  1081. /**
  1082. * Callback function to delete subscriptions.
  1083. *
  1084. * @param $snids
  1085. * Array of snid's to be deleted.
  1086. */
  1087. function simplenews_subscription_delete_multiple($snids = array()) {
  1088. foreach ($snids as $snid) {
  1089. // Delete Subscription
  1090. simplenews_subscription_delete(array('snid' => $snid));
  1091. // Delete subscriber
  1092. $subscriber = simplenews_subscriber_load($snid);
  1093. simplenews_subscriber_delete($subscriber);
  1094. }
  1095. }
  1096. /**
  1097. * Menu callback: Simplenews admin settings - Newsletter.
  1098. */
  1099. function simplenews_admin_settings_newsletter($form, &$form_state) {
  1100. $address_default = variable_get('site_mail', ini_get('sendmail_from'));
  1101. $form = array();
  1102. $form['simplenews_default_options'] = array(
  1103. '#type' => 'fieldset',
  1104. '#title' => t('Default newsletter options'),
  1105. '#collapsible' => FALSE,
  1106. '#description' => t('These options will be the defaults for new newsletters, but can be overridden in the newsletter editing form.'),
  1107. );
  1108. $links = array('!mime_mail_url' => 'http://drupal.org/project/mimemail', '!html_url' => 'http://drupal.org/project/htmlmail');
  1109. $description = t('Default newsletter format. Install <a href="!mime_mail_url">Mime Mail</a> module or <a href="!html_url">HTML Mail</a> module to send newsletters in HTML format.', $links);
  1110. $form['simplenews_default_options']['simplenews_format'] = array(
  1111. '#type' => 'select',
  1112. '#title' => t('Format'),
  1113. '#options' => simplenews_format_options(),
  1114. '#description' => $description,
  1115. '#default_value' => variable_get('simplenews_format', 'plain'),
  1116. );
  1117. // @todo Do we need these master defaults for 'priority' and 'receipt'?
  1118. $form['simplenews_default_options']['simplenews_priority'] = array(
  1119. '#type' => 'select',
  1120. '#title' => t('Priority'),
  1121. '#options' => simplenews_get_priority(),
  1122. '#description' => t('Note that email priority is ignored by a lot of email programs.'),
  1123. '#default_value' => variable_get('simplenews_priority', SIMPLENEWS_PRIORITY_NONE),
  1124. );
  1125. $form['simplenews_default_options']['simplenews_receipt'] = array(
  1126. '#type' => 'checkbox',
  1127. '#title' => t('Request receipt'),
  1128. '#default_value' => variable_get('simplenews_receipt', 0),
  1129. '#description' => t('Request a Read Receipt from your newsletters. A lot of email programs ignore these so it is not a definitive indication of how many people have read your newsletter.'),
  1130. );
  1131. $form['simplenews_default_options']['simplenews_send'] = array(
  1132. '#type' => 'radios',
  1133. '#title' => t('Default send action'),
  1134. '#options' => array(
  1135. SIMPLENEWS_COMMAND_SEND_TEST => t('Send one test newsletter to the test address'),
  1136. SIMPLENEWS_COMMAND_SEND_NOW => t('Send newsletter'),
  1137. ),
  1138. '#default_value' => variable_get('simplenews_send', 0),
  1139. );
  1140. $form['simplenews_test_address'] = array(
  1141. '#type' => 'fieldset',
  1142. '#title' => t('Test addresses'),
  1143. '#collapsible' => FALSE,
  1144. '#description' => t('Supply a comma-separated list of email addresses to be used as test addresses. The override function allows to override these addresses in the newsletter editing form.'),
  1145. );
  1146. $form['simplenews_test_address']['simplenews_test_address'] = array(
  1147. '#type' => 'textfield',
  1148. '#title' => t('Email address'),
  1149. '#size' => 60,
  1150. '#maxlength' => 128,
  1151. '#default_value' => variable_get('simplenews_test_address', $address_default),
  1152. );
  1153. $form['simplenews_test_address']['simplenews_test_address_override'] = array(
  1154. '#type' => 'checkbox',
  1155. '#title' => t('Allow test address override'),
  1156. '#default_value' => variable_get('simplenews_test_address_override', 0),
  1157. );
  1158. $form['simplenews_sender_info'] = array(
  1159. '#type' => 'fieldset',
  1160. '#title' => t('Sender information'),
  1161. '#collapsible' => FALSE,
  1162. '#description' => t('Default sender address that will only be used for confirmation emails. You can specify sender information for each newsletter separately on the newsletter\'s settings page.'),
  1163. );
  1164. $form['simplenews_sender_info']['simplenews_from_name'] = array(
  1165. '#type' => 'textfield',
  1166. '#title' => t('From name'),
  1167. '#size' => 60,
  1168. '#maxlength' => 128,
  1169. '#default_value' => variable_get('simplenews_from_name', variable_get('site_name', 'Drupal')),
  1170. );
  1171. $form['simplenews_sender_info']['simplenews_from_address'] = array(
  1172. '#type' => 'textfield',
  1173. '#title' => t('From email address'),
  1174. '#size' => 60,
  1175. '#maxlength' => 128,
  1176. '#required' => TRUE,
  1177. '#default_value' => variable_get('simplenews_from_address', $address_default),
  1178. );
  1179. return system_settings_form($form);
  1180. }
  1181. /**
  1182. * @todo
  1183. */
  1184. function simplenews_admin_settings_newsletter_validate($form, &$form_state) {
  1185. if (!valid_email_address($form_state['values']['simplenews_from_address'])) {
  1186. form_set_error($field_name, t("The sender's email address you supplied is not valid."));
  1187. }
  1188. }
  1189. /**
  1190. * Menu callback: Simplenews admin settings - Email.
  1191. */
  1192. function simplenews_admin_settings_mail($form, &$form_state) {
  1193. $address_default = variable_get('site_mail', ini_get('sendmail_from'));
  1194. $form = array();
  1195. $form['simplenews_mail_backend']['simplenews_use_cron'] = array(
  1196. '#type' => 'checkbox',
  1197. '#title' => t('Use cron to send newsletters'),
  1198. '#default_value' => variable_get('simplenews_use_cron', TRUE),
  1199. '#description' => t('When checked cron will be used to send newsletters (recommended). Test newsletters and confirmation emails will be sent immediately. Leave unchecked for testing purposes.'),
  1200. );
  1201. $sources = simplenews_get_source_caches();
  1202. $sources_labels = array();
  1203. $sources_descriptions = '';
  1204. foreach ($sources as $name => $source) {
  1205. $sources_labels[$name] = $source['label'];
  1206. $sources_descriptions .= t('<strong>@label</strong>: @description <br />', array('@label' => $source['label'], '@description' => $source['description']));
  1207. }
  1208. $form['simplenews_mail_backend']['simplenews_source_cache'] = array(
  1209. '#type' => 'select',
  1210. '#title' => t('Cache'),
  1211. '#description' => t('Chosing a different cache implementation allows for a different behavior during sending mails.') . '<br /><br />' . $sources_descriptions,
  1212. '#options' => $sources_labels,
  1213. '#default_value' => variable_get('simplenews_source_cache', 'SimplenewsSourceCacheBuild'),
  1214. );
  1215. $throttle = drupal_map_assoc(array(1, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000));
  1216. $throttle[SIMPLENEWS_UNLIMITED] = t('Unlimited');
  1217. if (function_exists('getrusage')) {
  1218. $description_extra = '<br />' . t('Cron execution must not exceed the PHP maximum execution time of %max seconds. You find the time spend to send emails in the <a href="/admin/reports/dblog">Recent log entries</a>.', array('%max' => ini_get('max_execution_time')));
  1219. }
  1220. else {
  1221. $description_extra = '<br />' . t('Cron execution must not exceed the PHP maximum execution time of %max seconds.', array('%max' => ini_get('max_execution_time')));
  1222. }
  1223. $form['simplenews_mail_backend']['simplenews_throttle'] = array(
  1224. '#type' => 'select',
  1225. '#title' => t('Cron throttle'),
  1226. '#options' => $throttle,
  1227. '#default_value' => variable_get('simplenews_throttle', 20),
  1228. '#description' => t('Sets the numbers of newsletters sent per cron run. Failure to send will also be counted.') . $description_extra,
  1229. );
  1230. $form['simplenews_mail_backend']['simplenews_spool_expire'] = array(
  1231. '#type' => 'select',
  1232. '#title' => t('Mail spool expiration'),
  1233. '#options' => array(
  1234. 0 => t('Immediate'),
  1235. 1 => t('1 day'),
  1236. 7 => t('1 week'),
  1237. 14 => t('2 weeks'),
  1238. ),
  1239. '#default_value' => variable_get('simplenews_spool_expire', 0),
  1240. '#description' => t('Newsletter mails are spooled. How long must messages be retained in the spool after successful sending. Keeping the message in the spool allows mail statistics (which is not yet implemented). If cron is not used, immediate expiration is advised.'),
  1241. );
  1242. $form['simplenews_mail_backend']['simplenews_debug'] = array(
  1243. '#type' => 'checkbox',
  1244. '#title' => t('Log emails'),
  1245. '#default_value' => variable_get('simplenews_debug', FALSE),
  1246. '#description' => t('When checked all outgoing simplenews emails are logged in the system log. A logged email does not guarantee that it is send or will be delivered. It only indicates that a message is sent to the PHP mail() function. No status information is available of delivery by the PHP mail() function.'),
  1247. );
  1248. return system_settings_form($form);
  1249. }
  1250. /**
  1251. * Menu callback: Simplenews admin settings - Subscription.
  1252. */
  1253. function simplenews_admin_settings_subscription($form, &$form_state) {
  1254. $address_default = variable_get('site_mail', ini_get('sendmail_from'));
  1255. $form = array();
  1256. $form['account'] = array(
  1257. '#type' => 'fieldset',
  1258. '#title' => t('User account'),
  1259. '#collapsible' => FALSE,
  1260. );
  1261. $form['account']['simplenews_sync_account'] = array(
  1262. '#type' => 'checkbox',
  1263. '#title' => t('Synchronize with account'),
  1264. '#default_value' => variable_get('simplenews_sync_account', TRUE),
  1265. '#description' => t('When checked subscriptions will be synchronized with site accounts. When accounts are deleted, subscriptions with the same email address will be removed. When site accounts are blocked/unblocked, subscriptions will be deactivated/activated. When not checked subscriptions will be unchanged when associated accounts are deleted or blocked.'),
  1266. );
  1267. $form['subscription_mail'] = array(
  1268. '#type' => 'fieldset',
  1269. '#title' => t('Confirmation emails'),
  1270. '#collapsible' => FALSE,
  1271. );
  1272. $form['subscription_mail']['simplenews_use_combined'] = array(
  1273. '#type' => 'select',
  1274. '#title' => t('Use combined confirmation mails'),
  1275. '#options' => array(
  1276. 'multiple' => t('For multiple changes'),
  1277. 'always' => t('Always'),
  1278. 'never' => t('Never'),
  1279. ),
  1280. '#description' => t('Combined confirmation mails allow subscribers to confirm multiple newsletter changes with single mail.'),
  1281. '#default_value' => variable_get('simplenews_use_combined', 'multiple'),
  1282. );
  1283. if (module_exists('token')) {
  1284. $form['subscription_mail']['token_help'] = array(
  1285. '#title' => t('Replacement patterns'),
  1286. '#type' => 'fieldset',
  1287. '#collapsible' => TRUE,
  1288. '#collapsed' => TRUE,
  1289. );
  1290. $form['subscription_mail']['token_help']['browser'] = array(
  1291. '#theme' => 'token_tree',
  1292. '#token_types' => array('simplenews-category', 'simplenews-subscriber'),
  1293. );
  1294. }
  1295. $form['subscription_mail']['single'] = array(
  1296. '#type' => 'fieldset',
  1297. '#title' => t('Single confirmation mails'),
  1298. '#collapsed' => TRUE,
  1299. '#collapsible' => TRUE,
  1300. '#states' => array(
  1301. 'invisible' => array(
  1302. ':input[name="simplenews_use_combined"]' => array(
  1303. 'value' => 'always',
  1304. ),
  1305. ),
  1306. ),
  1307. );
  1308. $form['subscription_mail']['single']['simplenews_confirm_subscribe_subject'] = array(
  1309. '#type' => 'textfield',
  1310. '#title' => t('Subject'),
  1311. '#default_value' => simplenews_subscription_confirmation_text('subscribe_subject'),
  1312. '#maxlength' => 180,
  1313. );
  1314. $form['subscription_mail']['single']['simplenews_confirm_subscribe_unsubscribed'] = array(
  1315. '#type' => 'textarea',
  1316. '#title' => t('Body text of subscribe email'),
  1317. '#default_value' => simplenews_subscription_confirmation_text('subscribe_unsubscribed'),
  1318. '#rows' => 5,
  1319. );
  1320. $form['subscription_mail']['single']['simplenews_confirm_subscribe_subscribed'] = array(
  1321. '#type' => 'textarea',
  1322. '#title' => t('Body text for already subscribed visitor'),
  1323. '#default_value' => simplenews_subscription_confirmation_text('subscribe_subscribed'),
  1324. '#rows' => 5,
  1325. );
  1326. $form['subscription_mail']['single']['simplenews_confirm_unsubscribe_subscribed'] = array(
  1327. '#type' => 'textarea',
  1328. '#title' => t('Body text of unsubscribe email'),
  1329. '#default_value' => simplenews_subscription_confirmation_text('unsubscribe_subscribed'),
  1330. '#rows' => 5,
  1331. );
  1332. $form['subscription_mail']['single']['simplenews_confirm_unsubscribe_unsubscribed'] = array(
  1333. '#type' => 'textarea',
  1334. '#title' => t('Body text for not yet subscribed visitor'),
  1335. '#default_value' => simplenews_subscription_confirmation_text('unsubscribe_unsubscribed'),
  1336. '#rows' => 5,
  1337. );
  1338. $form['subscription_mail']['combined'] = array(
  1339. '#type' => 'fieldset',
  1340. '#title' => t('Combined confirmation mails'),
  1341. '#collapsed' => TRUE,
  1342. '#collapsible' => TRUE,
  1343. '#states' => array(
  1344. 'invisible' => array(
  1345. ':input[name="simplenews_use_combined"]' => array(
  1346. 'value' => 'never',
  1347. ),
  1348. ),
  1349. ),
  1350. );
  1351. $form['subscription_mail']['combined']['simplenews_confirm_combined_subject'] = array(
  1352. '#type' => 'textfield',
  1353. '#title' => t('Subject text for combined confirmation mail'),
  1354. '#default_value' => simplenews_subscription_confirmation_text('combined_subject'),
  1355. );
  1356. $form['subscription_mail']['combined']['simplenews_confirm_combined_body'] = array(
  1357. '#type' => 'textarea',
  1358. '#title' => t('Body text for combined confirmation mail'),
  1359. '#default_value' => simplenews_subscription_confirmation_text('combined_body'),
  1360. '#rows' => 5,
  1361. );
  1362. $form['subscription_mail']['combined']['simplenews_confirm_combined_body_unchanged'] = array(
  1363. '#type' => 'textarea',
  1364. '#title' => t('Body text for unchanged combined confirmation mail'),
  1365. '#default_value' => simplenews_subscription_confirmation_text('combined_body_unchanged'),
  1366. '#rows' => 5,
  1367. '#description' => t('This body is used when there are no change requests which have no effect, e.g trying to subscribe when already being subscribed to a category.')
  1368. );
  1369. $form['subscription_mail']['combined']['simplenews_confirm_combined_line_subscribe_unsubscribed'] = array(
  1370. '#type' => 'textfield',
  1371. '#title' => t('Change text for a new subscription'),
  1372. '#default_value' => simplenews_subscription_confirmation_text('combined_line_subscribe_unsubscribed'),
  1373. );
  1374. $form['subscription_mail']['combined']['simplenews_confirm_combined_line_subscribe_subscribed'] = array(
  1375. '#type' => 'textfield',
  1376. '#title' => t('Change text when already subscribed'),
  1377. '#default_value' => simplenews_subscription_confirmation_text('combined_line_subscribe_subscribed'),
  1378. );
  1379. $form['subscription_mail']['combined']['simplenews_confirm_combined_line_unsubscribe_subscribed'] = array(
  1380. '#type' => 'textfield',
  1381. '#title' => t('Change text for an unsubscription'),
  1382. '#default_value' => simplenews_subscription_confirmation_text('combined_line_unsubscribe_subscribed'),
  1383. );
  1384. $form['subscription_mail']['combined']['simplenews_confirm_combined_line_unsubscribe_unsubscribed'] = array(
  1385. '#type' => 'textfield',
  1386. '#title' => t('Change text when already unsubscribed'),
  1387. '#default_value' => simplenews_subscription_confirmation_text('combined_line_unsubscribe_unsubscribed'),
  1388. );
  1389. $form['confirm_pages'] = array(
  1390. '#type' => 'fieldset',
  1391. '#title' => t('Confirmation pages'),
  1392. '#collapsible' => FALSE,
  1393. );
  1394. $form['confirm_pages']['simplenews_confirm_subscribe_page'] = array(
  1395. '#type' => 'textfield',
  1396. '#title' => t('Subscribe confirmation'),
  1397. '#description' => t('Drupal path or URL of the destination page where after the subscription is confirmed (e.g. node/123). Leave empty to go to the front page.'),
  1398. '#default_value' => variable_get('simplenews_confirm_subscribe_page', ''),
  1399. );
  1400. $form['simplenews_subscription']['confirm_pages']['simplenews_confirm_unsubscribe_page'] = array(
  1401. '#type' => 'textfield',
  1402. '#title' => t('Unsubscribe confirmation'),
  1403. '#description' => t('Drupal path or URL of the destination page when the subscription removal is confirmed (e.g. node/123). Leave empty to go to the front page.'),
  1404. '#default_value' => variable_get('simplenews_confirm_unsubscribe_page', ''),
  1405. );
  1406. return system_settings_form($form);
  1407. }
  1408. /**
  1409. * Generate subscription filters
  1410. */
  1411. function simplenews_subscription_filters() {
  1412. // Newsletter filter
  1413. $filters['list'] = array(
  1414. 'title' => t('Subscribed to'),
  1415. 'options' => array(
  1416. 'all' => t('All newsletters'),
  1417. ),
  1418. );
  1419. foreach (simplenews_categories_load_multiple() as $list) {
  1420. $filters['list']['options']['tid-' . $list->tid] = _simplenews_newsletter_name($list);
  1421. }
  1422. // Email filter
  1423. $filters['email'] = array(
  1424. 'title' => t('Email address'),
  1425. );
  1426. return $filters;
  1427. }
  1428. /**
  1429. * Return form for subscription filters.
  1430. *
  1431. * @see simplenews_subscription_filter_form_submit()
  1432. */
  1433. function simplenews_subscription_filter_form() {
  1434. // Current filter selections in $session var; stored at form submission
  1435. // Example: array('list' => 'all', 'email' => 'hotmail')
  1436. $session = isset($_SESSION['simplenews_subscriptions_filter']) ? $_SESSION['simplenews_subscriptions_filter'] : '';
  1437. $session = is_array($session) ? $session : _simplenews_subscription_filter_default();
  1438. $filters = simplenews_subscription_filters();
  1439. $form['filters'] = array(
  1440. '#type' => 'fieldset',
  1441. '#title' => t('Show only subscription which'),
  1442. '#collapsible' => FALSE,
  1443. );
  1444. // Filter values are default
  1445. $form['filters']['list'] = array(
  1446. '#type' => 'select',
  1447. '#title' => $filters['list']['title'],
  1448. '#options' => $filters['list']['options'],
  1449. '#default_value' => $session['list'],
  1450. );
  1451. $form['filters']['email'] = array(
  1452. '#type' => 'textfield',
  1453. '#title' => $filters['email']['title'],
  1454. '#default_value' => $session['email'],
  1455. );
  1456. $form['filters']['submit'] = array(
  1457. '#type' => 'submit',
  1458. '#value' => t('Filter'),
  1459. '#prefix' => '<span class="spacer" />',
  1460. );
  1461. // Add Reset button if filter is in use
  1462. if ($session != _simplenews_subscription_filter_default()) {
  1463. $form['filters']['reset'] = array(
  1464. '#type' => 'submit',
  1465. '#value' => t('Reset'),
  1466. );
  1467. }
  1468. return $form;
  1469. }
  1470. /**
  1471. * Helper function: returns subscription filter default settings
  1472. */
  1473. function _simplenews_subscription_filter_default() {
  1474. return array(
  1475. 'list' => 'all',
  1476. 'email' => '',
  1477. );
  1478. }
  1479. /**
  1480. * @todo
  1481. */
  1482. function simplenews_subscription_filter_form_submit($form, &$form_state) {
  1483. switch ($form_state['values']['op']) {
  1484. case t('Filter'):
  1485. $_SESSION['simplenews_subscriptions_filter'] = array(
  1486. 'list' => $form_state['values']['list'],
  1487. 'email' => $form_state['values']['email'],
  1488. );
  1489. break;
  1490. case t('Reset'):
  1491. $_SESSION['simplenews_subscriptions_filter'] = _simplenews_subscription_filter_default();
  1492. break;
  1493. }
  1494. }
  1495. /**
  1496. * Apply filters for subscription filters based on session.
  1497. *
  1498. * @param $query
  1499. * A SelectQuery to which the filters should be applied.
  1500. */
  1501. function simplenews_build_subscription_filter_query(SelectQueryInterface $query) {
  1502. if (isset($_SESSION['simplenews_subscriptions_filter'])) {
  1503. foreach ($_SESSION['simplenews_subscriptions_filter'] as $key => $value) {
  1504. switch ($key) {
  1505. case 'list':
  1506. if ($value != 'all') {
  1507. list($key, $value) = explode('-', $value, 2);
  1508. $query->condition('su.' . $key, $value);
  1509. }
  1510. break;
  1511. case 'email':
  1512. if (!empty($value)) {
  1513. $query->condition('sn.mail', '%' . $value . '%', 'LIKE');
  1514. }
  1515. break;
  1516. }
  1517. }
  1518. }
  1519. }
  1520. /**
  1521. * Count number of subscribers per newsletter list.
  1522. *
  1523. * @return number of subscribers.
  1524. */
  1525. function simplenews_count_subscriptions($tid) {
  1526. $subscription_count = &drupal_static(__FUNCTION__);
  1527. if (isset($subscription_count[$tid])) {
  1528. return $subscription_count[$tid];
  1529. }
  1530. $query = db_select('simplenews_subscription', 'ss');
  1531. $query->leftJoin('simplenews_subscriber', 'sn', 'sn.snid = ss.snid');
  1532. $query->condition('tid', $tid)
  1533. ->condition('sn.activated', 1)
  1534. ->condition('status', SIMPLENEWS_SUBSCRIPTION_STATUS_SUBSCRIBED);
  1535. $subscription_count[$tid] = $query->countQuery()->execute()->fetchField();
  1536. return $subscription_count[$tid];
  1537. }
  1538. /**
  1539. * Return a status image.
  1540. *
  1541. * @param $variables An associative array containing:
  1542. * source: Source which status will be displayed ('published', 'activated', 'sent')
  1543. * status: Status of the source (0 or 1)
  1544. *
  1545. * @return string
  1546. * HTML string containing an image tag.
  1547. *
  1548. * @ingroup theming
  1549. */
  1550. function theme_simplenews_status($variables) {
  1551. $source = $variables['source'];
  1552. $status = $variables['status'];
  1553. switch ($source) {
  1554. case 'published':
  1555. $images = array(
  1556. 0 => 'sn-saved.png',
  1557. 1 => 'sn-sent.png',
  1558. );
  1559. $title = array(
  1560. 0 => t('Not published'),
  1561. 1 => t('Published'),
  1562. );
  1563. break;
  1564. case 'activated':
  1565. $images = array(
  1566. 0 => 'sn-saved.png',
  1567. 1 => 'sn-sent.png',
  1568. );
  1569. $title = array(
  1570. 0 => t('Inactive: no newsletters will be sent'),
  1571. 1 => t('Active: user will receive newsletters'),
  1572. );
  1573. break;
  1574. case 'sent':
  1575. $images = array(
  1576. SIMPLENEWS_STATUS_SEND_PENDING => 'sn-cron.png',
  1577. SIMPLENEWS_STATUS_SEND_READY => 'sn-sent.png',
  1578. );
  1579. $title = array(
  1580. SIMPLENEWS_STATUS_SEND_NOT => t('Not yet sent'),
  1581. SIMPLENEWS_STATUS_SEND_PENDING => t('Currently sending by cron'),
  1582. SIMPLENEWS_STATUS_SEND_READY => t('Sent'),
  1583. SIMPLENEWS_STATUS_SEND_PUBLISH => t('Send on publish'),
  1584. );
  1585. break;
  1586. }
  1587. // Build the output
  1588. if (isset($images[$status])) {
  1589. $img_vars = array(
  1590. 'path' => drupal_get_path('module', 'simplenews') . '/' . $images[$status],
  1591. 'alt' => $title[$status],
  1592. 'title' => $title[$status],
  1593. 'getsize' => TRUE,
  1594. );
  1595. $output = theme('image', $img_vars);
  1596. }
  1597. else {
  1598. $output = check_plain($title[$status]);
  1599. }
  1600. return $output;
  1601. }
  1602. /**
  1603. * Theme simplenews issues and subscriptions filter form.
  1604. *
  1605. * @ingroup theming
  1606. */
  1607. function theme_simplenews_filter_form($variables) {
  1608. $form = $variables['form'];
  1609. $output = '<div id="simplenews-admin-filter">';
  1610. $output .= drupal_render($form['filters']);
  1611. $output .= '</div>';
  1612. $output .= drupal_render_children($form);
  1613. return $output;
  1614. }
  1615. /**
  1616. * Theme simplenews subscriptions administration filter form.
  1617. *
  1618. * @ingroup theming
  1619. */
  1620. function theme_simplenews_subscription_filter_form($variables) {
  1621. $form = $variables['form'];
  1622. $output = '<div id="simplenews-subscription-filter">';
  1623. $output .= drupal_render($form['filters']);
  1624. $output .= '</div>';
  1625. $output .= drupal_render_children($form);
  1626. return $output;
  1627. }
  1628. /**
  1629. * Function to provide the various simplenews mail priorities for newsletter categories
  1630. */
  1631. function simplenews_get_priority() {
  1632. return array(
  1633. SIMPLENEWS_PRIORITY_NONE => t('none'),
  1634. SIMPLENEWS_PRIORITY_HIGHEST => t('highest'),
  1635. SIMPLENEWS_PRIORITY_HIGH => t('high'),
  1636. SIMPLENEWS_PRIORITY_NORMAL => t('normal'),
  1637. SIMPLENEWS_PRIORITY_LOW => t('low'),
  1638. SIMPLENEWS_PRIORITY_LOWEST => t('lowest'),
  1639. );
  1640. }
  1641. /**
  1642. * Menu callback; Newsletter tab page.
  1643. */
  1644. function simplenews_node_tab_page($node){
  1645. drupal_set_title(t('<em>Newsletter</em> @title', array('@title' => $node->title)), PASS_THROUGH);
  1646. return drupal_get_form('simplenews_node_tab_send_form', $node);
  1647. }
  1648. /**
  1649. * @todo
  1650. */
  1651. function simplenews_node_tab_send_form($form, &$form_state, $node){
  1652. // First check if there already is a loaded simplenews object.
  1653. if (!empty($node->simplenews)) {
  1654. $simplenews_values = $node->simplenews;
  1655. }
  1656. // If not, try to load it based on the node id.
  1657. else if ($loaded = simplenews_newsletter_load($node->nid)) {
  1658. $simplenews_values = $loaded;
  1659. }
  1660. // If that fails too, fall back to the defaults.
  1661. else {
  1662. $simplenews_values = (object)_simplenews_get_node_form_defaults($node);
  1663. }
  1664. $form = array();
  1665. // We will need the node
  1666. $form['nid'] = array(
  1667. '#type' => 'value',
  1668. '#value' => $node->nid,
  1669. );
  1670. // @todo delete this fieldset?
  1671. $form['simplenews'] = array(
  1672. '#type' => 'fieldset',
  1673. '#title' => t('Send newsletter'),
  1674. '#collapsible' => FALSE,
  1675. '#collapsed' => FALSE,
  1676. '#tree' => TRUE,
  1677. );
  1678. // Translations of newsletters don't have the 'send' option. Only the
  1679. // translation source (and non translated) newsletters will get these options.
  1680. if (module_exists('translation') && translation_supported_type($node->type)
  1681. && (isset($node->translate) && ($node->tnid > 0) && ($node->tnid != $node->nid))) {
  1682. $form['simplenews']['#description'] = t('This newsletter issue is part of a translation set. Sending this set is controlled from the <a href="@link">translation source newsletter</a>.', array('@link' => url('node/' . $node->tnid)));
  1683. // @todo Translated nodes must also have the same Category!
  1684. // Move the category in here and give the user feedback.
  1685. }
  1686. else {
  1687. // Show newsletter sending options if newsletter has not been send yet.
  1688. // If send a notification is shown.
  1689. if ($simplenews_values->status == SIMPLENEWS_STATUS_SEND_NOT || $simplenews_values->status == SIMPLENEWS_STATUS_SEND_PUBLISH) {
  1690. $options = array(
  1691. SIMPLENEWS_COMMAND_SEND_TEST => t('Send one test newsletter to the test address'),
  1692. );
  1693. // Add option to send on publish when the node is unpublished.
  1694. if ($node->status == NODE_NOT_PUBLISHED) {
  1695. $options[SIMPLENEWS_COMMAND_SEND_PUBLISH] = t('Send newsletter when published');
  1696. }
  1697. else {
  1698. $options[SIMPLENEWS_COMMAND_SEND_NOW] = t('Send newsletter');
  1699. }
  1700. if ($simplenews_values->status == SIMPLENEWS_STATUS_SEND_PUBLISH) {
  1701. $send_default = SIMPLENEWS_STATUS_SEND_PUBLISH;
  1702. }
  1703. else {
  1704. $send_default = variable_get('simplenews_send', SIMPLENEWS_COMMAND_SEND_TEST);
  1705. }
  1706. $form['simplenews']['send'] = array(
  1707. '#type' => 'radios',
  1708. '#title' => t('Send newsletter'),
  1709. '#default_value' => isset($simplenews_values->send) ? $simplenews_values->send : $send_default,
  1710. '#options' => $options,
  1711. '#attributes' => array(
  1712. 'class' => array('simplenews-command-send'),
  1713. ),
  1714. );
  1715. $address_default = variable_get('site_mail', ini_get('sendmail_from'));
  1716. if (variable_get('simplenews_test_address_override', 0)) {
  1717. $form['simplenews']['test_address'] = array(
  1718. '#type' => 'textfield',
  1719. '#title' => t('Test email addresses'),
  1720. '#description' => t('A comma-separated list of email addresses to be used as test addresses.'),
  1721. '#default_value' => variable_get('simplenews_test_address', $address_default),
  1722. '#size' => 60,
  1723. '#maxlength' => 128,
  1724. );
  1725. }
  1726. else {
  1727. $form['simplenews']['test_address'] = array(
  1728. '#type' => 'value',
  1729. '#value' => variable_get('simplenews_test_address', $address_default),
  1730. );
  1731. }
  1732. }
  1733. else {
  1734. $form['simplenews']['none'] = array(
  1735. '#type' => 'checkbox',
  1736. '#return_value' => 0,
  1737. '#attributes' => array(
  1738. 'checked' => 'checked',
  1739. 'disabled' => 'disabled',
  1740. ),
  1741. );
  1742. $form['simplenews']['none']['#title'] = ($simplenews_values->status == SIMPLENEWS_STATUS_SEND_READY) ? t('This newsletter has been sent') : t('This newsletter is pending');
  1743. return $form;
  1744. }
  1745. $form['submit'] = array(
  1746. '#type' => 'submit',
  1747. '#value' => t('Submit'),
  1748. );
  1749. }
  1750. return $form;
  1751. }
  1752. /**
  1753. * @todo
  1754. */
  1755. function simplenews_node_tab_send_form_validate($form, &$form_state) {
  1756. $values = $form_state['values'];
  1757. $node = node_load($values['nid']);
  1758. $default_address = variable_get('simplenews_test_address', variable_get('site_mail', ini_get('sendmail_from')));
  1759. $mails = array($default_address);
  1760. if (isset($values['simplenews']['send']) && $values['simplenews']['send'] == SIMPLENEWS_COMMAND_SEND_TEST && variable_get('simplenews_test_address_override', 0)) {
  1761. // @todo Can we simplify and use only two kind of messages?
  1762. if (!empty($values['simplenews']['test_address'])) {
  1763. $mails = explode(',', $values['simplenews']['test_address']);
  1764. foreach ($mails as $mail) {
  1765. $mail = trim($mail);
  1766. if ($mail == '') {
  1767. form_set_error('simplenews][test_address', t('Test email address is empty.'));
  1768. }
  1769. elseif (!valid_email_address($mail)) {
  1770. form_set_error('simplenews][test_address', t('Invalid email address "%mail".', array('%mail' => $mail)));
  1771. }
  1772. }
  1773. }
  1774. else {
  1775. form_set_error('simplenews][test_address', t('Missing test email address.'));
  1776. }
  1777. }
  1778. $form_state['test_addresses'] = $mails;
  1779. }
  1780. /**
  1781. * @todo
  1782. */
  1783. function simplenews_node_tab_send_form_submit($form, &$form_state) {
  1784. $values = $form_state['values'];
  1785. $node = node_load($values['nid']);
  1786. // Send newsletter to all subscribers or send test newsletter
  1787. module_load_include('inc', 'simplenews', 'includes/simplenews.mail');
  1788. if ($values['simplenews']['send'] == SIMPLENEWS_COMMAND_SEND_NOW) {
  1789. simplenews_add_node_to_spool($node);
  1790. // Attempt to send immediatly, if configured to do so.
  1791. if (simplenews_mail_attempt_immediate_send(array('nid' => $node->nid))) {
  1792. drupal_set_message(t('Newsletter %title sent.', array('%title' => $node->title)));
  1793. }
  1794. else {
  1795. drupal_set_message(t('Newsletter %title pending.', array('%title' => $node->title)));
  1796. }
  1797. }
  1798. elseif ($values['simplenews']['send'] == SIMPLENEWS_COMMAND_SEND_TEST) {
  1799. simplenews_send_test($node, $form_state['test_addresses']);
  1800. }
  1801. // If the selected command is send on publish, just set the newsletter status.
  1802. if ($values['simplenews']['send'] == SIMPLENEWS_COMMAND_SEND_PUBLISH) {
  1803. $newsletter = simplenews_newsletter_load($node->nid);
  1804. if (!$newsletter) {
  1805. $newsletter = simplenews_newsletter_defaults($node);
  1806. }
  1807. $newsletter->status = SIMPLENEWS_STATUS_SEND_PUBLISH;
  1808. simplenews_newsletter_save($newsletter);
  1809. drupal_set_message(t('The newsletter will be sent when the content is published.'));
  1810. }
  1811. }