File/program/modules/newsletter/newsletter_admin.php

Description

/program/modules/newsletter/newsletter_admin.php - management interface for newsletter-module

This file defines the administrative interface to this module. The interface consists of the following four functions.

    newsletter_disconnect(&$output,$area_id,$node_id,$module) newsletter_connect(&$output,$area_id,$node_id,$module) newsletter_show_edit(&$output,$area_id,$node_id,$module,$viewonly,$edit_again,$href,$option) newsletter_save(&$output,$area_id,$node_id,$module,$viewonly,&$edit_again,$option)

These functions are called from pagemanagerlib.php whenever necessary.

Includes
 require_once (dirname(__FILE__)."/newsletter_common.php") (line 39)
Functions
newsletter_add_related (line 4456)

add the file in path as a related attachment to the email being built

note: mimetype of $filename becomes application/octet-stream with disposition = attachment if we cannot determine the mimetype

  • return: the content-id of the related attachment or FALSE on error
string newsletter_add_related (object &$mailer, string $filename)
  • object &$mailer: builds the email message with (related) attachments
  • string $filename: identifies the local file to add
newsletter_body2text (line 4543)

convert the body of an HTML-document to text

this routine tries to convert the HTML in $body into plain text while maintaining as much as possible of the layout.

The HTML can contain links '<a href="...">' and images '<img src="...">'. For local files we already established CID's (see newsletter_urls2cids()) and we know that those files are to be found in the body. In order to reduce the work, we first convert all those tags into the string '[ATTACHMENT:$href]'.

Next step is to replace the other A- and IMG-tags to their href|src.

Finally we use a heuristic approach to replace a subset of all HTML tags with a more or less readable translation. This can certainly be improved upon.

string newsletter_body2text (string $body, array &$cids)
  • string $body: holds the body of an HTML page (newsletter)
  • array &$cids: holds a list of mappings between a local path and a CID
newsletter_compose_get_dialogdef (line 1558)

construct a dialog definition for a newsletter article (add/edit)

this constructs a dialog definition which handles adding and editing articles In the case of adding a new article we start with empty fields (mostly), otherwise we attempt to load the existing data from the DB.

If the article_id is 0 we are adding a new article. In that case the name and the email address of the current user are automatically added. Note that the email field is write-once: we do want to record the initial value but it is not supposed to change; we want to keep a contact address for the author of the article, at least while the article exists in the articles table (the record will be deleted once an issue is officially published).

  • return: dialog definition
array newsletter_compose_get_dialogdef (int $node_id, int $viewonly, int $article_id)
  • int $node_id: identifies the current newsletter
  • int $viewonly: if TRUE the Save button is not displayed and values cannot be changed
  • int $article_id: identifies the article, 0 for a new one
newsletter_compose_get_dialogdef_delete (line 1667)

construct a dialog definition for deletion of an article

this constructs a dialog definition which handles deleting of an article.

  • return: dialog definition
array newsletter_compose_get_dialogdef_delete (int $viewonly)
  • int $viewonly: if TRUE the Delete button is not displayed
newsletter_compose_move (line 1256)

swap two articles in the list of ((de)selected) articles

this swaps two adjacent articles, effectively moving article $article_id up (or down) a position within the list. If the article is already at the end/begin of the list nothing happens.

  • return: TRUE on success, FALSE otherwise
bool newsletter_compose_move (int $node_id, int $article_id, bool $reverse)
  • int $node_id: identifies the newsletter
  • int $article_id: is the article that needs to be moved
  • bool $reverse: TRUE=move up in the list, FALSE is move down
newsletter_compose_new_sort_order (line 1691)

calculate a new sort order based on the current values of available articles in this newsletter

note that as a rule the new sort order is negative for unselected articles and positive for selected articles. Also, none of the existing sort_orders are touched or modified here because know that eventually the selected articles are 'eaten' once they are incorporated into a newsletter issue.

  • return: a new sort order
int newsletter_compose_new_sort_order (int $newsletter_id, [bool $selected = TRUE], [bool $first = FALSE])
  • int $newsletter_id: identifies the newsletter
  • bool $selected: identifies which list to add to
  • bool $first: if TRUE, the article is inserted at the top of the list, FALSE is append at the end
newsletter_compose_save (line 1324)

handle saving & deleting of articles

