From 51c42a65c55f02dc3d60a936a463c5d520f64fc4 Mon Sep 17 00:00:00 2001 From: Thomas Keller Date: Mon, 6 Dec 2010 00:11:59 +0100 Subject: [PATCH] Project owners can now enter multiple email addresses for each notification type. Each email must be separated by a comma from the other. (Based on a patch from Pierre Marechal, fixes issue 372). --- src/IDF/Commit.php | 43 +++++++++++----------- src/IDF/Form/Field/EmailList.php | 51 +++++++++++++++++++++++++++ src/IDF/Form/TabsConf.php | 5 +-- src/IDF/Issue.php | 42 +++++++++++----------- src/IDF/Review/Patch.php | 19 +++++----- src/IDF/Upload.php | 46 ++++++++++++------------ src/IDF/WikiRevision.php | 45 ++++++++++++----------- src/IDF/templates/idf/admin/tabs.html | 8 ++--- 8 files changed, 163 insertions(+), 96 deletions(-) create mode 100644 src/IDF/Form/Field/EmailList.php diff --git a/src/IDF/Commit.php b/src/IDF/Commit.php index 0a8690c..70414aa 100644 --- a/src/IDF/Commit.php +++ b/src/IDF/Commit.php @@ -44,9 +44,9 @@ class IDF_Commit extends Pluf_Model 'id' => array( 'type' => 'Pluf_DB_Field_Sequence', - 'blank' => true, + 'blank' => true, ), - 'project' => + 'project' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'IDF_Project', @@ -54,7 +54,7 @@ class IDF_Commit extends Pluf_Model 'verbose' => __('project'), 'relate_name' => 'commits', ), - 'author' => + 'author' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'Pluf_User', @@ -118,7 +118,7 @@ class IDF_Commit extends Pluf_Model { IDF_Search::index($this); if ($create) { - IDF_Timeline::insert($this, $this->get_project(), + IDF_Timeline::insert($this, $this->get_project(), $this->get_author(), $this->creation_dtime); } } @@ -200,13 +200,13 @@ class IDF_Commit extends Pluf_Model * Returns the timeline fragment for the commit. * * - * @param Pluf_HTTP_Request + * @param Pluf_HTTP_Request * @return Pluf_Template_SafeString */ public function timelineFragment($request) { - $url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit', - array($request->project->shortname, + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit', + array($request->project->shortname, $this->scm_id)); $out = ''. Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')). @@ -222,24 +222,24 @@ class IDF_Commit extends Pluf_Model -
'.sprintf(__('Commit %s, by %s'), ''.$this->scm_id.'', $user).'
'; +
'.sprintf(__('Commit %s, by %s'), ''.$this->scm_id.'', $user).'
'; return Pluf_Template::markSafe($out); } /** * Returns the feed fragment for the commit. * - * @param Pluf_HTTP_Request + * @param Pluf_HTTP_Request * @return Pluf_Template_SafeString */ public function feedFragment($request) { $url = Pluf::f('url_base') - .Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit', - array($request->project->shortname, + .Pluf_HTTP_URL_urlForView('IDF_Views_Source::commit', + array($request->project->shortname, $this->scm_id)); $date = Pluf_Date::gmDateToGmString($this->creation_dtime); - $author = ($this->get_author()) ? + $author = ($this->get_author()) ? $this->get_author() : $this->origauthor; $cproject = $this->get_project(); $context = new Pluf_Template_Context_Request( @@ -298,7 +298,7 @@ class IDF_Commit extends Pluf_Model $current_locale = Pluf_Translation::getLocale(); $langs = Pluf::f('languages', array('en')); - Pluf_Translation::loadSetLocale($langs[0]); + Pluf_Translation::loadSetLocale($langs[0]); $context = new Pluf_Template_Context( array( @@ -309,13 +309,16 @@ class IDF_Commit extends Pluf_Model ); $tmpl = new Pluf_Template('idf/source/commit-created-email.txt'); $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $conf->getVal('source_notification_email'), - sprintf(__('New Commit %s - %s (%s)'), - $this->scm_id, $this->summary, - $this->get_project()->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); + $addresses = explode(',', $conf->getVal('source_notification_email')); + foreach ($addresses as $address) { + $email = new Pluf_Mail(Pluf::f('from_email'), + $address, + sprintf(__('New Commit %s - %s (%s)'), + $this->scm_id, $this->summary, + $this->get_project()->shortname)); + $email->addTextMessage($text_email); + $email->sendMail(); + } Pluf_Translation::loadSetLocale($current_locale); } } diff --git a/src/IDF/Form/Field/EmailList.php b/src/IDF/Form/Field/EmailList.php new file mode 100644 index 0000000..3f5b8cc --- /dev/null +++ b/src/IDF/Form/Field/EmailList.php @@ -0,0 +1,51 @@ +empty_values)) { + $value = ''; + } + if ($value == '') { + return $value; + } + $emails = preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY); + foreach ($emails as $email) { + if (!Pluf_Utils::isValidEmail($email)) { + throw new Pluf_Form_Invalid(__( + 'Please enter one or more valid email addresses.' + )); + } + } + return implode(',', $emails); + } +} diff --git a/src/IDF/Form/TabsConf.php b/src/IDF/Form/TabsConf.php index a9087c9..969c6d7 100644 --- a/src/IDF/Form/TabsConf.php +++ b/src/IDF/Form/TabsConf.php @@ -45,7 +45,7 @@ class IDF_Form_TabsConf extends Pluf_Form array('required' => true, 'label' => $label, 'initial' => $this->conf->getVal($key, 'all'), - 'widget_attrs' => array('choices' => + 'widget_attrs' => array('choices' => array( __('Open to all') => 'all', __('Signed in users') => 'login', @@ -63,10 +63,11 @@ class IDF_Form_TabsConf extends Pluf_Form 'source_notification_email', 'issues_notification_email',); foreach ($ak as $key) { - $this->fields[$key] = new Pluf_Form_Field_Email( + $this->fields[$key] = new IDF_Form_Field_EmailList( array('required' => false, 'label' => $key, 'initial' => $this->conf->getVal($key, ''), + 'widget_attrs' => array('size' => 40), )); } diff --git a/src/IDF/Issue.php b/src/IDF/Issue.php index dc77e1a..3be0253 100644 --- a/src/IDF/Issue.php +++ b/src/IDF/Issue.php @@ -42,9 +42,9 @@ class IDF_Issue extends Pluf_Model 'id' => array( 'type' => 'Pluf_DB_Field_Sequence', - 'blank' => true, + 'blank' => true, ), - 'project' => + 'project' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'IDF_Project', @@ -59,7 +59,7 @@ class IDF_Issue extends Pluf_Model 'size' => 250, 'verbose' => __('summary'), ), - 'submitter' => + 'submitter' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'Pluf_User', @@ -67,7 +67,7 @@ class IDF_Issue extends Pluf_Model 'verbose' => __('submitter'), 'relate_name' => 'submitted_issue', ), - 'owner' => + 'owner' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'Pluf_User', @@ -76,7 +76,7 @@ class IDF_Issue extends Pluf_Model 'verbose' => __('owner'), 'relate_name' => 'owned_issue', ), - 'interested' => + 'interested' => array( 'type' => 'Pluf_DB_Field_Manytomany', 'model' => 'Pluf_User', @@ -86,14 +86,14 @@ class IDF_Issue extends Pluf_Model ), 'tags' => array( - 'type' => 'Pluf_DB_Field_Manytomany', + 'type' => 'Pluf_DB_Field_Manytomany', 'blank' => true, 'model' => 'IDF_Tag', 'verbose' => __('labels'), ), - 'status' => + 'status' => array( - 'type' => 'Pluf_DB_Field_Foreignkey', + 'type' => 'Pluf_DB_Field_Foreignkey', 'blank' => false, 'model' => 'IDF_Tag', 'verbose' => __('status'), @@ -111,7 +111,7 @@ class IDF_Issue extends Pluf_Model 'verbose' => __('modification date'), ), ); - $this->_a['idx'] = array( + $this->_a['idx'] = array( 'modif_dtime_idx' => array( 'col' => 'modif_dtime', @@ -120,7 +120,7 @@ class IDF_Issue extends Pluf_Model ); $table = $this->_con->pfx.'idf_issue_idf_tag_assoc'; $this->_a['views'] = array( - 'join_tags' => + 'join_tags' => array( 'join' => 'LEFT JOIN '.$table .' ON idf_issue_id=id', @@ -164,7 +164,7 @@ class IDF_Issue extends Pluf_Model // that the issue as at least one comment in the database when // doing the indexing. if ($create) { - IDF_Timeline::insert($this, $this->get_project(), + IDF_Timeline::insert($this, $this->get_project(), $this->get_submitter()); } } @@ -177,12 +177,12 @@ class IDF_Issue extends Pluf_Model * as such create links to other items etc. You can consider that * if displayed, you can create a link to it. * - * @param Pluf_HTTP_Request + * @param Pluf_HTTP_Request * @return Pluf_Template_SafeString */ public function timelineFragment($request) { - $url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view', + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view', array($request->project->shortname, $this->id)); $out = ''. @@ -193,14 +193,14 @@ class IDF_Issue extends Pluf_Model $ic = (in_array($this->status, $request->project->getTagIdsByStatus('closed'))) ? 'issue-c' : 'issue-o'; $out .= sprintf(__('Issue %3$d, %4$s'), $url, $ic, $this->id, Pluf_esc($this->summary)).''; $out .= "\n".' -
'.sprintf(__('Creation of issue %d, by %s'), $url, $ic, $this->id, $user).'
'; +
'.sprintf(__('Creation of issue %d, by %s'), $url, $ic, $this->id, $user).'
'; return Pluf_Template::markSafe($out); } public function feedFragment($request) { $url = Pluf::f('url_base') - .Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view', + .Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view', array($request->project->shortname, $this->id)); $title = sprintf(__('%s: Issue %d created - %s'), @@ -241,15 +241,17 @@ class IDF_Issue extends Pluf_Model $prj = $this->get_project(); $to_email = array(); if ('' != $conf->getVal('issues_notification_email', '')) { - $langs = Pluf::f('languages', array('en')); - $to_email[] = array($conf->getVal('issues_notification_email'), - $langs[0]); + $langs = Pluf::f('languages', array('en')); + $addresses = explode(',', $conf->getVal('issues_notification_email')); + foreach ($addresses as $address) { + $to_email[] = array($address, $langs[0]); + } } $current_locale = Pluf_Translation::getLocale(); $id = '<'.md5($this->id.md5(Pluf::f('secret_key'))).'@'.Pluf::f('mail_host', 'localhost').'>'; if ($create) { - if (null != $this->get_owner() and $this->owner != $this->submitter) { - $email_lang = array($this->get_owner()->email, + if (null != $this->get_owner() and $this->owner != $this->submitter) { + $email_lang = array($this->get_owner()->email, $this->get_owner()->language); if (!in_array($email_lang, $to_email)) { $to_email[] = $email_lang; diff --git a/src/IDF/Review/Patch.php b/src/IDF/Review/Patch.php index 5c9f5da..656493d 100644 --- a/src/IDF/Review/Patch.php +++ b/src/IDF/Review/Patch.php @@ -197,14 +197,17 @@ class IDF_Review_Patch extends Pluf_Model ); $tmpl = new Pluf_Template('idf/review/review-created-email.txt'); $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $conf->getVal('review_notification_email'), - sprintf(__('New Code Review %s - %s (%s)'), - $this->get_review()->id, - $this->get_review()->summary, - $this->get_review()->get_project()->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); + $addresses = explode(';',$conf->getVal('review_notification_email')); + foreach ($addresses as $address) { + $email = new Pluf_Mail(Pluf::f('from_email'), + $address, + sprintf(__('New Code Review %s - %s (%s)'), + $this->get_review()->id, + $this->get_review()->summary, + $this->get_review()->get_project()->shortname)); + $email->addTextMessage($text_email); + $email->sendMail(); + } Pluf_Translation::loadSetLocale($current_locale); } } diff --git a/src/IDF/Upload.php b/src/IDF/Upload.php index 955af97..8effae0 100644 --- a/src/IDF/Upload.php +++ b/src/IDF/Upload.php @@ -39,9 +39,9 @@ class IDF_Upload extends Pluf_Model 'id' => array( 'type' => 'Pluf_DB_Field_Sequence', - 'blank' => true, + 'blank' => true, ), - 'project' => + 'project' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'IDF_Project', @@ -77,7 +77,7 @@ class IDF_Upload extends Pluf_Model 'default' => 0, 'verbose' => __('file size in bytes'), ), - 'submitter' => + 'submitter' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'Pluf_User', @@ -87,7 +87,7 @@ class IDF_Upload extends Pluf_Model ), 'tags' => array( - 'type' => 'Pluf_DB_Field_Manytomany', + 'type' => 'Pluf_DB_Field_Manytomany', 'blank' => true, 'model' => 'IDF_Tag', 'verbose' => __('labels'), @@ -112,7 +112,7 @@ class IDF_Upload extends Pluf_Model 'verbose' => __('modification date'), ), ); - $this->_a['idx'] = array( + $this->_a['idx'] = array( 'modif_dtime_idx' => array( 'col' => 'modif_dtime', @@ -121,7 +121,7 @@ class IDF_Upload extends Pluf_Model ); $table = $this->_con->pfx.'idf_tag_idf_upload_assoc'; $this->_a['views'] = array( - 'join_tags' => + 'join_tags' => array( 'join' => 'LEFT JOIN '.$table .' ON idf_upload_id=id', @@ -150,7 +150,7 @@ class IDF_Upload extends Pluf_Model function postSave($create=false) { if ($create) { - IDF_Timeline::insert($this, $this->get_project(), + IDF_Timeline::insert($this, $this->get_project(), $this->get_submitter(), $this->creation_dtime); } } @@ -173,13 +173,13 @@ class IDF_Upload extends Pluf_Model * Returns the timeline fragment for the file. * * - * @param Pluf_HTTP_Request + * @param Pluf_HTTP_Request * @return Pluf_Template_SafeString */ public function timelineFragment($request) { - $url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view', - array($request->project->shortname, + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Download::view', + array($request->project->shortname, $this->id)); $out = ''. Pluf_esc(Pluf_Template_dateAgo($this->creation_dtime, 'without')). @@ -189,15 +189,15 @@ class IDF_Upload extends Pluf_Model $out .= sprintf(__('Download %2$d, %3$s'), $url, $this->id, Pluf_esc($this->summary)).''; $out .= ''; $out .= "\n".' -
'.sprintf(__('Addition of download %d, by %s'), $url, $this->id, $user).'
'; +
'.sprintf(__('Addition of download %d, by %s'), $url, $this->id, $user).'
'; return Pluf_Template::markSafe($out); } public function feedFragment($request) { $url = Pluf::f('url_base') - .Pluf_HTTP_URL_urlForView('IDF_Views_Download::view', - array($request->project->shortname, + .Pluf_HTTP_URL_urlForView('IDF_Views_Download::view', + array($request->project->shortname, $this->id)); $title = sprintf(__('%s: Download %d added - %s'), $request->project->name, @@ -227,7 +227,7 @@ class IDF_Upload extends Pluf_Model } $current_locale = Pluf_Translation::getLocale(); $langs = Pluf::f('languages', array('en')); - Pluf_Translation::loadSetLocale($langs[0]); + Pluf_Translation::loadSetLocale($langs[0]); $context = new Pluf_Template_Context( array('file' => $this, @@ -237,14 +237,16 @@ class IDF_Upload extends Pluf_Model )); $tmpl = new Pluf_Template('idf/downloads/download-created-email.txt'); $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $conf->getVal('downloads_notification_email'), - sprintf(__('New download - %s (%s)'), - $this->summary, - $this->get_project()->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); - + $addresses = explode(',', $conf->getVal('downloads_notification_email')); + foreach ($addresses as $address) { + $email = new Pluf_Mail(Pluf::f('from_email'), + $address, + sprintf(__('New download - %s (%s)'), + $this->summary, + $this->get_project()->shortname)); + $email->addTextMessage($text_email); + $email->sendMail(); + } Pluf_Translation::loadSetLocale($current_locale); } } \ No newline at end of file diff --git a/src/IDF/WikiRevision.php b/src/IDF/WikiRevision.php index 27504e0..5528a84 100644 --- a/src/IDF/WikiRevision.php +++ b/src/IDF/WikiRevision.php @@ -38,9 +38,9 @@ class IDF_WikiRevision extends Pluf_Model 'id' => array( 'type' => 'Pluf_DB_Field_Sequence', - 'blank' => true, + 'blank' => true, ), - 'wikipage' => + 'wikipage' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'IDF_WikiPage', @@ -55,7 +55,7 @@ class IDF_WikiRevision extends Pluf_Model 'default' => false, 'help_text' => 'If this revision is the latest, we mark it as being the head revision.', 'index' => true, - + ), 'summary' => array( @@ -71,7 +71,7 @@ class IDF_WikiRevision extends Pluf_Model 'blank' => false, 'verbose' => __('content'), ), - 'submitter' => + 'submitter' => array( 'type' => 'Pluf_DB_Field_Foreignkey', 'model' => 'Pluf_User', @@ -92,7 +92,7 @@ class IDF_WikiRevision extends Pluf_Model 'verbose' => __('creation date'), ), ); - $this->_a['idx'] = array( + $this->_a['idx'] = array( 'creation_dtime_idx' => array( 'col' => 'creation_dtime', @@ -138,7 +138,7 @@ class IDF_WikiRevision extends Pluf_Model $sql = new Pluf_SQL('wikipage=%s', array($this->wikipage)); $rev = Pluf::factory('IDF_WikiRevision')->getList(array('filter'=>$sql->gen())); if ($rev->count() > 1) { - IDF_Timeline::insert($this, $this->get_wikipage()->get_project(), + IDF_Timeline::insert($this, $this->get_wikipage()->get_project(), $this->get_submitter()); foreach ($rev as $r) { if ($r->id != $this->id and $r->is_head) { @@ -156,7 +156,7 @@ class IDF_WikiRevision extends Pluf_Model public function timelineFragment($request) { $page = $this->get_wikipage(); - $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', + $url = Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', array($request->project->shortname, $page->title)); $out = "\n".''. @@ -186,7 +186,7 @@ class IDF_WikiRevision extends Pluf_Model } $out .= ''; $out .= "\n".' -
'.sprintf(__('Change of %s, by %s'), $url, Pluf_esc($page->title), $user).'
'; +
'.sprintf(__('Change of %s, by %s'), $url, Pluf_esc($page->title), $user).'
'; return Pluf_Template::markSafe($out); } @@ -195,13 +195,13 @@ class IDF_WikiRevision extends Pluf_Model $page = $this->get_wikipage(); if (!$this->is_head) { $url = Pluf::f('url_base') - .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', + .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', array($request->project->shortname, $page->title), array('rev' => $this->id)); } else { $url = Pluf::f('url_base') - .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', + .Pluf_HTTP_URL_urlForView('IDF_Views_Wiki::view', array($request->project->shortname, $page->title)); } @@ -248,7 +248,7 @@ class IDF_WikiRevision extends Pluf_Model } $current_locale = Pluf_Translation::getLocale(); $langs = Pluf::f('languages', array('en')); - Pluf_Translation::loadSetLocale($langs[0]); + Pluf_Translation::loadSetLocale($langs[0]); $context = new Pluf_Template_Context( array( 'page' => $this->get_wikipage(), @@ -260,23 +260,28 @@ class IDF_WikiRevision extends Pluf_Model if ($create) { $template = 'idf/wiki/wiki-created-email.txt'; $title = sprintf(__('New Documentation Page %s - %s (%s)'), - $this->get_wikipage()->title, - $this->get_wikipage()->summary, + $this->get_wikipage()->title, + $this->get_wikipage()->summary, $this->get_wikipage()->get_project()->shortname); } else { $template = 'idf/wiki/wiki-updated-email.txt'; $title = sprintf(__('Documentation Page Changed %s - %s (%s)'), - $this->get_wikipage()->title, - $this->get_wikipage()->summary, + $this->get_wikipage()->title, + $this->get_wikipage()->summary, $this->get_wikipage()->get_project()->shortname); } $tmpl = new Pluf_Template($template); $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $conf->getVal('wiki_notification_email'), - $title); - $email->addTextMessage($text_email); - $email->sendMail(); + + $addresses = explode(',', $conf->getVal('wiki_notification_email')); + foreach ($addresses as $address) { + $email = new Pluf_Mail(Pluf::f('from_email'), + $address, + $title); + $email->addTextMessage($text_email); + $email->sendMail(); + } + Pluf_Translation::loadSetLocale($current_locale); } } diff --git a/src/IDF/templates/idf/admin/tabs.html b/src/IDF/templates/idf/admin/tabs.html index 7a3b25a..f221d61 100644 --- a/src/IDF/templates/idf/admin/tabs.html +++ b/src/IDF/templates/idf/admin/tabs.html @@ -57,7 +57,7 @@ {blocktrans} Only project members and admins have write access to the source.
-If you restrict the access to the source, anonymous access is
+If you restrict the access to the source, anonymous access is
not provided and the users must authenticate themselves with their
password or SSH key.{/blocktrans} @@ -86,7 +86,7 @@ password or SSH key.{/blocktrans}   - + @@ -96,7 +96,7 @@ password or SSH key.{/blocktrans}

{trans 'Instructions:'}

{blocktrans}You can configure here the project tabs access rights and notification emails.{/blocktrans}

-

{blocktrans}Notification emails will be sent from the {$from_email} address, if you send the email to a mailing list, you may need to register this email address. If you do not want to send emails for a given type of changes, simply leave the corresponding field empty.{/blocktrans}

+

{blocktrans}Notification emails will be sent from the {$from_email} address, if you send the email to a mailing list, you may need to register this email address. Multiple email addresses must be separated through commas (','). If you do not want to send emails for a given type of changes, simply leave the corresponding field empty.{/blocktrans}

{blocktrans}If you mark a project as private, only the project members and administrators, together with the extra authorized users you provide will have access to the project. You will still be able to define further access rights for the different tabs but the "Open to all" and "Signed in users" will default to authorized users only.{/blocktrans}

{blocktrans}Specify each person by its login. Each person must have already registered with the given login. Separate the logins with commas and/or new lines.{/blocktrans}

@@ -111,7 +111,7 @@ $(document).ready(function(){ $("#id_private_project").click(function(){ if ($("#id_private_project").is(":checked")) { $("#authorized-users-row").show(); - } else { + } else { $("#authorized-users-row").hide(); } });