Commit 611924e8 authored by Craig Andrews's avatar Craig Andrews

Merge branch '0.9.x' into 1.0.x

parents 78eb9c78 b157fcbb
......@@ -150,6 +150,12 @@ StartAddressData: Allows the site owner to provide additional information about
EndAddressData: At the end of <address>
- $action: the current action
StartShowSiteNotice: Before showing site notice
- $action: the current action
EndShowSiteNotice: After showing site notice
- $action: the current action
StartLoginGroupNav: Before showing the login and register navigation menu
- $action: the current action
......
......@@ -45,6 +45,7 @@ require_once INSTALLDIR . '/lib/apiprivateauth.php';
* @author Evan Prodromou <evan@status.net>
* @author Jeffery To <jeffery.to@gmail.com>
* @author Zach Copley <zach@status.net>
* @author Michele <macno@macno.org>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/
*/
......@@ -68,6 +69,24 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
$this->group = $this->getTargetGroup($this->arg('id'));
if (empty($this->group)) {
$alias = Group_alias::staticGet(
'alias',
common_canonical_nickname($this->arg('id'))
);
if (!empty($alias)) {
$args = array('id' => $alias->group_id, 'format' => $this->format);
common_redirect(common_local_url('ApiGroupShow', $args), 301);
} else {
$this->clientError(
_('Group not found!'),
404,
$this->format
);
}
return;
}
return true;
}
......@@ -85,15 +104,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
{
parent::handle($args);
if (empty($this->group)) {
$this->clientError(
_('Group not found!'),
404,
$this->format
);
return;
}
switch($this->format) {
case 'xml':
$this->showSingleXmlGroup($this->group);
......@@ -105,7 +115,6 @@ class ApiGroupShowAction extends ApiPrivateAuthAction
$this->clientError(_('API method not found.'), 404, $this->format);
break;
}
}
/**
......
......@@ -126,6 +126,6 @@ class ApiStatusesRetweetsAction extends ApiAuthAction
function isReadOnly($args)
{
return false;
return true;
}
}
......@@ -69,66 +69,14 @@ class ApiTimelineRetweetedByMeAction extends ApiAuthAction
{
parent::prepare($args);
$cnt = $this->int('count', self::DEFAULTCOUNT, self::MAXCOUNT, 1);
$this->serverError('Unimplemented', 503);
$page = $this->int('page', 1, (self::MAXNOTICES/$this->cnt));
$since_id = $this->int('since_id');
$max_id = $this->int('max_id');
return true;
}
/**
* Handle the request
*
* show a timeline of the user's repeated notices
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
$offset = ($this->page-1) * $this->cnt;
$limit = $this->cnt;
$strm = $this->auth_user->repeatedByMe($offset, $limit, $this->since_id, $this->max_id);
switch ($this->format) {
case 'xml':
$this->showXmlTimeline($strm);
break;
case 'json':
$this->showJsonTimeline($strm);
break;
case 'atom':
$profile = $this->auth_user->getProfile();
$title = sprintf(_("Repeated by %s"), $this->auth_user->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:RepeatedByMe:" . $this->auth_user->id;
$link = common_local_url('showstream',
array('nickname' => $this->auth_user->nickname));
$this->showAtomTimeline($strm, $title, $id, $link);
break;
default:
$this->clientError(_('API method not found.'), $code = 404);
break;
}
return false;
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
......@@ -136,6 +84,6 @@ class ApiTimelineRetweetedByMeAction extends ApiAuthAction
function isReadOnly($args)
{
return false;
return true;
}
}
......@@ -135,6 +135,6 @@ class ApiTimelineRetweetedToMeAction extends ApiAuthAction
function isReadOnly($args)
{
return false;
return true;
}
}
......@@ -123,4 +123,19 @@ class ApiTimelineRetweetsOfMeAction extends ApiAuthAction
break;
}
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}
......@@ -45,11 +45,23 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/
class DocAction extends Action
{
var $filename;
var $title;
var $output = null;
var $filename = null;
var $title = null;
function prepare($args)
{
parent::prepare($args);
$this->title = $this->trimmed('title');
$this->output = null;
$this->loadDoc();
return true;
}
/**
* Class handler.
* Handle a request
*
* @param array $args array of arguments
*
......@@ -58,51 +70,51 @@ class DocAction extends Action
function handle($args)
{
parent::handle($args);
$this->title = $this->trimmed('title');
$this->output = null;
if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
$this->filename = INSTALLDIR.'/doc-src/'.$this->title;
if (!file_exists($this->filename)) {
$this->clientError(_('No such document.'));
return;
}
$c = file_get_contents($this->filename);
$this->output = common_markup_to_html($c);
Event::handle('EndLoadDoc', array($this->title, &$this->output));
}
$this->showPage();
}
// overrrided to add entry-title class
function showPageTitle() {
/**
* Page title
*
* Gives the page title of the document. Override default for hAtom entry.
*
* @return void
*/
function showPageTitle()
{
$this->element('h1', array('class' => 'entry-title'), $this->title());
}
// overrided to add hentry, and content-inner classes
/**
* Block for content.
*
* Overrides default from Action to wrap everything in an hAtom entry.
*
* @return void.
*/
function showContentBlock()
{
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
$this->showPageTitle();
$this->showPageNoticeBlock();
$this->elementStart('div', array('id' => 'content_inner',
'class' => 'entry-content'));
// show the actual content (forms, lists, whatever)
$this->showContent();
$this->elementEnd('div');
$this->elementEnd('div');
}
{
$this->elementStart('div', array('id' => 'content', 'class' => 'hentry'));
$this->showPageTitle();
$this->showPageNoticeBlock();
$this->elementStart('div', array('id' => 'content_inner',
'class' => 'entry-content'));
// show the actual content (forms, lists, whatever)
$this->showContent();
$this->elementEnd('div');
$this->elementEnd('div');
}
/**
* Display content.
*
* @return nothing
* Shows the content of the document.
*
* @return void
*/
function showContent()
{
$this->raw($this->output);
......@@ -111,6 +123,8 @@ class DocAction extends Action
/**
* Page title.
*
* Uses the title of the document.
*
* @return page title
*/
function title()
......@@ -118,8 +132,74 @@ class DocAction extends Action
return ucfirst($this->title);
}
/**
* These pages are read-only.
*
* @param array $args unused.
*
* @return boolean read-only flag (false)
*/
function isReadOnly($args)
{
return true;
}
function loadDoc()
{
if (Event::handle('StartLoadDoc', array(&$this->title, &$this->output))) {
$this->filename = $this->getFilename();
if (empty($this->filename)) {
throw new ClientException(sprintf(_('No such document "%s"'), $this->title), 404);
}
$c = file_get_contents($this->filename);
$this->output = common_markup_to_html($c);
Event::handle('EndLoadDoc', array($this->title, &$this->output));
}
}
function getFilename()
{
if (file_exists(INSTALLDIR.'/local/doc-src/'.$this->title)) {
$localDef = INSTALLDIR.'/local/doc-src/'.$this->title;
}
$local = glob(INSTALLDIR.'/local/doc-src/'.$this->title.'.*');
if (count($local) || isset($localDef)) {
return $this->negotiateLanguage($local, $localDef);
}
if (file_exists(INSTALLDIR.'/doc-src/'.$this->title)) {
$distDef = INSTALLDIR.'/doc-src/'.$this->title;
}
$dist = glob(INSTALLDIR.'/doc-src/'.$this->title.'.*');
if (count($dist) || isset($distDef)) {
return $this->negotiateLanguage($dist, $distDef);
}
return null;
}
function negotiateLanguage($filenames, $defaultFilename=null)
{
// XXX: do this better
$langcode = common_language();
foreach ($filenames as $filename) {
if (preg_match('/\.'.$langcode.'$/', $filename)) {
return $filename;
}
}
return $defaultFilename;
}
}
......@@ -309,6 +309,8 @@ class ImsettingsAction extends ConnectSettingsAction
$confirm->address_type = 'jabber';
$confirm->user_id = $user->id;
$confirm->code = common_confirmation_code(64);
$confirm->sent = common_sql_now();
$confirm->claimed = common_sql_now();
$result = $confirm->insert();
......@@ -318,11 +320,9 @@ class ImsettingsAction extends ConnectSettingsAction
return;
}
if (!common_config('queue', 'enabled')) {
jabber_confirm_address($confirm->code,
$user->nickname,
$jabber);
}
jabber_confirm_address($confirm->code,
$user->nickname,
$jabber);
$msg = sprintf(_('A confirmation code was sent '.
'to the IM address you added. '.
......
......@@ -251,6 +251,8 @@ class File extends Memcached_DataObject
if($oembed->modified) $enclosure->modified=$oembed->modified;
unset($oembed->size);
}
} else {
return false;
}
}
}
......
......@@ -19,8 +19,6 @@
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Memcached_DataObject extends DB_DataObject
{
/**
......@@ -315,6 +313,39 @@ class Memcached_DataObject extends DB_DataObject
return new ArrayWrapper($cached);
}
/**
* sends query to database - this is the private one that must work
* - internal functions use this rather than $this->query()
*
* Overridden to do logging.
*
* @param string $string
* @access private
* @return mixed none or PEAR_Error
*/
function _query($string)
{
$start = microtime(true);
$result = parent::_query($string);
$delta = microtime(true) - $start;
$limit = common_config('db', 'log_slow_queries');
if (($limit > 0 && $delta >= $limit) || common_config('db', 'log_queries')) {
$clean = $this->sanitizeQuery($string);
common_log(LOG_DEBUG, sprintf("DB query (%0.3fs): %s", $delta, $clean));
}
return $result;
}
// Sanitize a query for logging
// @fixme don't trim spaces in string literals
function sanitizeQuery($string)
{
$string = preg_replace('/\s+/', ' ', $string);
$string = trim($string);
return $string;
}
// We overload so that 'SET NAMES "utf8"' is called for
// each connection
......@@ -353,7 +384,7 @@ class Memcached_DataObject extends DB_DataObject
unset($_DB_DATAOBJECT['CONNECTIONS'][$index]);
}
}
$result = parent::_connect();
if ($result && !$exists) {
......
......@@ -10,8 +10,8 @@ class Queue_item extends Memcached_DataObject
/* the code below is auto generated do not remove the above tag */
public $__table = 'queue_item'; // table name
public $notice_id; // int(4) primary_key not_null
public $transport; // varchar(8) primary_key not_null
public $id; // int(4) primary_key not_null
public $frame; // blob not_null
public $created; // datetime() not_null
public $claimed; // datetime()
......@@ -22,14 +22,21 @@ class Queue_item extends Memcached_DataObject
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
function sequenceKey()
{ return array(false, false); }
static function top($transport=null) {
/**
* @param mixed $transports name of a single queue or array of queues to pull from
* If not specified, checks all queues in the system.
*/
static function top($transports=null) {
$qi = new Queue_item();
if ($transport) {
$qi->transport = $transport;
if ($transports) {
if (is_array($transports)) {
// @fixme use safer escaping
$list = implode("','", array_map('addslashes', $transports));
$qi->whereAdd("transport in ('$list')");
} else {
$qi->transport = $transports;
}
}
$qi->orderBy('created');
$qi->whereAdd('claimed is null');
......@@ -42,7 +49,7 @@ class Queue_item extends Memcached_DataObject
# XXX: potential race condition
# can we force it to only update if claimed is still null
# (or old)?
common_log(LOG_INFO, 'claiming queue item = ' . $qi->notice_id .
common_log(LOG_INFO, 'claiming queue item id = ' . $qi->id .
' for transport ' . $qi->transport);
$orig = clone($qi);
$qi->claimed = common_sql_now();
......@@ -57,9 +64,4 @@ class Queue_item extends Memcached_DataObject
$qi = null;
return null;
}
function pkeyGet($kv)
{
return Memcached_DataObject::pkeyGet('Queue_item', $kv);
}
}
......@@ -428,14 +428,14 @@ tagged = K
tag = K
[queue_item]
notice_id = 129
id = 129
frame = 66
transport = 130
created = 142
claimed = 14
[queue_item__keys]
notice_id = K
transport = K
id = K
[related_group]
group_id = 129
......
......@@ -94,3 +94,19 @@ create table user_location_prefs (
constraint primary key (user_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table queue_item_new (
id integer auto_increment primary key comment 'unique identifier',
frame blob not null comment 'data: object reference or opaque string',
transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
created datetime not null comment 'date this record was created',
claimed datetime comment 'date this item was claimed',
index queue_item_created_idx (created)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
insert into queue_item_new (frame,transport,created,claimed)
select notice_id,transport,created,claimed from queue_item;
alter table queue_item rename to queue_item_old;
alter table queue_item_new rename to queue_item;
create table queue_item_new (
id integer auto_increment primary key comment 'unique identifier',
frame blob not null comment 'data: object reference or opaque string',
transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
created datetime not null comment 'date this record was created',
claimed datetime comment 'date this item was claimed',
index queue_item_created_idx (created)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
insert into queue_item_new (frame,transport,created,claimed)
select notice_id,transport,created,claimed from queue_item;
alter table queue_item rename to queue_item_old;
alter table queue_item_new rename to queue_item;
......@@ -274,13 +274,12 @@ create table remember_me (
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
create table queue_item (
notice_id integer not null comment 'notice queued' references notice (id),
id integer auto_increment primary key comment 'unique identifier',
frame blob not null comment 'data: object reference or opaque string',
transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
created datetime not null comment 'date this record was created',
claimed datetime comment 'date this item was claimed',
constraint primary key (notice_id, transport),
index queue_item_created_idx (created)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
......
......@@ -223,7 +223,7 @@ function markupPost(raw, server) {
},
changeUserTo : function(el) {
$.a.user = el.rel;
$.s.h.a.innerHTML = el.rev + $.a.headerText;
$.s.h.a.appendChild(document.createTextNode(el.rev + $.a.headerText));
$.s.h.a.href = 'http://' + $.a.server + '/' + el.id;
$.f.runSearch();
},
......
......@@ -205,8 +205,10 @@ var SN = { // StatusNet
cookieValue = JSON.parse(cookieValue);
NLat = $('#'+SN.C.S.NoticeLat).val(cookieValue.NLat).val();
NLon = $('#'+SN.C.S.NoticeLon).val(cookieValue.NLon).val();
NLNS = $('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS).val();
NLID = $('#'+SN.C.S.NoticeLocationId).val(cookieValue.NLID).val();
if ($('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS)) {
NLNS = $('#'+SN.C.S.NoticeLocationNs).val(cookieValue.NLNS).val();
NLID = $('#'+SN.C.S.NoticeLocationId).val(cookieValue.NLID).val();
}
}
if (cookieValue == 'disabled') {
NDG = $('#'+SN.C.S.NoticeDataGeo).attr('checked', false).attr('checked');
......@@ -301,8 +303,10 @@ var SN = { // StatusNet
$('#'+SN.C.S.NoticeLat).val(NLat);
$('#'+SN.C.S.NoticeLon).val(NLon);
$('#'+SN.C.S.NoticeLocationNs).val(NLNS);
$('#'+SN.C.S.NoticeLocationId).val(NLID);
if ($('#'+SN.C.S.NoticeLocationNs)) {
$('#'+SN.C.S.NoticeLocationNs).val(NLNS);
$('#'+SN.C.S.NoticeLocationId).val(NLID);
}
$('#'+SN.C.S.NoticeDataGeo).attr('checked', NDG);
}
});
......
......@@ -199,10 +199,6 @@ class Action extends HTMLOutputter // lawsuit
if (Event::handle('StartShowStatusNetStyles', array($this)) &&
Event::handle('StartShowLaconicaStyles', array($this))) {
$this->cssLink('css/display.css',null,'screen, projection, tv');
if (common_config('site', 'mobile')) {
// TODO: "handheld" CSS for other mobile devices
$this->cssLink('css/mobile.css','base','only screen and (max-device-width: 480px)'); // Mobile WebKit
}
$this->cssLink('css/print.css','base','print');
Event::handle('EndShowStatusNetStyles', array($this));
Event::handle('EndShowLaconicaStyles', array($this));
......@@ -373,7 +369,11 @@ class Action extends HTMLOutputter // lawsuit
$this->elementStart('div', array('id' => 'header'));
$this->showLogo();
$this->showPrimaryNav();
$this->showSiteNotice();
if (Event::handle('StartShowSiteNotice', array($this))) {
$this->showSiteNotice();
Event::handle('EndShowSiteNotice', array($this));
}
if (common_logged_in()) {