diff --git a/src/IDF/Commit.php b/src/IDF/Commit.php index 50c9402..6ea7f97 100644 --- a/src/IDF/Commit.php +++ b/src/IDF/Commit.php @@ -156,25 +156,7 @@ class IDF_Commit extends Pluf_Model $commit->origauthor = $change->author; $commit->creation_dtime = $change->date; $commit->create(); - // We notify the creation of the commit - if ('' != $project->getConf()->getVal('source_notification_email', '')) { - $context = new Pluf_Template_Context( - array( - 'c' => $commit, - 'project' => $project, - 'url_base' => Pluf::f('url_base'), - ) - ); - $tmpl = new Pluf_Template('idf/source/commit-created-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $project->getConf()->getVal('source_notification_email'), - sprintf(__('New Commit %s - %s (%s)'), - $commit->scm_id, $commit->summary, $project->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); - } - + $commit->notify($project->getConf()); return $commit; } @@ -272,4 +254,38 @@ class IDF_Commit extends Pluf_Model '; return $out; } + + /** + * Notification of change of the object. + * + * @param IDF_Conf Current configuration + * @param bool Creation (true) + */ + public function notify($conf, $create=true) + { + if ('' == $conf->getVal('source_notification_email', '')) { + return; + } + $current_locale = Pluf_Translation::getLocale(); + $langs = Pluf::f('languages', array('en')); + Pluf_Translation::loadSetLocale($langs[0]); + + $context = new Pluf_Template_Context( + array( + 'c' => $this, + 'project' => $this->get_project(), + 'url_base' => Pluf::f('url_base'), + ) + ); + $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(); + Pluf_Translation::loadSetLocale($current_locale); + } } diff --git a/src/IDF/Form/ReviewCreate.php b/src/IDF/Form/ReviewCreate.php index 3e5ae4e..2b914e4 100644 --- a/src/IDF/Form/ReviewCreate.php +++ b/src/IDF/Form/ReviewCreate.php @@ -204,26 +204,7 @@ class IDF_Form_ReviewCreate extends Pluf_Form $patch->commit = self::findCommit($this->cleaned_data['commit']); $patch->patch = $this->cleaned_data['patch']; $patch->create(); - // Send create notification - if ('' != $this->project->getConf()->getVal('review_notification_email', '')) { - $context = new Pluf_Template_Context( - array( - 'review' => $review, - 'patch' => $patch, - 'comments' => array(), - 'project' => $this->project, - 'url_base' => Pluf::f('url_base'), - ) - ); - $tmpl = new Pluf_Template('idf/review/review-created-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $this->project->getConf()->getVal('review_notification_email'), - sprintf(__('New Code Review %s - %s (%s)'), - $review->id, $review->summary, $this->project->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); - } + $patch->notify($this->project->getConf()); return $review; } diff --git a/src/IDF/Form/ReviewFileComment.php b/src/IDF/Form/ReviewFileComment.php index a0da84b..3d1b22a 100644 --- a/src/IDF/Form/ReviewFileComment.php +++ b/src/IDF/Form/ReviewFileComment.php @@ -93,6 +93,6 @@ class IDF_Form_ReviewFileComment extends Pluf_Form } $this->patch->get_review()->update(); // reindex and put up in // the list. - return $this->patch; + return $bc; } } diff --git a/src/IDF/Form/Upload.php b/src/IDF/Form/Upload.php index bdd2339..159a592 100644 --- a/src/IDF/Form/Upload.php +++ b/src/IDF/Form/Upload.php @@ -175,21 +175,7 @@ class IDF_Form_Upload extends Pluf_Form $upload->setAssoc($tag); } // Send the notification - if ('' != $this->project->getConf()->getVal('downloads_notification_email', '')) { - $context = new Pluf_Template_Context( - array('file' => $upload, - 'urlfile' => $upload->getAbsoluteUrl($this->project), - 'project' => $this->project, - 'tags' => $upload->get_tags_list(), - )); - $tmpl = new Pluf_Template('idf/downloads/download-created-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), $this->project->getConf()->getVal('downloads_notification_email'), - sprintf(__('New download - %s (%s)'), - $upload->summary, $this->project->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); - } + $upload->notify($this->project->getConf()); return $upload; } } diff --git a/src/IDF/Form/WikiCreate.php b/src/IDF/Form/WikiCreate.php index caee52f..22ecaff 100644 --- a/src/IDF/Form/WikiCreate.php +++ b/src/IDF/Form/WikiCreate.php @@ -199,25 +199,7 @@ Add your content here. Format your content with: $rev->submitter = $this->user; $rev->summary = __('Initial page creation'); $rev->create(); - // send the notification - if ('' != $this->project->getConf()->getVal('wiki_notification_email', '')) { - $context = new Pluf_Template_Context( - array( - 'page' => $page, - 'rev' => $rev, - 'project' => $this->project, - 'url_base' => Pluf::f('url_base'), - ) - ); - $tmpl = new Pluf_Template('idf/wiki/wiki-created-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $this->project->getConf()->getVal('wiki_notification_email'), - sprintf(__('New Documentation Page %s - %s (%s)'), - $page->title, $page->summary, $this->project->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); - } + $rev->notify($this->project->getConf()); return $page; } } diff --git a/src/IDF/Form/WikiUpdate.php b/src/IDF/Form/WikiUpdate.php index 98b4253..bfa9c4e 100644 --- a/src/IDF/Form/WikiUpdate.php +++ b/src/IDF/Form/WikiUpdate.php @@ -236,25 +236,7 @@ class IDF_Form_WikiUpdate extends Pluf_Form $rev->summary = $this->cleaned_data['comment']; $rev->changes = $changes; $rev->create(); - // send the notification - if ('' != $this->project->getConf()->getVal('wiki_notification_email', '')) { - $context = new Pluf_Template_Context( - array( - 'page' => $this->page, - 'rev' => $rev, - 'project' => $this->project, - 'url_base' => Pluf::f('url_base'), - ) - ); - $tmpl = new Pluf_Template('idf/wiki/wiki-updated-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail(Pluf::f('from_email'), - $this->project->getConf()->getVal('wiki_notification_email'), - sprintf(__('Documentation Page Changed %s - %s (%s)'), - $this->page->title, $this->page->summary, $this->project->shortname)); - $email->addTextMessage($text_email); - $email->sendMail(); - } + $rev->notify($this->project->getConf(), false); return $this->page; } } diff --git a/src/IDF/Issue.php b/src/IDF/Issue.php index 462d3e5..47ae074 100644 --- a/src/IDF/Issue.php +++ b/src/IDF/Issue.php @@ -227,4 +227,93 @@ class IDF_Issue extends Pluf_Model 'content' => $content, 'date' => $date)); } + + /** + * Notification of change of the object. + * + * For the moment, only email, but one can add webhooks later. + * + * Usage: + *
+ * $this->notify($conf); // Notify the creation + * $this->notify($conf, false); // Notify the update of the object + *+ * + * @param IDF_Conf Current configuration + * @param bool Creation (true) + */ + public function notify($conf, $create=true) + { + $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]); + } + $current_locale = Pluf_Translation::getLocale(); + + if ($create) { + if (null != $this->get_owner() and $this->owner != $this->submitter) { + $to_email[] = array($this->get_owner()->email, + $this->get_owner()->language); + } + $comments = $this->get_comments_list(array('order' => 'id ASC')); + $context = new Pluf_Template_Context( + array( + 'issue' => $this, + 'comment' => $comments[0], + 'project' => $prj, + 'url_base' => Pluf::f('url_base'), + ) + ); + foreach ($to_email as $email_lang) { + Pluf_Translation::loadSetLocale($email_lang[1]); + $email = new Pluf_Mail(Pluf::f('from_email'), $email_lang[0], + sprintf(__('Issue %s - %s (%s)'), + $this->id, $this->summary, $prj->shortname)); + $tmpl = new Pluf_Template('idf/issues/issue-created-email.txt'); + $email->addTextMessage($tmpl->render($context)); + $email->sendMail(); + } + } else { + $comments = $this->get_comments_list(array('order' => 'id DESC')); + foreach ($this->get_interested_list() as $interested) { + $email_lang = array($interested->email, + $interested->language); + if (!in_array($email_lang, $to_email)) { + $to_email[] = $email_lang; + } + } + $email_lang = array($this->get_submitter()->email, + $this->get_submitter()->language); + if (!in_array($email_lang, $to_email)) { + $to_email[] = $email_lang; + } + if (null != $this->get_owner()) { + $email_lang = array($this->get_owner()->email, + $this->get_owner()->language); + if (!in_array($email_lang, $to_email)) { + $to_email[] = $email_lang; + } + } + $context = new Pluf_Template_Context( + array( + 'issue' => $this, + 'comments' => $comments, + 'project' => $prj, + 'url_base' => Pluf::f('url_base'), + )); + foreach ($to_email as $email_lang) { + Pluf_Translation::loadSetLocale($email_lang[1]); + $email = new Pluf_Mail(Pluf::f('from_email'), $email_lang[0], + sprintf(__('Updated Issue %s - %s (%s)'), + $this->id, $this->summary, $prj->shortname)); + $tmpl = new Pluf_Template('idf/issues/issue-updated-email.txt'); + $email->addTextMessage($tmpl->render($context)); + $email->sendMail(); + } + } + Pluf_Translation::loadSetLocale($current_locale); + } } \ No newline at end of file diff --git a/src/IDF/Review/Comment.php b/src/IDF/Review/Comment.php index 4cda7ed..cbf4e3d 100644 --- a/src/IDF/Review/Comment.php +++ b/src/IDF/Review/Comment.php @@ -140,4 +140,58 @@ class IDF_Review_Comment extends Pluf_Model { return ''; } + + /** + * Notify of the update of the review. + * + * + * @param IDF_Conf Current configuration + * @param bool Creation (true) + */ + public function notify($conf, $create=true) + { + $patch = $this->get_patch(); + $review = $patch->get_review(); + $prj = $review->get_project(); + $to_email = array(); + if ('' != $conf->getVal('review_notification_email', '')) { + $langs = Pluf::f('languages', array('en')); + $to_email[] = array($conf->getVal('issues_notification_email'), + $langs[0]); + } + $current_locale = Pluf_Translation::getLocale(); + $reviewers = $review->getReviewers(); + if (!Pluf_Model_InArray($review->get_submitter(), $reviewers)) { + $reviewers[] = $review->get_submitter(); + } + $comments = $patch->getFileComments(array('order' => 'id DESC')); + $context = new Pluf_Template_Context( + array( + 'review' => $review, + 'patch' => $patch, + 'comments' => $comments, + 'project' => $prj, + 'url_base' => Pluf::f('url_base'), + ) + ); + // build the list of emails and lang + foreach ($reviewers as $user) { + $email_lang = array($user->email, + $user->language); + if (!in_array($email_lang, $to_email)) { + $to_email[] = $email_lang; + } + } + $tmpl = new Pluf_Template('idf/review/review-updated-email.txt'); + foreach ($to_email as $email_lang) { + Pluf_Translation::loadSetLocale($email_lang[1]); + $email = new Pluf_Mail(Pluf::f('from_email'), $email_lang[0], + sprintf(__('Updated Code Review %s - %s (%s)'), + $review->id, $review->summary, $prj->shortname)); + + $email->addTextMessage($tmpl->render($context)); + $email->sendMail(); + } + Pluf_Translation::loadSetLocale($current_locale); + } } diff --git a/src/IDF/Review/Patch.php b/src/IDF/Review/Patch.php index decf17f..83186fe 100644 --- a/src/IDF/Review/Patch.php +++ b/src/IDF/Review/Patch.php @@ -138,4 +138,35 @@ class IDF_Review_Patch extends Pluf_Model { return ''; } + + public function notify($conf, $create=true) + { + if ('' == $conf->getVal('review_notification_email', '')) { + return; + } + $current_locale = Pluf_Translation::getLocale(); + $langs = Pluf::f('languages', array('en')); + Pluf_Translation::loadSetLocale($langs[0]); + + $context = new Pluf_Template_Context( + array( + 'review' => $this->get_review(), + 'patch' => $this, + 'comments' => array(), + 'project' => $this->get_review()->get_project(), + 'url_base' => Pluf::f('url_base'), + ) + ); + $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(); + Pluf_Translation::loadSetLocale($current_locale); + } } diff --git a/src/IDF/Upload.php b/src/IDF/Upload.php index 4f849be..4c93293 100644 --- a/src/IDF/Upload.php +++ b/src/IDF/Upload.php @@ -218,4 +218,38 @@ class IDF_Upload extends Pluf_Model 'content' => $content, 'date' => $date)); } + + /** + * Notification of change of the object. + * + * @param IDF_Conf Current configuration + * @param bool Creation (true) + */ + public function notify($conf, $create=true) + { + if ('' == $conf->getVal('downloads_notification_email', '')) { + return; + } + $current_locale = Pluf_Translation::getLocale(); + $langs = Pluf::f('languages', array('en')); + Pluf_Translation::loadSetLocale($langs[0]); + + $context = new Pluf_Template_Context( + array('file' => $this, + 'urlfile' => $this->getAbsoluteUrl($this->get_project()), + 'project' => $this->get_project(), + 'tags' => $this->get_tags_list(), + )); + $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(); + + Pluf_Translation::loadSetLocale($current_locale); + } } \ No newline at end of file diff --git a/src/IDF/Views/Issue.php b/src/IDF/Views/Issue.php index 596792a..211e4b4 100644 --- a/src/IDF/Views/Issue.php +++ b/src/IDF/Views/Issue.php @@ -175,30 +175,7 @@ class IDF_Views_Issue $issue = $form->save(); $url = Pluf_HTTP_URL_urlForView('IDF_Views_Issue::view', array($prj->shortname, $issue->id)); - $to_emails = array(); - if (null != $issue->get_owner() and $issue->owner != $issue->submitter) { - $to_emails[] = $issue->get_owner()->email; - } - if ('' != $request->conf->getVal('issues_notification_email', '')) { - $to_emails[] = $request->conf->getVal('issues_notification_email', ''); - } - foreach ($to_emails as $oemail) { - $comments = $issue->get_comments_list(array('order' => 'id ASC')); - $context = new Pluf_Template_Context( - array( - 'issue' => $issue, - 'comment' => $comments[0], - 'project' => $prj, - 'url_base' => Pluf::f('url_base'), - ) - ); - $email = new Pluf_Mail(Pluf::f('from_email'), $oemail, - sprintf(__('Issue %s - %s (%s)'), - $issue->id, $issue->summary, $prj->shortname)); - $tmpl = new Pluf_Template('idf/issues/issue-created-email.txt'); - $email->addTextMessage($tmpl->render($context)); - $email->sendMail(); - } + $issue->notify($request->conf); if ($api) return $issue; $request->user->setMessage(sprintf(__('Issue %d has been created.'), $url, $issue->id)); return new Pluf_HTTP_Response_Redirect($url); @@ -290,45 +267,11 @@ class IDF_Views_Issue $request->FILES), $params); if (!isset($request->POST['preview']) && $form->isValid()) { - $issue = $form->save(); + $issue = $form->save(); // Note, should return the + // last comment + $issue->notify($request->conf, false); $comments = $issue->get_comments_list(array('order' => 'id DESC')); $url .= '#ic' . $comments[0]->id; - // Get the list of interested person + owner + submitter - if (!Pluf_Model_InArray($issue->get_submitter(), $interested)) { - $interested[] = $issue->get_submitter(); - } - if (null != $issue->get_owner() and - !Pluf_Model_InArray($issue->get_owner(), $interested)) { - $interested[] = $issue->get_owner(); - } - $context = new Pluf_Template_Context( - array( - 'issue' => $issue, - 'comments' => $comments, - 'project' => $prj, - 'url_base' => Pluf::f('url_base'), - )); - $tmpl = new Pluf_Template('idf/issues/issue-updated-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail_Batch(Pluf::f('from_email')); - $to_emails = array(); - foreach ($interested as $user) { - if ($user->id != $request->user->id) { - $to_emails[] = $user->email; - } - } - if ('' != $request->conf->getVal('issues_notification_email', '')) { - $to_emails[] = $request->conf->getVal('issues_notification_email'); - } - foreach ($to_emails as $oemail) { - $email->setSubject(sprintf(__('Updated Issue %s - %s (%s)'), - $issue->id, $issue->summary, $prj->shortname)); - $email->setTo($oemail); - $email->setReturnPath(Pluf::f('from_email')); - $email->addTextMessage($text_email); - $email->sendMail(); - } - $email->close(); $request->user->setMessage(sprintf(__('Issue %d has been updated.'), $url, $issue->id)); return new Pluf_HTTP_Response_Redirect($url); } diff --git a/src/IDF/Views/Review.php b/src/IDF/Views/Review.php index 17ddd9b..5316f4d 100644 --- a/src/IDF/Views/Review.php +++ b/src/IDF/Views/Review.php @@ -152,49 +152,14 @@ class IDF_Views_Review 'patch' => $patch, )); if ($form->isValid()) { - $patch = $form->save(); + $review_comment = $form->save(); $review = $patch->get_review(); $urlr = Pluf_HTTP_URL_urlForView('IDF_Views_Review::view', array($prj->shortname, $review->id)); $request->user->setMessage(sprintf(__('Your code review %d has been published.'), $urlr, $review->id)); $url = Pluf_HTTP_URL_urlForView('IDF_Views_Review::index', array($prj->shortname)); - // Get the list of reviewers + submitter - $reviewers = $review->getReviewers(); - if (!Pluf_Model_InArray($review->get_submitter(), $reviewers)) { - $reviewers[] = $review->get_submitter(); - } - $comments = $patch->getFileComments(array('order' => 'id DESC')); - $context = new Pluf_Template_Context( - array( - 'review' => $review, - 'patch' => $patch, - 'comments' => $comments, - 'project' => $prj, - 'url_base' => Pluf::f('url_base'), - ) - ); - $tmpl = new Pluf_Template('idf/review/review-updated-email.txt'); - $text_email = $tmpl->render($context); - $email = new Pluf_Mail_Batch(Pluf::f('from_email')); - $to_emails = array(); - foreach ($reviewers as $user) { - if ($user->id != $request->user->id) { - $to_emails[] = $user->email; - } - } - if ('' != $request->conf->getVal('review_notification_email', '')) { - $to_emails[] = $request->conf->getVal('review_notification_email'); - } - foreach ($to_emails as $oemail) { - $email->setSubject(sprintf(__('Updated Code Review %s - %s (%s)'), - $review->id, $review->summary, $prj->shortname)); - $email->setTo($oemail); - $email->setReturnPath(Pluf::f('from_email')); - $email->addTextMessage($text_email); - $email->sendMail(); - } - $email->close(); + $review_comment->notify($request->conf); return new Pluf_HTTP_Response_Redirect($url); } } else { diff --git a/src/IDF/WikiRevision.php b/src/IDF/WikiRevision.php index 8dbf070..135a8f8 100644 --- a/src/IDF/WikiRevision.php +++ b/src/IDF/WikiRevision.php @@ -218,4 +218,60 @@ class IDF_WikiRevision extends Pluf_Model 'date' => $date)); } + + /** + * Notification of change of a WikiPage. + * + * The content of a WikiPage is in the IDF_WikiRevision object, + * this is why we send the notificatin from there. This means that + * when the create flag is set, this is for the creation of a + * wikipage and not, for the addition of a new revision. + * + * Usage: + *
+ * $this->notify($conf); // Notify the creation of a wiki page + * $this->notify($conf, false); // Notify the update of the page + *+ * + * @param IDF_Conf Current configuration + * @param bool Creation (true) + */ + public function notify($conf, $create=true) + { + if ('' == $conf->getVal('wiki_notification_email', '')) { + return; + } + $current_locale = Pluf_Translation::getLocale(); + $langs = Pluf::f('languages', array('en')); + Pluf_Translation::loadSetLocale($langs[0]); + $context = new Pluf_Template_Context( + array( + 'page' => $this->get_wikipage(), + 'rev' => $this, + 'project' => $this->get_wikipage()->get_project(), + 'url_base' => Pluf::f('url_base'), + ) + ); + 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()->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()->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(); + Pluf_Translation::loadSetLocale($current_locale); + } } diff --git a/src/IDF/templates/idf/review/review-created-email.txt b/src/IDF/templates/idf/review/review-created-email.txt index af19808..63575df 100644 --- a/src/IDF/templates/idf/review/review-created-email.txt +++ b/src/IDF/templates/idf/review/review-created-email.txt @@ -3,6 +3,7 @@ {blocktrans}The following review has been created:{/blocktrans} {$review.id} - {$review.summary|safe} + {trans 'Project:'} {$project.name|safe} {trans 'Status:'} {$review.get_status.name} {trans 'Reported by:'} {$review.get_submitter|safe} diff --git a/src/IDF/templates/idf/review/review-updated-email.txt b/src/IDF/templates/idf/review/review-updated-email.txt index 7562da2..52e4049 100644 --- a/src/IDF/templates/idf/review/review-updated-email.txt +++ b/src/IDF/templates/idf/review/review-updated-email.txt @@ -15,7 +15,6 @@ {foreach $comments as $c}{assign $who = $c.get_comment().get_submitter()}# {blocktrans}By {$who|safe}, {$c.creation_dtime|date}, on file: {$c.cfile|safe} {/blocktrans} - {$c.content|safe} {/foreach} diff --git a/src/IDF/templates/idf/source/commit-created-email.txt b/src/IDF/templates/idf/source/commit-created-email.txt index 1734922..4e09f37 100644 --- a/src/IDF/templates/idf/source/commit-created-email.txt +++ b/src/IDF/templates/idf/source/commit-created-email.txt @@ -3,6 +3,7 @@ {blocktrans}A new commit has been created:{/blocktrans} {$c.summary|safe} + {trans 'Commit:'} {$c.scm_id|safe} {trans 'Project:'} {$project.name|safe} {trans 'Created by:'} {$c.get_author|safe}