Merge branch '0.9.x' into 1.0.x

This commit is contained in:
Brion Vibber 2010-08-16 16:56:27 -07:00
commit 0cfaae48a3
16 changed files with 728 additions and 123 deletions

View File

@ -1063,3 +1063,24 @@ StartActivityEnd: before the closing </entry> in a notice activity entry (last c
EndActivityEnd: after the closing </entry> in a notice activity entry EndActivityEnd: after the closing </entry> in a notice activity entry
- &$notice: notice being output - &$notice: notice being output
- &$xs: XMLStringer for output - &$xs: XMLStringer for output
StartNoticeSaveWeb: before saving a notice through the Web interface
- $action: action being executed (instance of NewNoticeAction)
- &$authorId: integer ID of the author
- &$text: text of the notice
- &$options: additional options (location, replies, etc.)
EndNoticeSaveWeb: after saving a notice through the Web interface
- $action: action being executed (instance of NewNoticeAction)
- $notice: notice that was saved
StartRssEntryArray: at the start of copying a notice to an array
- $notice: the notice being copied
- &$entry: the entry (empty at beginning)
EndRssEntryArray: at the end of copying a notice to an array
- $notice: the notice being copied
- &$entry: the entry, with all the fields filled up
NoticeDeleteRelated: at the beginning of deleting related fields to a notice
- $notice: notice being deleted

7
README
View File

@ -2,8 +2,8 @@
README README
------ ------
StatusNet 0.9.4beta2 StatusNet 0.9.4 "Orange Crush"
11 August 2010 16 August 2010
This is the README file for StatusNet, the Open Source microblogging This is the README file for StatusNet, the Open Source microblogging
platform. It includes installation instructions, descriptions of platform. It includes installation instructions, descriptions of
@ -88,9 +88,6 @@ For best compatibility with client software and site federation, and a lot of
bug fixes, it is highly recommended that all public sites upgrade to the new bug fixes, it is highly recommended that all public sites upgrade to the new
version. version.
Changes from 0.9.4beta1:
- fix for daemon config switching on multi-site setup
Notable changes this version: Notable changes this version:
- OpenID and OAuth libraries patched for potential timing attack - OpenID and OAuth libraries patched for potential timing attack

View File

@ -204,10 +204,18 @@ class NewnoticeAction extends Action
$options = array_merge($options, $locOptions); $options = array_merge($options, $locOptions);
} }
$notice = Notice::saveNew($user->id, $content_shortened, 'web', $options); $author_id = $user->id;
$text = $content_shortened;
if (isset($upload)) { if (Event::handle('StartNoticeSaveWeb', array($this, &$author_id, &$text, &$options))) {
$upload->attachToNotice($notice);
$notice = Notice::saveNew($user->id, $content_shortened, 'web', $options);
if (isset($upload)) {
$upload->attachToNotice($notice);
}
Event::handle('EndNoticeSaveWeb', array($this, $notice));
} }
Event::handle('EndSaveNewNoticeWeb', array($this, $user, &$content_shortened, &$options)); Event::handle('EndSaveNewNoticeWeb', array($this, $user, &$content_shortened, &$options));

View File

@ -121,16 +121,19 @@ class Notice extends Memcached_DataObject
$deleted->insert(); $deleted->insert();
} }
// Clear related records if (Event::handle('NoticeDeleteRelated', array($this))) {
$this->clearReplies(); // Clear related records
$this->clearRepeats();
$this->clearFaves();
$this->clearTags();
$this->clearGroupInboxes();
// NOTE: we don't clear inboxes $this->clearReplies();
// NOTE: we don't clear queue items $this->clearRepeats();
$this->clearFaves();
$this->clearTags();
$this->clearGroupInboxes();
// NOTE: we don't clear inboxes
// NOTE: we don't clear queue items
}
$result = parent::delete(); $result = parent::delete();

View File

