--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Data structure for blog entries
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Data structure for blog entries
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BlogEntry extends Managed_DataObject
+{
+ public $__table = 'blog_entry';
+
+ public $id; // UUID
+ public $profile_id; // int
+ public $title; // varchar(255)
+ public $summary; // text
+ public $content; // text
+ public $uri; // text
+ public $url; // text
+ public $created; // datetime
+ public $modified; // datetime
+
+ const TYPE = 'http://activitystrea.ms/schema/1.0/blog-entry';
+
+ static function staticGet($k, $v=null)
+ {
+ return Managed_DataObject::staticGet('blog_entry', $k, $v);
+ }
+
+ static function schemaDef()
+ {
+ return array(
+ 'description' => 'lite blog entry',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'Unique ID (UUID)'),
+ 'profile_id' => array('type' => 'int',
+ 'not null' => true,
+ 'description' => 'Author profile ID'),
+ 'title' => array('type' => 'varchar',
+ 'length' => 255,
+ 'description' => 'title of the entry'),
+ 'summary' => array('type' => 'text',
+ 'description' => 'initial summary'),
+ 'content' => array('type' => 'text',
+ 'description' => 'HTML content of the entry'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'description' => 'URI (probably http://) for this entry'),
+ 'url' => array('type' => 'varchar',
+ 'length' => 255,
+ 'description' => 'URL (probably http://) for this entry'),
+ 'created' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ 'modified' => array('type' => 'datetime',
+ 'not null' => true,
+ 'description' => 'date this record was created'),
+ ),
+ 'primary key' => array('id'),
+ 'foreign keys' => array(
+ 'blog_entry_profile_id_fkey' => array('profile', array('profile_id' => 'id')),
+ ),
+ 'indexes' => array(
+ 'blog_entry_created_idx' => array('created'),
+ 'blog_entry_uri_idx' => array('uri'),
+ ),
+ );
+ }
+
+ static function saveNew($profile, $title, $content, $options=null)
+ {
+ if (is_null($options)) {
+ $options = array();
+ }
+
+ $be = new BlogEntry();
+ $be->id = (string) new UUID();
+ $be->profile_id = $profile->id;
+ $be->title = htmlspecialchars($title);
+ $be->content = $content;
+
+ if (array_key_exists('summary', $options)) {
+ $be->summary = $options['summary'];
+ } else {
+ $be->summary = self::summarize($content);
+ }
+
+ $url = common_local_url('showblogentry', array('id' => $be->id));
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = $url;
+ }
+
+ $be->uri = $options['uri'];
+
+ if (!array_key_exists('url', $options)) {
+ $options['url'] = $url;
+ }
+
+ $be->url = $options['url'];
+
+ if (!array_key_exists('created', $options)) {
+ $be->created = common_sql_now();
+ }
+
+ $be->created = $options['created'];
+
+ $be->modified = common_sql_now();
+
+ $be->insert();
+
+ // Use user's preferences for short URLs, if possible
+
+ try {
+ $user = $profile->getUser();
+ $shortUrl = File_redirection::makeShort($url,
+ empty($user) ? null : $user);
+ } catch (Exception $e) {
+ // Don't let this stop us.
+ $shortUrl = $url;
+ }
+
+ // XXX: this might be too long.
+
+ $options['rendered'] = $be->summary . ' ' .
+ XMLStringer::estring('a', array('href' => $shortUrl,
+ 'class' => 'blog-entry'),
+ _('More...'));
+
+ $summaryText = html_entity_decode(strip_tags($summary), ENT_QUOTES, 'UTF-8');
+
+ if (Notice::contentTooLong($summaryText)) {
+ $summaryText = substr($summaryText, 0, Notice::maxContent() - mb_strlen($shortUrl) - 2) .
+ '… ' . $shortUrl;
+ }
+
+ $content = $summaryText;
+
+ // Override this no matter what.
+
+ $options['object_type'] = self::TYPE;
+
+ $source = array_key_exists('source', $options) ?
+ $options['source'] : 'web';
+
+ Notice::saveNew($profile->id, $content, $source, $options);
+ }
+
+ /**
+ * Summarize the contents of a blog post
+ *
+ * We take the first div or paragraph of the blog post if there's a hit;
+ * Otherwise we take the whole thing.
+ *
+ * @param string $html HTML of full content
+ */
+ static function summarize($html)
+ {
+ if (preg_match('#<p>.*?</p>#s', $html, $matches)) {
+ return $matches[0];
+ } else if (preg_match('#<div>.*?</div>#s', $html, $matches)) {
+ return $matches[0];
+ } else {
+ return $html;
+ }
+ }
+
+ static function fromNotice($notice)
+ {
+ return BlogEntry::staticGet('uri', $notice->uri);
+ }
+
+ function getNotice()
+ {
+ return Notice::staticGet('uri', $this->uri);
+ }
+
+ function asActivityObject()
+ {
+ $obj = new ActivityObject();
+
+ $obj->id = $this->uri;
+ $obj->type = self::TYPE;
+ $obj->title = $this->title;
+ $obj->summary = $this->summary;
+ $obj->content = $this->content;
+ $obj->link = $this->url;
+
+ return $obj;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * A microapp to implement lite blogging
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Blog plugin
+ *
+ * Many social systems have a way to write and share long-form texts with
+ * your network. This microapp plugin lets users post blog entries.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BlogPlugin extends MicroAppPlugin
+{
+ /**
+ * Database schema setup
+ *
+ * @see Schema
+ * @see ColumnDef
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+
+ $schema->ensureTable('blog_entry', BlogEntry::schemaDef());
+
+ return true;
+ }
+
+ /**
+ * Load related modules when needed
+ *
+ * @param string $cls Name of the class to be loaded
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+ function onAutoload($cls)
+ {
+ $dir = dirname(__FILE__);
+
+ switch ($cls)
+ {
+ case 'NewblogentryAction':
+ case 'ShowblogentryAction':
+ include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+ return false;
+ case 'BlogEntryForm':
+ case 'BlogEntryListItem':
+ include_once $dir . '/'.strtolower($cls).'.php';
+ return false;
+ case 'BlogEntry':
+ include_once $dir . '/'.$cls.'.php';
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Map URLs to actions
+ *
+ * @param Net_URL_Mapper $m path-to-action mapper
+ *
+ * @return boolean hook value; true means continue processing, false means stop.
+ */
+ function onRouterInitialized($m)
+ {
+ $m->connect('blog/new',
+ array('action' => 'newblogentry'));
+ $m->connect('blog/:id',
+ array('action' => 'showblogentry'),
+ array('id' => UUID::REGEX));
+ return true;
+ }
+
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array('name' => 'Blog',
+ 'version' => STATUSNET_VERSION,
+ 'author' => 'Evan Prodromou',
+ 'homepage' => 'http://status.net/wiki/Plugin:Blog',
+ 'rawdescription' =>
+ _m('Let users write and share long-form texts.'));
+ return true;
+ }
+
+ function appTitle()
+ {
+ return _m('Blog');
+ }
+
+ function tag()
+ {
+ return 'blog';
+ }
+
+ function types()
+ {
+ return array(BlogEntry::TYPE);
+ }
+
+ function saveNoticeFromActivity($activity, $actor, $options=array())
+ {
+ if (count($activity->objects) != 1) {
+ // TRANS: Exception thrown when there are too many activity objects.
+ throw new ClientException(_m('Too many activity objects.'));
+ }
+
+ $entryObj = $activity->objects[0];
+
+ if ($entryObj->type != BlogEntry::TYPE) {
+ // TRANS: Exception thrown when blog plugin comes across a non-event type object.
+ throw new ClientException(_m('Wrong type for object.'));
+ }
+
+ $notice = null;
+
+ switch ($activity->verb) {
+ case ActivityVerb::POST:
+ $notice = BlogEntry::saveNew($actor,
+ $entryObj->title,
+ $entryObj->content,
+ $options);
+ break;
+ default:
+ // TRANS: Exception thrown when blog plugin comes across a undefined verb.
+ throw new ClientException(_m('Unknown verb for blog entries.'));
+ }
+
+ return $notice;
+ }
+
+ function activityObjectFromNotice($notice)
+ {
+ $entry = BlogEntry::fromNotice($notice);
+
+ if (empty($entry)) {
+ throw new ClientException(sprintf(_('No blog entry for notice %s'),
+ $notice->id));
+ }
+
+ return $entry->asActivityObject();
+ }
+
+ function entryForm($out)
+ {
+ return new BlogEntryForm($out);
+ }
+
+ function deleteRelated($notice)
+ {
+ if ($notice->object_type == BlogEntry::TYPE) {
+ $entry = BlogEntry::fromNotice($notice);
+ if (exists($entry)) {
+ $entry->delete();
+ }
+ }
+ }
+
+ function adaptNoticeListItem($nli)
+ {
+ $notice = $nli->notice;
+
+ if ($notice->object_type == BlogEntry::TYPE) {
+ return new BlogEntryListItem($nli);
+ }
+
+ return null;
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Form for creating a blog entry
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Form for creating a blog entry
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BlogEntryForm extends Form
+{
+ /**
+ * ID of the form
+ *
+ * @return int ID of the form
+ */
+ function id()
+ {
+ return 'form_new_blog_entry';
+ }
+
+ /**
+ * class of the form
+ *
+ * @return string class of the form
+ */
+ function formClass()
+ {
+ return 'form_settings ajax-notice';
+ }
+
+ /**
+ * Action of the form
+ *
+ * @return string URL of the action
+ */
+ function action()
+ {
+ return common_local_url('newblogentry');
+ }
+
+ /**
+ * Data elements of the form
+ *
+ * @return void
+ */
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_blog_entry_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('blog-entry-title',
+ // TRANS: Field label on blog entry form.
+ _m('LABEL','Title'),
+ null,
+ // TRANS: Field title on blog entry form.
+ _m('Title of the blog entry.'),
+ 'title');
+ $this->unli();
+
+ $this->li();
+ $this->out->textarea('blog-entry-content',
+ // TRANS: Field label on event form.
+ _m('LABEL','Text'),
+ null,
+ // TRANS: Field title on event form.
+ _m('Text of the blog entry.'),
+ 'content');
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+
+ $toWidget = new ToSelector($this->out,
+ common_current_user(),
+ null);
+ $toWidget->show();
+
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+ function formActions()
+ {
+ // TRANS: Button text to save an event..
+ $this->out->submit('blog-entry-submit',
+ _m('BUTTON', 'Save'),
+ 'submit',
+ 'submit');
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * NoticeListItem adapter for blog entries
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * NoticeListItem adapter for blog entries
+ *
+ * @category General
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class BlogEntryListItem extends NoticeListItemAdapter
+{
+ function showNotice()
+ {
+ $this->out->elementStart('div', 'entry-title');
+ $this->showAuthor();
+ $this->showContent();
+ $this->out->elementEnd('div');
+ }
+
+ function showContent()
+ {
+ $notice = $this->nli->notice;
+ $out = $this->nli->out;
+
+ $entry = BlogEntry::fromNotice($notice);
+
+ if (empty($entry)) {
+ throw new Exception('BlogEntryListItem used for non-blog notice.');
+ }
+
+ $out->elementStart('h4', array('class' => 'blog-entry-title'));
+ $out->element('a', array('href' => $notice->bestUrl()), $entry->title);
+ $out->elementEnd('h4');
+
+ $out->element('div', 'blog-entry-summary', $entry->summary);
+
+ // XXX: hide content initially; click More... for full text.
+
+ $out->element('div', 'blog-entry-content', $entry->content);
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Save a new blog entry
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Save a new blog entry
+ *
+ * @category Action
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class NewblogentryAction extends Action
+{
+ protected $user;
+ protected $title;
+ protected $content;
+
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+
+ if (!$this->isPost()) {
+ throw new ClientException(_('Must be a POST.'), 405);
+ }
+
+ $this->user = common_current_user();
+
+ if (empty($this->user)) {
+ // TRANS: Client exception thrown when trying to post a blog entry while not logged in.
+ throw new ClientException(_m('Must be logged in to post a blog entry.'),
+ 403);
+ }
+
+ $this->checkSessionToken();
+
+ $this->title = $this->trimmed('title');
+
+ if (empty($this->title)) {
+ // TRANS: Client exception thrown when trying to post a blog entry without providing a title.
+ throw new ClientException(_m('Title required.'));
+ }
+
+ $this->content = $this->trimmed('content');
+
+ if (empty($this->content)) {
+ // TRANS: Client exception thrown when trying to post a blog entry without providing content.
+ throw new ClientException(_m('Content required.'));
+ }
+
+ return true;
+ }
+
+ /**
+ * Handler method
+ *
+ * @param array $argarray is ignored since it's now passed in in prepare()
+ *
+ * @return void
+ */
+
+ function handle($argarray=null)
+ {
+ $options = array();
+
+ // Does the heavy-lifting for getting "To:" information
+
+ ToSelector::fillOptions($this, $options);
+
+ $options['source'] = 'web';
+
+ $profile = $this->user->getProfile();
+
+ $saved = BlogEntry::saveNew($profile,
+ $this->title,
+ $this->content,
+ $options);
+
+ if ($this->boolean('ajax')) {
+ header('Content-Type: text/xml; charset=utf-8');
+ $this->xw->startDocument('1.0', 'UTF-8');
+ $this->elementStart('html');
+ $this->elementStart('head');
+ // TRANS: Page title after sending a notice.
+ $this->element('title', null, _m('Blog entry saved'));
+ $this->elementEnd('head');
+ $this->elementStart('body');
+ $this->showNotice($saved);
+ $this->elementEnd('body');
+ $this->elementEnd('html');
+ } else {
+ common_redirect($saved->bestUrl(), 303);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2011, StatusNet, Inc.
+ *
+ * Show a blog entry
+ *
+ * PHP version 5
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+ // This check helps protect against security problems;
+ // your code file can't be executed directly from the web.
+ exit(1);
+}
+
+/**
+ * Show a blog entry
+ *
+ * @category Blog
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @copyright 2011 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ * @link http://status.net/
+ */
+
+class ShowblogentryAction extends ShownoticeAction
+{
+ protected $id;
+ protected $entry;
+
+ function getNotice()
+ {
+ $this->id = $this->trimmed('id');
+
+ $this->entry = BlogEntry::staticGet('id', $this->id);
+
+ if (empty($this->entry)) {
+ // TRANS: Client exception thrown when referring to a non-existing blog entry.
+ throw new ClientException(_m('No such entry.'), 404);
+ }
+
+ $notice = $this->entry->getNotice();
+
+ if (empty($notice)) {
+ // TRANS: Client exception thrown when referring to a non-existing blog entry.
+ throw new ClientException(_m('No such entry.'), 404);
+ }
+
+ return $notice;
+ }
+
+ /**
+ * Title of the page
+ *
+ * Used by Action class for layout.
+ *
+ * @return string page tile
+ */
+ function title()
+ {
+ // XXX: check for double-encoding
+ return (empty($this->entry->title)) ? _m('Untitled') : $this->entry->title;
+ }
+}