this handles all actual article add/edit/delete actions. criterion for delete is the existence of the delete-parameter (which identifies the article to delete), the criterion for edit/add is the article-parameter.

Part of the logic handling the [Cancel] button is done here too (see also newsletter_compose_show_edit()).

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_save (object &$output, int $node_id, bool $viewonly,  &$edit_again, bool $edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node alias the newsletter
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • &$edit_again
newsletter_compose_show (line 758)

dispatcher for displaying newsletter composition dialogs

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show (object &$output, int $node_id, array $module, bool $viewonly,  $edit_again, string $href, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
  • $edit_again
newsletter_compose_show_add (line 1064)

show the dialog for adding a new article

actual work is done in newsletter_compose_show_edit() but with article_id set to 0 instead of a valid, existing article_id.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show_add (object &$output, int $node_id, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • bool $viewonly: if TRUE, adding/editing is not allowed (but simply showing the content is)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_compose_show_delete (line 1154)

show a delete confirmation dialog

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show_delete (object &$output, int $node_id, int $article_id, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • int $article_id: identifies the article to edit (0 means add a new article dialog)
  • bool $viewonly: if TRUE, adding/editing is not allowed (but simply showing the content is)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_compose_show_edit (line 1101)

show dialog for editing (or adding) an article

this displays the edit dialog for articles. It is also used by newsletter_compose_show_add() with article_id = 0.

This dialog usually ends with three buttons: [Save] - saves the current article and edits again [Done] - save the article and return to the list of articles [Cancel] - don't save and return to the list of articles This poses a little problem when a new article is added and the user clicks [Save]; there is no elegant way to convey the new article_id (which was 0 in the add article dialog) to the routine that subsequently edits the newly added article. The (ugly) work around is to set the global $newsletter_new_article_id in the save routine and pick up the new value here.

Also part of the logic to deal with [Cancel] is handled here; the [Cancel]-button in this Add/Edit dialog (and the Delete dialog in newsletter_compose_show_delete() for that matter) should return to the list of articles, whereas the [Cancel] button in the list of articles should lead to the content overview in .

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show_edit (object &$output, int $node_id, int $article_id, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • int $article_id: identifies the article to edit (0 means add a new article dialog)
  • bool $viewonly: if TRUE, adding/editing is not allowed (but simply showing the content is)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_compose_show_list (line 841)

create the main newsletter compose screen

Display a list of currently selected articles followed by a list of currently unselected articles.

$newslettertitle (volume $volume number $number)

                 Add an article

Currently selected articles

[D] [F]     [L] Article title
[D] [F] [H] [L] Article title 
    ...
[D] [F] [H]     Article title

                Preview link (in new window)
                Testmail link

Currently unselected articles

[D] [C]     [L] Article title
[D] [C] [H] [L] Article title 
    ...
[D] [C] [H]     Article title

[Cancel]

[D] = delete, [F] = future (postpone), [C] = current (select) [H] = higher (up), [L] lower (down)

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show_list (object &$output, int $node_id, bool $viewonly,  $edit_again, string $href, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
  • $edit_again
newsletter_compose_show_list_article (line 978)

output various icons and links for manipulating articles

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show_list_article (object &$output, array $a_params, array &$article, bool $first, bool $last, bool $viewonly)
  • object &$output: collects the html output (if any)
  • array $a_params: holds information to build a href
  • array &$article: properties of the article straight from the database
  • bool $first: if TRUE this article is first in the list hence no 'up' icon
  • bool $last: if TRUE this article is last in the list hence no 'down' icon
  • bool $viewonly: if TRUE modification is not allowed so no icons at all
newsletter_compose_show_preview (line 1437)
void newsletter_compose_show_preview ( &$output,  $newsletter_id)
  • &$output
  • $newsletter_id
newsletter_compose_show_testmail (line 1470)

send an example mail of the current newsletter to the sender address

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_compose_show_testmail (object &$output, int $node_id, bool $viewonly,  $edit_again, string $href, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
  • $edit_again
newsletter_compose_toggle (line 1215)

select or deselect an article

this moves an existing article to the 'other' part of the list: selected articles will be added at the top of the unselected ones, unselected articles will be added at the bottom of the selected ones. we allow the sort order to show 'holes' (when an article in the middle of a list is (de)selected) because eventually all articles will be swallowed once a newsletter issue is published.

  • return: TRUE on success, FALSE otherwise
bool newsletter_compose_toggle (int $node_id, int $article_id, bool $select)
  • int $node_id: identifies the newsletter
  • int $article_id: is the article that needs to be (de)selected
  • bool $select: TRUE=select article, FALSE=deselect article
newsletter_configuration_dialog_validate (line 732)

validation of configuration dialog + rewriting the list of administrator email

validate dialog and rewrite admin email addresses as a side effect

  • return: if valid, FALSE otherwise (+messages in dialogdef)
TRUE newsletter_configuration_dialog_validate (array &$dialogdef)
  • array &$dialogdef: the dialog to check
newsletter_configuration_get_dialogdef (line 382)

construct a dialog definition for the main newsletter configuration

  • return: dialog definition
  • uses: $USER, - $CFG
array newsletter_configuration_get_dialogdef (int $node_id, int $viewonly)
  • int $node_id: identifies the current newsletter
  • int $viewonly: if TRUE the Save button is not displayed and config values cannot be changed
newsletter_configuration_save (line 313)

validate and save the modified newsletter configuration linked to node $node_id

this validates and saves the data that was submitted by the user.

If validation fails, the flag $edit_again is set to TRUE and the return value is FALSE.

If the user has cancelled the operation, the flag $edit_again is set to FALSE and the return value is also FALSE.

If the modified data is stored successfully, the return value is TRUE. The flag edit_again is set to TRUE if the user saved via the [Save] button, and to FALSE if the user saved via the [Done] button.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_configuration_save (object &$output, int $node_id, bool $viewonly, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
newsletter_configuration_show (line 271)

show a simple edit screen for the newsletter configuration

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_configuration_show (object &$output, int $node_id, array $module, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_connect (line 85)

connect this module to a node

this makes the link between the node $node_id in area $area_id and this module. In this case we create a single 'newsletters' record linked to node_id via newsletter_id.

  • return: TRUE on success, FALSE otherwise
bool newsletter_connect (object &$output, int $area_id, int $node_id, array $module)
  • object &$output: collects the html output (if any)
  • int $area_id: the area in which $node_id resides
  • int $node_id: the node to which we need to connect
  • array $module: the module record straight from the database
newsletter_content_show (line 220)

show the main content screen (in fact documentation only)

this displays the simple overview screen with documentation. It ends with a cancel button that ends the whole edit operation for this node.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_content_show (object &$output, int $node_id, array $module)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • array $module: the module record straight from the database
newsletter_disconnect (line 54)

disconnect this module from a node

this breaks the link between the node $node_id in area $area_id and this module. For now we simply delete the records in all tables 'newsletters*' using node_id == newsletter_id. Note the order in which the tables are emptied (to satisfy the FK constraints).

  • return: TRUE on success, FALSE otherwise
bool newsletter_disconnect (object &$output, int $area_id, int $node_id, array $module)
  • object &$output: collects the html output (if any)
  • int $area_id: the area in which $node_id resides
  • int $node_id: the node from which we need to disconnect
  • array $module: the module record straight from the database
newsletter_download_csv (line 3081)

send a CSV file of subscribers to the browser

CSV-rules are simple:

  • first line shows column names
  • any LF+CR, CR+LF or CR in data is replaced with a LF 0x0A
  • any quote 0x22 in a quoted field is doubled
  • the numeric field 'status' is not quoted, the other fields are
  • fields are comma-separated (not TAB or semicolon)
  • records are newline-separated (no CR's at all)

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_download_csv (object &$output, int $node_id, bool $viewonly, bool &$edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
newsletter_get_html (line 4103)

construct the HTML-version of the newsletter in parts

this routine constructs the various parts of the HTML-version of the current newsletter. As an added bonus, this routine calculates a newline-delimited table of contents. This can be used to construct the newsletter archives lateron.

Note that the created #fragments start with 'h1' (and not h0). These continue to the end, including the colofon; the colofon is considered the N+1'th article. #toc leads to the start of the ToC, #top goes to the start of the body.

It is possible to have so-called 'ankeilers' (teasers) in ammounce messages. This works as follows: the Editor has to insert a horizontal line ('<hr>') into the article content somewhere. This implies that the announce message will not only contain the ToC of the newsletter but also will contain the title and the content of the articles upto the marker '<hr>'. This marker is removed from the announce article and an empty name anchor is inserted instead. Note that this only works for the FIRST '<hr>' in an article; any subsequent lines are left untouched. The named anchor is used as a target for the 'read more...' prompt that is added to the announce message after the ankeiler. This prompt is linked to the 'b' name in the full article online. If there is an ankeiler, there is also a link before it ('read online...') that links to the 'h' name in the full article online.

If none of the articles contains a horizontal line, we don't do ankeilers at all, but just the ToC (with links to the online articles) and the Colofon.

  • return: TRUE on success, FALSE otherwise
bool newsletter_get_html (int $newsletter_id, string &$toc, string &$title, string &$style, string &$body, [int $issue_id = 0], [bool $announce = FALSE])
  • int $newsletter_id: identifies the newsletter to construct
  • string &$toc: receives newline delimited table of contents
  • string &$title: receives the contents of the HTML title tag
  • string &$style: receives the configured newsletter style information
  • string &$body: receives the full body (but without the tag 'body')
  • int $issue_id: is the unique issue ID for this issue (used for self reference)
  • bool $announce: TRUE means: create only an announce message, FALSE=full HTML newsletter
newsletter_get_html_templates (line 4293)

construct the configurable part of the HTML-version of the newsletter, with parameters

this prepars the 'template'-fields in the HTML-version of the newsletter. These fields can contain the following parameters:

{TITLE}        - title of the newsletter
{SUBTITLE}     - subtitle of the newsletter
{VOLUME}       - issue volume number
{NUMBER}       - issue number within volume
{DATIM}        - yyyy-mm-dd hh:mm:ss is exact publication time stamp
{YEAR}         - yyyy is [publication year (as in (C)Copyright {YEAR} {TITLE})
{DATE}         - yyyy-mm-dd is publication date
{TIME}         - hh:mm is publication time
{ARCHIVE}      - fully qualified link leading to newsletter archive
{CONTRIBUTION} - fully qualified link leading to visitor contribution dialog
{SUBSCRIBE}    - fully qualified link leading to visitor subscription dialog
{UNSUBSCRIBE}  - fully qualified link leading to visitor unscription dialog
{CONFIRM}      - fully qualified link leading to visitor confirmation dialog (for completeness...)
{ISSUE}        - fully qualified link leading to online version of newsletter
{PRINT}        - fully qualified link leading to printversion of this issue (after publication)

Note that the links my yield an error, e.g. when the newsletter is configured to not allow contributions the link '{CONTRIBUTION}' will not actually work. It is the responsability of the newsletter administrator to use the parameters in say the newsletter footer.

Also note that the '{PRINT}' link only really works when an issue is (finally) published. Before publication the issue number yields an error message; this is a feature (we don't want Smart Alec's to see the next issue before publication). When this routine is called from the COMPOSE-preview we don't know the issue_id yet, so we show a 0 (it is only a preview, right?). In the PUBLICATION-preview we use the correct issue_id (but that only works after publication). The same logic applies to {ISSUE}.

Finally, the print version opens in a (very clean) new window.

  • return: contains the ready-to-use text from the configurable templates
array newsletter_get_html_templates (array &$config, int $newsletter_id, [int $issue_id = 0])
  • array &$config: contains newsletter configuration
  • int $newsletter_id: aka node_id
  • int $issue_id: is the unique issue ID for this issue (used for self reference)
newsletter_publish_dialog_validate (line 2150)

validation of publication confirmation dialog checks checked checkbox

validate dialog and also make sure that the checkbox is checked

  • return: if valid, FALSE otherwise (+messages in dialogdef)
TRUE newsletter_publish_dialog_validate (array &$dialogdef)
  • array &$dialogdef: the dialog to check
newsletter_publish_get_dialogdef (line 2120)

construct the dialog definition for confirmation of newsletter publication

  • return: dialog definition
array newsletter_publish_get_dialogdef (bool $viewonly)
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
newsletter_publish_prepare_issue (line 1804)

prepare the current newsletter for publication in the issues table

  • return: TRUE on success, FALSE otherwise
bool newsletter_publish_prepare_issue (object &$output, int $newsletter_id, array &$issue)
  • object &$output: collects the html output (if any)
  • int $newsletter_id: identifies the node/newsletter
  • array &$issue: receives a copy of the issue-record that was saved
newsletter_publish_save (line 2182)

publish the prepared newsletter

this routine actually 'flips the bit' and officially publishes the prepared newsletter. Strategy: A: retrieve the key information about the upcoming issue (status is still NEWSLETTER_UNPUBLISHED B: determine which channel to use (sets status of issue) C: set status D: update next_number in configuration E: add issue+subscribers to the queue F: remove all selected articles now that they are part of the newsletter issue

If anything goes wrong during this process, we return FALSE and we won't be editing again, ie. the user is returned to the page manager. A little ugly but there's only a small chance that this fails. I hope.

  • return: TRUE on success, FALSE otherwise
bool newsletter_publish_save (object &$output, int $node_id, bool $viewonly, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node from which we need to disconnect
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
newsletter_publish_show (line 1727)

show the newsletter publication confirmation screen for the current newsletter

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_publish_show (object &$output, int $node_id, array $module, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_publish_show_confirm (line 1944)

show a confirmation dialog for the publisher

the confirmation dialog requires the publisher to manually check the box for publishing; it is reset every time this dialog is created. We want to prevent accidental publications...

Note that we also check to see if the combination of volume and number is not used before. If it is, the publisher is not able to check the box and hence publish the newsletter. We don't want two different newsletters with the same volume/number identification.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_publish_show_confirm (object &$output, int $node_id, bool $viewonly, bool $edit_again, string $href, $array &$issue)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
  • $array &$issue: contains all data for the newsletter issue to be published
newsletter_publish_show_preview (line 2028)
void newsletter_publish_show_preview ( &$output,  $newsletter_id)
  • &$output
  • $newsletter_id
newsletter_publish_show_testmail (line 2061)

send final example mail of the current newsletter from database to the publishers address

  • return: TRUE on success + output stored via $output, FALSE otherwise
  • uses: $USER
  • uses: $CFG
bool newsletter_publish_show_testmail (object &$output, int $node_id, bool $viewonly,  $edit_again, string $href, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
  • $edit_again
newsletter_queue_get_dialogdef (line 4044)

construct an OK-button and a Cancel-button for the queue overview dialog

  • return: dialog definition
array newsletter_queue_get_dialogdef (bool $viewonly)
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
newsletter_queue_save (line 4006)

process a few entries in the queue (if any)

this routine is called whenever the user presses the [OK] button in the queue overview screen. This is a way to speed up emptying of the queue; we process a few pending messages each time.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_queue_save (object &$output, int $node_id, bool $viewonly, bool &$edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
newsletter_queue_show (line 3908)

display a table with pending newsletter emails

this shows all entries in the queue as a table with these columns:

id | volume | number | next | errors | email | full_name

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_queue_show (object &$output, int $node_id, array $module, bool $viewonly,  $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
  • $edit_again
newsletter_save (line 189)

dispatcher for save routines

We use different subroutines for clarity.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_save (object &$output, int $area_id, int $node_id, array $module, bool $viewonly, bool &$edit_again, string $option)
  • object &$output: collects the html output (if any)
  • int $area_id: the area in which $node_id resides
  • int $node_id: the node to which the content is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $option: the selected submenu option or NULL if user used the 'Content' option to get here
newsletter_show_edit (line 149)

dispatcher for showing various dialog screens

there are a few dialogs that are accessed via this routine: - overview: a simple introduction to this module (via $option==NULL) - configuration: all properties of the newsletter (main newsletters record) ($option=configuration) - edit: add, edit, delete, rearrange and select articles ($option=edit) - publish: approve/publish the prepared newsletter ($option=publish) - subscriptions: manage subscriptions and blacklist ($option=subscriptions) - queue: manage the mail queue ($option=queue)

The actual work is done in subroutines.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_show_edit (object &$output, int $area_id, int $node_id, array $module, bool $viewonly, bool $edit_again, string $href, string $option)
  • object &$output: collects the html output (if any)
  • int $area_id: the area in which $node_id resides
  • int $node_id: the node to which this module is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
  • string $option: the selected submenu option or NULL if user used the 'Content' option to get here
newsletter_strip8859_1 (line 4514)

transliterate characters 128-255 to something 'ascii-like'

translate chars 128-255 to acceptable (?) ASCII used to make non-UTF-8 data behave (sort of) kludge, sorry :-(

void newsletter_strip8859_1 (string $text, string 1)
  • string $text: may contain chrs 128-255
  • string 1: all chars 128-255 transliterated to ascii equivalents
newsletter_subscriptions_get_dialogdef (line 2948)

construct a dialog definition for a subscriber (add/edit)

this constructs a dialog definition which handles adding and editing subscribers In the case of adding a new subscriber we start with empty fields (mostly), otherwise we attempt to load the existing data from the DB.

If the subscriber_id is 0 we are adding a new subscriber.

  • return: dialog definition
array newsletter_subscriptions_get_dialogdef (int $node_id, int $viewonly, int $subscriber_id)
  • int $node_id: identifies the current newsletter
  • int $viewonly: if TRUE the Save button is not displayed and values cannot be changed
  • int $subscriber_id: identifies the subscriber, 0 for a new one
newsletter_subscriptions_get_dialogdef_delete (line 3047)

construct a dialog definition for deletion of a subscriber

this constructs a dialog definition which handles deleting of a subscriber. There is not much to do: the subscriber_id to delete is conveyed via $_GET[].

  • return: dialog definition
array newsletter_subscriptions_get_dialogdef_delete (int $viewonly)
  • int $viewonly: if TRUE the Delete button is not displayed
newsletter_subscriptions_save (line 2794)

handle saving & deleting of subscribers

this handles all actual subscriber add/edit/delete actions. criterion for delete is the existence of the delete-parameter (which identifies the subscriber to delete), the criterion for edit/add is the subscriber-parameter.

Part of the logic handling the [Cancel] button is done here too (see also newsletter_subscriptions_show_edit()).

  • return: TRUE on success + output stored via $output, FALSE otherwise
  • todo: what to do with equal email addresses: can those simply be added or must they be unique?
bool newsletter_subscriptions_save (object &$output, int $node_id, bool $viewonly,  &$edit_again, bool $edit_again)
  • object &$output: collects the html output (if any)
  • int $node_id: the node alias the newsletter
  • bool $viewonly: if TRUE, editing is not allowed (but simply showing the content is allowed)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • &$edit_again
newsletter_subscriptions_show (line 2321)

dispatcher for displaying newsletter subscriptions dialogs

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_subscriptions_show (object &$output, int $node_id, array $module, bool $viewonly, bool &$edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • array $module: the module record straight from the database
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
newsletter_subscriptions_show_add (line 2639)

show the dialog for adding a new subscriber

actual work is done in newsletter_subscriptions_show_edit() but with subscriber_id set to 0 instead of a valid, existing subscriber_id.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_subscriptions_show_add (object &$output, int $node_id, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • bool $viewonly: if TRUE, adding/editing is not allowed (but simply showing the content is)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_subscriptions_show_delete (line 2728)

show a delete confirmation dialog

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_subscriptions_show_delete (object &$output, int $node_id, int $subscriber_id, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • int $subscriber_id: identifies the subscription to delete
  • bool $viewonly: if TRUE, adding/editing is not allowed (but simply showing the content is)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_subscriptions_show_edit (line 2676)

show dialog for editing (or adding) a subscriber

this displays the edit dialog for subscribers. It is also used by newsletter_subscriptions_show_add() with subscriber_id = 0.

This dialog usually ends with three buttons: [Save] - saves the current subscriber and edits again [Done] - save the subscriber and return to the list of subscriptions [Cancel] - don't save and return to the list of subscriptions This poses a little problem when a new subscriber is added and the user clicks [Save]; there is no elegant way to convey the new subscriber_id (which was 0 in the add subscriber dialog) to the routine that subsequently edits the newly added subscriber. The (ugly) work around is to set the global $newsletter_new_subscriber_id in the save routine and pick up the new value here.

Also part of the logic to deal with [Cancel] is handled here; the [Cancel]-button in this Add/Edit dialog (and the Delete dialog in newsletter_subscriptions_show_delete() for that matter) should return to the list of subscriptions, whereas the [Cancel] button in the list of subscriptions should lead to the content overview in .

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_subscriptions_show_edit (object &$output, int $node_id, int $subscriber_id, bool $viewonly, bool $edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which this module is connected
  • int $subscriber_id: identifies the subscription to edit (0 means add a new subscription dialog)
  • bool $viewonly: if TRUE, adding/editing is not allowed (but simply showing the content is)
  • bool $edit_again: if TRUE start with data from $_POST, else use data from database
  • string $href: the action property of the HTML-form, the place where data will be POST'ed
newsletter_subscriptions_show_list (line 2396)

create the main newsletter subscriptions overview screen

Display a list of all current subscribers (if any)

Header

Explanation

Add a subscriber
    ID Status Email Name
[D] id status email full_name
    ...
[D] id status email full_name

Download

Upload

[Cancel]

If there are no subscribers, only the Add + Upload links are visible (if editing is allowed). If there are subscribers, they are listed in a HTML-table. The [D]elete icon leads to the delete dialog but is only visible if editing is allowed, 'Add' leads to the add subscriber dialog (if editing is allowed), The ID field is clickable and leads to the edit dialog. The table headers are clickable and change the sort order. If there are many subscribers, the list is paginated.

The column with delete icons is only visible when $viewonly == FALSE.

Sort order: 1=ID, 2=Status,Email, 3=Email,ID, 4=Name,ID; negative=DESC; default +2

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_subscriptions_show_list (object &$output, int $node_id, bool $viewonly, bool &$edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
newsletter_subscriptions_table (line 2517)

pretty-print a list of subscribers including sort options in the HTML table header

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_subscriptions_table (object &$output, int $newsletter_id, array &$records, bool $viewonly, int $sort, int $limit, in $offset)
  • object &$output: collects the html output
  • int $newsletter_id: aka the node_id
  • array &$records: all subscribers that need to be displayed in the list
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • int $sort: indicates sort order (1/id, 2/status, 3/email, 4/name), negative is descending
  • int $limit:
    • of records per screen
  • in $offset: offset in the database to the 1st record in the visible list
newsletter_upload_csv (line 3155)

handle subscribers upload

this whole procedure works with 2 dialogs. The first dialog lets the user specify a file to upload and/or allows for a list of subscriber information (in CSV format). This dialog is presented here in newsletter_upload_csv().

Once the CSV-records are submitted (file and/or text area), a second dialog is presented to the user (see newsletter_upload_entries()). In that dialog the user can manipulate the status of the new subscribers but not the actual data.

In this routine we present the first dialog and we also validate the incoming data from that dialog. If that appears to be valid, we switch to phase two by calling newsletter_upload_entries(). If we are already in phase two, we continue with that routine immediately.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_upload_csv (object &$output, int $node_id, bool $viewonly, bool &$edit_again, string $href)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
newsletter_upload_csv_extract (line 3464)

helper routine to extract usable data from a single CSV record

this routine extracts the 0-based fields from $row based on the information in the $fields array. That array provides 4 lists of input fields that should be combined to form a single output field.

After constructing the four fields (and lowercasing the email address along the way), we take a look in the database to see if this newsletter already has this email address. If that is the case, we collect the subscriber_id and the current status in additional fields 4 and 5. If the email address does noet yet exist, we simpy set fields 4 and 5 to a 0, indicating a new subscriber.

The output fields are subsequently added to the $uploads array.

  • return: and valid records added to $uploads
void newsletter_upload_csv_extract (int $newsletter_id, array &$uploads, array &$row, array &$fields)
  • int $newsletter_id: identifies the newsletter
  • array &$uploads: receives processed upload data (4 fields)
  • array &$row: contains the CSV-record, one field per array element
  • array &$fields: contains the lists of CSV-fields to combine
newsletter_upload_csv_get_dialogdef (line 3202)

construct a dialog for specifying CSV upload

  • return: dialog definition
array newsletter_upload_csv_get_dialogdef (bool $viewonly)
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
newsletter_upload_csv_load (line 3307)

massage the submitted data and return a neat array with subscriber information

  • return: FALSE on error, array with subscriber data on success
bool|array newsletter_upload_csv_load (int $newsletter_id, array &$dialogdef)
  • int $newsletter_id: identifies the newsletter
  • array &$dialogdef: contains the valid results of the 1st upload dialog
newsletter_upload_entries (line 3538)

handle phase two of subscriber upload

After handling the CSV-upload in newsletter_upload_csv(), we call this routine to handle the actual entries that were uploaded.

The first time this routine is called, it is with a reference to all uploaded entries in $uploads. This array is used to construct the initial dialog definintion. Every time we come here after that the dialogdefinition is reconstructed based on the count parameter in the dialog, and the data is retrieved from $_POST.

The main task here is to validate the data and subsequently show a neat HTML table with the uploaded entries. The user can then select the new status for the uploaded users. One of the options is to 'skip', i.e. prevent the uploaded entry from ending up in the database.

In order to make any errors a little more visible, we set the error flag in the status field even if the real error occurs in another field (e.g. the remarks field is too long). This way the status listbox turns red if there is an error.

Validation is handled 'manually' in two parts. The first part is all generic fields in the dialogdef, e.g. csrftoken. An error in those fields is fatal and will prevent saving of the data. The second part simply steps through the $count entries that are stored in $dialogdef. Errors in those entries are non-fatal, because the user can select 'skip' for erroneous entries and try again.

Note that we only take the non-skipped entries into account. If an entry contains errors, the user can (manually) set that record to 'skip' and that entry will not be used. Any errors in skipped entries are ignored when deciding if it is time to actually save the data.

Because we want an HTML table, we cannot use dialog_quickform(). Oh well.

  • return: TRUE on success + output stored via $output, FALSE otherwise
bool newsletter_upload_entries (object &$output, int $node_id, bool $viewonly, bool &$edit_again, string $href, array &$uploads)
  • object &$output: collects the html output (if any)
  • int $node_id: the node to which the content is connected
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool &$edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • string $href: the action property of the HTML-form, the place where data will be POSTed
  • array &$uploads: holds the preprocessed uploaded subscriber information (4 fields/row) or NULL
newsletter_upload_entries_get_dialogdef (line 3661)

construct a dialog definition, maybe filled with data from $uploads

this constructs a dialogdefinition based on either the records in $uploads OR from the $_POST array. In the latter case the number of elements is determined by the counter in a hidden field.

There are a few generic fields: 'csrftoken','count','button_done','button_cancel' and there $count sets of 'email','full_name','remarks','status','sid','old' with a 0-based index appended. Total size: $count * 6 + 4 elements.

void newsletter_upload_entries_get_dialogdef (bool $viewonly, bool $edit_again, array &$uploads, array 3)
  • bool $viewonly: if TRUE, editing and hence saving is not allowed
  • bool $edit_again: set to TRUE if we need to edit the content again, FALSE otherwise
  • array &$uploads: holds the preprocessed uploaded subscriber information (4 fields/row) or NULL
  • array 3: dialog definition
newsletter_upload_entries_store (line 3827)

store the subscribers data in the database

this stores the contents of the dialogdef in the database. All data is already validated, it is simply a question of storing the data. The only twist is that we either update an existing record or insert a new one, depending on the 'sid' (subscriber_id) value: a 0 indicates that a new record is required.

The new status of an existing subscriber is calculated from both the old and the new value as follows: we simply use the maximum value of both. This means that

  • 3 (blacklist) trumps everything: an import can never un-blacklist a subscriber. but selecting 'blacklist' in the upload overrules any existing value.
  • 2 (approved): an approved subscriber stays approved, even if the upload would suggest only 'confirmed'. OTOH: if the subscriber is only 'confirmed', the upload can upgrade the subscriber to 'approved'.
  • 1 (confirmed): any subscriber who is in the process of subscribing herself (status = 0/new) is automatically upgraded to 'confirmed' The other way around is not possible because the value 0 means 'skip' in the upload routine.
In other words: $status = max($old,$new). Easy.

  • return: TRUE on success, FALSE if at least 1 database action failed
bool newsletter_upload_entries_store (object &$output, array &$dialogdef, int $node_id)
  • object &$output: collects the html output (if any)
  • array &$dialogdef: holds the complete upload dialog including data
  • int $node_id: the node to which the content is connected
newsletter_volume_number_available (line 4490)

determine whether volume + number already exists in this newsletter

this check is performed while the preliminary newsletter issue is already in the issues table. Therefore there should be at most one record with that Volume + Number. If there are more, this combination is already taken.

void newsletter_volume_number_available (int $newsletter_id, int $volume, int $number, bool 3)
  • int $newsletter_id
  • int $volume
  • int $number
  • bool 3: TRUE if combination is available, FALSE means already exists or an error occurred

Documentation generated on Tue, 28 Jun 2016 19:10:47 +0200 by phpDocumentor 1.4.0