@ -120,3 +120,21 @@ create table inbox (
); );
create table user_location_prefs (
user_id integer not null /*comment 'user who has the preference'*/ references "user" (id),
share_location int default 1 /* comment 'Whether to share location data'*/,
created timestamp not null /*comment 'date this record was created'*/,
modified timestamp /* comment 'date this record was modified'*/,
primary key (user_id)
);
create table inbox (
user_id integer not null /* comment 'user receiving the notice' */ references "user" (id),
notice_ids bytea /* comment 'packed list of notice ids' */,
primary key (user_id)
);

View File

@ -136,7 +136,6 @@ create table notice (
is_local integer default 0 /* comment 'notice was generated by a user' */, is_local integer default 0 /* comment 'notice was generated by a user' */,
source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */, source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */,
conversation integer /*id of root notice in this conversation' */ references notice (id), conversation integer /*id of root notice in this conversation' */ references notice (id),
location varchar(255) /* comment 'physical location' */,
lat decimal(10,7) /* comment 'latitude'*/ , lat decimal(10,7) /* comment 'latitude'*/ ,
lon decimal(10,7) /* comment 'longitude'*/ , lon decimal(10,7) /* comment 'longitude'*/ ,
location_id integer /* comment 'location id if possible'*/ , location_id integer /* comment 'location id if possible'*/ ,

View File

@ -464,66 +464,71 @@ class ApiAction extends Action
function twitterRssEntryArray($notice) function twitterRssEntryArray($notice)
{ {
$profile = $notice->getProfile();
$entry = array(); $entry = array();
// We trim() to avoid extraneous whitespace in the output if (Event::handle('StartRssEntryArray', array($notice, &$entry))) {
$entry['content'] = common_xml_safe_str(trim($notice->rendered)); $profile = $notice->getProfile();
$entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content));
$entry['link'] = common_local_url('shownotice', array('notice' => $notice->id));
$entry['published'] = common_date_iso8601($notice->created);
$taguribase = TagURI::base(); // We trim() to avoid extraneous whitespace in the output
$entry['id'] = "tag:$taguribase:$entry[link]";
$entry['updated'] = $entry['published']; $entry['content'] = common_xml_safe_str(trim($notice->rendered));
$entry['author'] = $profile->getBestName(); $entry['title'] = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content));
$entry['link'] = common_local_url('shownotice', array('notice' => $notice->id));
$entry['published'] = common_date_iso8601($notice->created);
// Enclosures $taguribase = TagURI::base();
$attachments = $notice->attachments(); $entry['id'] = "tag:$taguribase:$entry[link]";
$enclosures = array();
foreach ($attachments as $attachment) { $entry['updated'] = $entry['published'];
$enclosure_o=$attachment->getEnclosure(); $entry['author'] = $profile->getBestName();
if ($enclosure_o) {
$enclosure = array(); // Enclosures
$enclosure['url'] = $enclosure_o->url; $attachments = $notice->attachments();
$enclosure['mimetype'] = $enclosure_o->mimetype; $enclosures = array();
$enclosure['size'] = $enclosure_o->size;
$enclosures[] = $enclosure; foreach ($attachments as $attachment) {
$enclosure_o=$attachment->getEnclosure();
if ($enclosure_o) {
$enclosure = array();
$enclosure['url'] = $enclosure_o->url;
$enclosure['mimetype'] = $enclosure_o->mimetype;
$enclosure['size'] = $enclosure_o->size;
$enclosures[] = $enclosure;
}
} }
}
if (!empty($enclosures)) { if (!empty($enclosures)) {
$entry['enclosures'] = $enclosures; $entry['enclosures'] = $enclosures;
}
// Tags/Categories
$tag = new Notice_tag();
$tag->notice_id = $notice->id;
if ($tag->find()) {
$entry['tags']=array();
while ($tag->fetch()) {
$entry['tags'][]=$tag->tag;
} }
}
$tag->free();
// RSS Item specific // Tags/Categories
$entry['description'] = $entry['content']; $tag = new Notice_tag();
$entry['pubDate'] = common_date_rfc2822($notice->created); $tag->notice_id = $notice->id;
$entry['guid'] = $entry['link']; if ($tag->find()) {
$entry['tags']=array();
while ($tag->fetch()) {
$entry['tags'][]=$tag->tag;
}
}
$tag->free();
if (isset($notice->lat) && isset($notice->lon)) { // RSS Item specific
// This is the format that GeoJSON expects stuff to be in. $entry['description'] = $entry['content'];
// showGeoRSS() below uses it for XML output, so we reuse it $entry['pubDate'] = common_date_rfc2822($notice->created);
$entry['geo'] = array('type' => 'Point', $entry['guid'] = $entry['link'];
'coordinates' => array((float) $notice->lat,
(float) $notice->lon)); if (isset($notice->lat) && isset($notice->lon)) {
} else { // This is the format that GeoJSON expects stuff to be in.
$entry['geo'] = null; // showGeoRSS() below uses it for XML output, so we reuse it
$entry['geo'] = array('type' => 'Point',
'coordinates' => array((float) $notice->lat,
(float) $notice->lon));
} else {
$entry['geo'] = null;
}
Event::handle('EndRssEntryArray', array($notice, &$entry));
} }
return $entry; return $entry;

View File

@ -22,7 +22,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
//exit with 200 response, if this is checking fancy from the installer //exit with 200 response, if this is checking fancy from the installer
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; } if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
define('STATUSNET_VERSION', '0.9.4beta2'); define('STATUSNET_VERSION', '0.9.4');
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
define('STATUSNET_CODENAME', 'Orange Crush'); define('STATUSNET_CODENAME', 'Orange Crush');

View File

@ -319,7 +319,7 @@ abstract class Installer
$this->updateStatus(sprintf("Adding %s data to database...", $name)); $this->updateStatus(sprintf("Adding %s data to database...", $name));
$res = $this->runDbScript($scr.'.sql', $conn, 'pgsql'); $res = $this->runDbScript($scr.'.sql', $conn, 'pgsql');
if ($res === false) { if ($res === false) {
$this->updateStatus(sprintf("Can't run %d script.", $name), true); $this->updateStatus(sprintf("Can't run %s script.", $name), true);
return false; return false;
} }
} }

View File

@ -169,7 +169,8 @@ class NoticeForm extends Form
function formData() function formData()
{ {
if (Event::handle('StartShowNoticeFormData', array($this))) { if (Event::handle('StartShowNoticeFormData', array($this))) {
$this->out->element('label', array('for' => 'notice_data-text'), $this->out->element('label', array('for' => 'notice_data-text',
'id' => 'notice_data-text-label'),
sprintf(_('What\'s up, %s?'), $this->user->nickname)); sprintf(_('What\'s up, %s?'), $this->user->nickname));
// XXX: vary by defined max size // XXX: vary by defined max size
$this->out->element('textarea', array('id' => 'notice_data-text', $this->out->element('textarea', array('id' => 'notice_data-text',

View File

@ -5367,7 +5367,7 @@ msgid ""
"org/licensing/licenses/agpl-3.0.html)." "org/licensing/licenses/agpl-3.0.html)."
msgstr "" msgstr ""
"Il utilise le logiciel de micro-blogging [StatusNet](http://status.net/), " "Il utilise le logiciel de micro-blogging [StatusNet](http://status.net/), "
"version %s, disponible sous la licence [GNU Affero General Public License] " "version %s, disponible sous la licence [GNU Affero General Public License]"
"(http://www.fsf.org/licensing/licenses/agpl-3.0.html)." "(http://www.fsf.org/licensing/licenses/agpl-3.0.html)."
#. TRANS: DT element for StatusNet site content license. #. TRANS: DT element for StatusNet site content license.

View File

@ -5343,7 +5343,7 @@ msgid ""
"org/licensing/licenses/agpl-3.0.html)." "org/licensing/licenses/agpl-3.0.html)."
msgstr "" msgstr ""
"Ele funciona sobre o software de microblog [StatusNet](http://status.net/), " "Ele funciona sobre o software de microblog [StatusNet](http://status.net/), "
"versão %s, disponível sob a [GNU Affero General Public License] (http://www." "versão %s, disponível sob a [GNU Affero General Public License](http://www."
"fsf.org/licensing/licenses/agpl-3.0.html)." "fsf.org/licensing/licenses/agpl-3.0.html)."
#. TRANS: DT element for StatusNet site content license. #. TRANS: DT element for StatusNet site content license.

171
plugins/DisqusPlugin.php Normal file
View File

@ -0,0 +1,171 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Plugin to add Disqus commenting to notice pages
*
* PHP version 5
*
* LICENCE: 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 Plugin
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
if (!defined('STATUSNET')) {
exit(1);
}
/**
*
* This plugin adds Disqus commenting to your notices. Enabling this
* plugin will make each notice page display the Disqus widget, and
* notice lists will display the number of commments each notice has.
*
* To use this plugin, you need to first register your site with Disqus
* and get a Discus 'shortname' for it.
*
* http://disqus.com
*
* To enable the plugin, put the following in you config.php:
*
* addPlugin(
* 'Disqus', array(
* 'shortname' => 'YOURSHORTNAME',
* 'div_style' => 'width:675px; padding-top:10px; position:relative; float:left;'
* )
* );
*
* NOTE: the 'div_style' in an optional parameter that passes in some
* inline CSS when creating the Disqus widget. It's a shortcut to make
* the widget look OK with the default StatusNet theme. If you leave
* it out you'll have to edit your theme CSS files to make the widget
* look good. You can also control the way the widget looks by
* adding style rules to your theme.
*
* See: http://help.disqus.com/entries/100878-css-customization
*
* @category Plugin
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*
* @see Event
*/
class DisqusPlugin extends Plugin
{
function onEndShowContentBlock($action)
{
if (get_class($action) == 'ShownoticeAction') {
$attrs = array();
$attrs['id'] = 'disqus_thread';
if ($this->div_style) {
$attrs['style'] = $this->div_style;
}
$action->element('div', $attrs, null);
$script = <<<ENDOFSCRIPT
var disqus_identifier = %d;
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://%s.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
ENDOFSCRIPT;
$action->inlineScript(sprintf($script, $action->notice->id, $this->shortname));
$attrs = array();
$attrs['id'] = 'disqus_thread_footer';
if ($this->div_style) {
$attrs['style'] = $this->div_style;
}
$action->elementStart('div', $attrs);
$action->elementStart('noscript');
$action->raw('Please enable JavaScript to view the ');
$noscriptUrl = 'http://disqus.com/?ref_noscript=' . $this->shortname;
$action->element('a', array('href' => $noscriptUrl), 'comments powered by Disqus.');
$action->elementEnd('noscript');
$action->elementStart('a', array('href' => 'http://disqus.com', 'class' => 'dsq-brlink'));
$action->raw('blog comments powered by ');
$action->element('span', array('class' => 'logo-disqus'), 'Disqus');
$action->elementEnd('a');
$action->elementEnd('div');
}
}
function onEndShowScripts($action)
{
// fugly
$script = <<<ENDOFSCRIPT
var disqus_shortname = '%s';
(function () {
var s = document.createElement('script'); s.async = true;
s.src = 'http://disqus.com/forums/%s/count.js';
(document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
}());
ENDOFSCRIPT;
$action->inlineScript(sprintf($script, $this->shortname, $this->shortname));
return true;
}
function onStartShowNoticeItem($noticeListItem)
{
if (empty($noticeListItem->notice->is_local)) {
return true;
}
$noticeListItem->showNotice();
$noticeListItem->showNoticeInfo();
$noticeUrl = $noticeListItem->notice->bestUrl();
$noticeUrl .= '#disqus_thread';
$noticeListItem->out->element(
'a', array('href' => $noticeUrl, 'class' => 'disqus_count', 'Comments')
);
$noticeListItem->showNoticeOptions();
Event::handle('EndShowNoticeItem', array($noticeListItem));
return false;
}
function onPluginVersion(&$versions)
{
$versions[] = array('name' => 'Disqus',
'version' => STATUSNET_VERSION,
'author' => 'Zach Copley',
'homepage' => 'http://status.net/wiki/Plugin:Disqus',
'rawdescription' =>
_m('Use <a href="http://disqus.com/">Disqus</a>'.
' to add commenting to notice pages.'));
return true;
}
}

View File

@ -36,54 +36,26 @@ if (!defined('STATUSNET')) {
* *
* This plugin adds an Echo commenting widget to each notice page on * This plugin adds an Echo commenting widget to each notice page on
* your site. To get it to work, first you'll have to sign up for Echo * your site. To get it to work, first you'll have to sign up for Echo
* (a commercial service) and register your site's URL. * (a for-pay service) and register your site's URL.
* *
* http://aboutecho.com/ * http://aboutecho.com/
* *
* Once you've done that it's pretty straight forward to turn the * Once you've done that it's pretty straight forward to turn the
* plugin on, just add: * plugin on; just add this to your config.php:
* *
* addPlugin('Echo'); * addPlugin(
* 'Echo',
* array('div_style' => 'width:675px; padding-top:10px; position:relative; float:left;')
* );
* *
* to your config.php. The defaults should work OK with the default * NOTE: the 'div_style' in an optional parameter that passes in some
* theme, but there are a lot of options to customize the look and * inline CSS when creating the Echo widget. It's a shortcut to make
* feel of the comment widget. You can control both the CSS for the * the widget look OK with the default StatusNet theme. If you leave
* div that contains the widget, as well as the CSS for the widget * it out you'll have to edit your theme CSS files to make the widget
* itself via config parameters that can be passed into the plugin. * look good. You can also control the way the widget looks by
* See below for a more complex example: * adding style rules to your theme.
* *
* // Custom stylesheet for Echo commenting widget * See: http://wiki.js-kit.com/Skinning-Guide#UsingCSSnbsptocustomizefontsandcolors
* // See: http://wiki.js-kit.com/Skinning-Guide#UsingCSSnbsptocustomizefontsandcolors
* $stylesheet = <<<ENDOFCSS
* .js-CommentsArea { width: 400px; }
* .jsk-HeaderWrapper { display: none; }
* .jsk-ItemUserAvatar { display: none; }
* .jsk-ItemBody { margin-left: -48px; }
* .js-kit-avatars-wrapper { display: none; }
* .js-kit-nonLoggedUserInfo { margin-left: -75px; }
* .js-singleViaLinkWrapper { display: none; }
* .js-CommentsSkin-echo div.jsk-ThreadWrapper { padding: 0px; }
* .js-singleCommentAdminStar { display: none !important; }
* .js-singleCommentName { margin-right: 1em; }
* .js-kit-miniProfile { background-color:#FFFFFF; }
* .jskit-MenuContainer { background-color:#FFFFFF; }
* .jskit-MenuItemMO { background-color: #EDEDED; }
* .jsk-CommentFormButton { display: none; }
* .js-singleCommentReplyable { display: none; }
* .jsk-CommentFormSurface { display: none; }
* .js-kit-tab-follow { display: none; }
* ENDOFCSS;
*
* addPlugin(
* 'Echo',
* array
* (
* // div_css is the css for the div containing the comment widget
* 'div_css' => 'width:675px; padding-top:10px; position:relative; float:left;',
* // stylesheet is the CSS for the comment widget itself
* 'stylesheet' => $stylesheet
* )
* );
* *
* @category Plugin * @category Plugin
* @package StatusNet * @package StatusNet
@ -122,24 +94,14 @@ class EchoPlugin extends Plugin
// NOTE: there are some other attributes that could be useful // NOTE: there are some other attributes that could be useful
// http://wiki.js-kit.com/Echo-Behavior // http://wiki.js-kit.com/Echo-Behavior
if (empty($this->div_css)) { if (!empty($this->div_style)) {
// This CSS seems to work OK with the default theme $attrs['style'] = $this->div_style;
$attrs['style'] = 'width:675px; padding-top:10px; position:relative; float:left;';
} else {
$attrs['style'] = $this->css;
} }
$action->element('div', $attrs, null); $action->element('div', $attrs, null);
} }
} }
function onEndShowStyles($action)
{
if (get_class($action) == 'ShownoticeAction' && !empty($this->stylesheet)) {
$action->style($this->stylesheet);
}
}
function onPluginVersion(&$versions) function onPluginVersion(&$versions)
{ {
$versions[] = array('name' => 'Echo', $versions[] = array('name' => 'Echo',

View File

@ -0,0 +1,282 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* A plugin to add titles to notices
*
* 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 NoticeTitle
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 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);
}
define('NOTICE_TITLE_PLUGIN_VERSION', '0.1');
/**
* NoticeTitle plugin to add an optional title to notices.
*
* Stores notice titles in a secondary table, notice_title.
*
* @category NoticeTitle
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @copyright 2010 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
* @link http://status.net/
*/
class NoticeTitlePlugin extends Plugin
{
/**
* Database schema setup
*
* Add the notice_title helper table
*
* @see Schema
* @see ColumnDef
*
* @return boolean hook value; true means continue processing, false means stop.
*/
function onCheckSchema()
{
$schema = Schema::get();
// For storing titles for notices
$schema->ensureTable('notice_title',
array(new ColumnDef('notice_id',
'integer',
null,
true,
'PRI'),
new ColumnDef('title',
'varchar',
Notice_title::MAXCHARS,
false)));
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 'Notice_title':
include_once $dir . '/'.$cls.'.php';
return false;
default:
return true;
}
}
/**
* Provide plugin version information.
*
* This data is used when showing the version page.
*
* @param array &$versions array of version data arrays; see EVENTS.txt
*
* @return boolean hook value
*/
function onPluginVersion(&$versions)
{
$url = 'http://status.net/wiki/Plugin:NoticeTitle';
$versions[] = array('name' => 'NoticeTitle',
'version' => NOTICE_TITLE_PLUGIN_VERSION,
'author' => 'Evan Prodromou',
'homepage' => $url,
'rawdescription' =>
_m('Adds optional titles to notices'));
return true;
}
/**
* Show title entry when showing notice form
*
* @param Form $form Form being shown
*
* @return boolean hook value
*/
function onStartShowNoticeFormData($form)
{
$form->out->element('style',
null,
'label#notice_data-text-label { display: none }');
$form->out->element('input', array('type' => 'text',
'id' => 'notice_title',
'name' => 'notice_title',
'size' => 40,
'maxlength' => Notice_title::MAXCHARS));
return true;
}
/**
* Validate notice title before saving
*
* @param Action $action NewNoticeAction being executed
* @param integer &$authorId Author ID
* @param string &$text Text of the notice
* @param array &$options Options array
*
* @return boolean hook value
*/
function onStartNoticeSaveWeb($action, &$authorId, &$text, &$options)
{
$title = $action->trimmed('notice_title');
if (!empty($title)) {
if (mb_strlen($title) > Notice_title::MAXCHARS) {
throw new Exception(sprintf(_m("Notice title too long (max %d)",
Notice_title::MAXCHARS)));
}
}
return true;
}
/**
* Save notice title after notice is saved
*
* @param Action $action NewNoticeAction being executed
* @param Notice $notice Notice that was saved
*
* @return boolean hook value
*/
function onEndNoticeSaveWeb($action, $notice)
{
if (!empty($notice)) {
$title = $action->trimmed('notice_title');
if (!empty($title)) {
$nt = new Notice_title();
$nt->notice_id = $notice->id;
$nt->title = $title;
$nt->insert();
}
}
return true;
}
/**
* Show the notice title in lists
*
* @param NoticeListItem $nli NoticeListItem being shown
*
* @return boolean hook value
*/
function onStartShowNoticeItem($nli)
{
$title = Notice_title::fromNotice($nli->notice);
if (!empty($title)) {
$nli->out->element('h4', array('class' => 'notice_title'), $title);
}
return true;
}
/**
* Show the notice title in RSS output
*
* @param Notice $notice Notice being shown
* @param array &$entry array of values used for RSS output
*
* @return boolean hook value
*/
function onEndRssEntryArray($notice, &$entry)
{
$title = Notice_title::fromNotice($notice);
if (!empty($title)) {
$entry['title'] = $title;
}
return true;
}
/**
* Show the notice title in Atom output
*
* @param Notice &$notice Notice being shown
* @param XMLStringer &$xs output context
* @param string &$output string to be output as title
*
* @return boolean hook value
*/
function onStartActivityTitle(&$notice, &$xs, &$output)
{
$title = Notice_title::fromNotice($notice);
if (!empty($title)) {
$output = $title;
}
return true;
}
/**
* Remove title when the notice is deleted
*
* @param Notice $notice Notice being deleted
*
* @return boolean hook value
*/
function onNoticeDeleteRelated($notice)
{
$nt = Notice_title::staticGet('notice_id', $notice->id);
if (!empty($nt)) {
$nt->delete();
}
return true;
}
}

View File

@ -0,0 +1,138 @@
<?php
/**
* Data class for notice titles
*
* PHP version 5
*
* @category Data
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc.
*
* 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/>.
*/
if (!defined('STATUSNET')) {
exit(1);
}
require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
/**
* Data class for notice titles
*
* @category Action
* @package StatusNet
* @author Evan Prodromou <evan@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*
* @see DB_DataObject
*/
class Notice_title extends Memcached_DataObject
{
const MAXCHARS = 255;
public $__table = 'notice_title'; // table name
public $notice_id; // int(4) primary_key not_null
public $title; // varchar(255)
/**
* Get an instance by key
*
* This is a utility method to get a single instance with a given key value.
*
* @param string $k Key to use to lookup (usually 'user_id' for this class)
* @param mixed $v Value to lookup
*
* @return Notice_title object found, or null for no hits
*
*/
function staticGet($k, $v=null)
{
return Memcached_DataObject::staticGet('Notice_title', $k, $v);
}
/**
* return table definition for DB_DataObject
*
* DB_DataObject needs to know something about the table to manipulate
* instances. This method provides all the DB_DataObject needs to know.
*
* @return array array of column definitions
*/
function table()
{
return array('notice_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
'title' => DB_DATAOBJECT_STR);
}
/**
* return key definitions for DB_DataObject
*
* @return array list of key field names
*/
function keys()
{
return array_keys($this->keyTypes());
}
/**
* return key definitions for Memcached_DataObject
*
* @return array list mapping field names to key types
*/
function keyTypes()
{
return array('notice_id' => 'K');
}
/**
* Magic formula for non-autoincrementing integer primary keys
*
* @return array magic three-false array that stops auto-incrementing.
*/
function sequenceKey()
{
return array(false, false, false);
}
/**
* Get a notice title based on the notice
*
* @param Notice $notice Notice to fetch a title for
*
* @return string title of the notice, or null if none
*/
static function fromNotice($notice)
{
$nt = Notice_title::staticGet('notice_id', $notice->id);
if (empty($nt)) {
return null;
} else {
return $nt->title;
}
}
}