Merge branch '0.9.x' into 1.0.x

Conflicts:
	classes/Memcached_DataObject.php
This commit is contained in:
Brion Vibber 2010-12-17 17:13:21 -08:00
commit d8a3a88ec8
20 changed files with 466 additions and 143 deletions

View File

@ -999,7 +999,7 @@ StartXrdActionAliases: About to set aliases for the XRD object for a user
EndXrdActionAliases: Done with aliases for the XRD object for a user EndXrdActionAliases: Done with aliases for the XRD object for a user
- &$xrd: XRD object being shown - &$xrd: XRD object being shown
- $user: User being shown - $user: User being shown
StartXrdActionLinks: About to set links for the XRD object for a user StartXrdActionLinks: About to set links for the XRD object for a user
- &$xrd: XRD object being shown - &$xrd: XRD object being shown
- $user: User being shown - $user: User being shown
@ -1007,3 +1007,13 @@ StartXrdActionLinks: About to set links for the XRD object for a user
EndXrdActionLinks: Done with links for the XRD object for a user EndXrdActionLinks: Done with links for the XRD object for a user
- &$xrd: XRD object being shown - &$xrd: XRD object being shown
- $user: User being shown - $user: User being shown
AdminPanelCheck: When checking whether the current user can access a given admin panel
- $name: Name of the admin panel
- &$isOK: Boolean whether the user is allowed to use the panel
StartAdminPanelNav: Before displaying the first item in the list of admin panels
- $nav The AdminPanelNav widget
EndAdminPanelNav: After displaying the last item in the list of admin panels
- $nav The AdminPanelNav widget

View File

@ -0,0 +1,135 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Return a user's avatar image
*
* 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 API
* @package StatusNet
* @author Brion Vibber <brion@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);
}
require_once INSTALLDIR . '/lib/apiprivateauth.php';
/**
* Ouputs avatar URL for a user, specified by screen name.
* Unlike most API endpoints, this returns an HTTP redirect rather than direct data.
*
* @category API
* @package StatusNet
* @author Brion Vibber <brion@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/
*/
class ApiUserProfileImageAction extends ApiPrivateAuthAction
{
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*
*/
function prepare($args)
{
parent::prepare($args);
$this->user = User::staticGet('nickname', $this->arg('screen_name'));
$this->size = $this->arg('size');
return true;
}
/**
* Handle the request
*
* Check the format and show the user info
*
* @param array $args $_REQUEST data (unused)
*
* @return void
*/
function handle($args)
{
parent::handle($args);
if (empty($this->user)) {
// TRANS: Client error displayed when requesting user information for a non-existing user.
$this->clientError(_('User not found.'), 404, $this->format);
return;
}
$profile = $this->user->getProfile();
if (empty($profile)) {
// TRANS: Client error displayed when requesting user information for a user without a profile.
$this->clientError(_('User has no profile.'));
return;
}
$size = $this->avatarSize();
$avatar = $profile->getAvatar($size);
if ($avatar) {
$url = $avatar->displayUrl();
} else {
$url = Avatar::defaultImage($size);
}
// We don't actually output JSON or XML data -- redirect!
common_redirect($url, 302);
}
/**
* Get the appropriate pixel size for an avatar based on the request...
*
* @return int
*/
private function avatarSize()
{
switch ($this->size) {
case 'mini':
return AVATAR_MINI_SIZE; // 24x24
case 'bigger':
return AVATAR_PROFILE_SIZE; // Twitter does 73x73, but we do 96x96
case 'normal': // fall through
default:
return AVATAR_STREAM_SIZE; // 48x48
}
}
/**
* Return true if read only.
*
* MAY override
*
* @param array $args other arguments
*
* @return boolean is read only action?
*/
function isReadOnly($args)
{
return true;
}
}

View File

@ -311,7 +311,7 @@ class ProfileNoticeListItem extends DoFollowListItem
'class' => 'url'); 'class' => 'url');
if (!empty($this->profile->fullname)) { if (!empty($this->profile->fullname)) {
$attrs['title'] = $this->getFancyName(); $attrs['title'] = $this->profile->getFancyName();
} }
$this->out->elementStart('span', 'repeat'); $this->out->elementStart('span', 'repeat');

View File

@ -85,6 +85,19 @@ class Fave extends Memcached_DataObject
return $ids; return $ids;
} }
/**
* Note that the sorting for this is by order of *fave* not order of *notice*.
*
* @fixme add since_id, max_id support?
*
* @param <type> $user_id
* @param <type> $own
* @param <type> $offset
* @param <type> $limit
* @param <type> $since_id
* @param <type> $max_id
* @return <type>
*/
function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id) function _streamDirect($user_id, $own, $offset, $limit, $since_id, $max_id)
{ {
$fav = new Fave(); $fav = new Fave();

View File

@ -339,10 +339,14 @@ class Memcached_DataObject extends Safe_DataObject
$start = microtime(true); $start = microtime(true);
$fail = false; $fail = false;
try { $result = null;
$result = parent::_query($string); if (Event::handle('StartDBQuery', array($this, $string, &$result))) {
} catch (Exception $e) { try {
$fail = $e; $result = parent::_query($string);
} catch (Exception $e) {
$fail = $e;
}
Event::handle('EndDBQuery', array($this, $string, &$result));
} }
$delta = microtime(true) - $start; $delta = microtime(true) - $start;

View File

@ -654,7 +654,7 @@ class Notice extends Memcached_DataObject
$notice->selectAdd(); // clears it $notice->selectAdd(); // clears it
$notice->selectAdd('id'); $notice->selectAdd('id');
$notice->orderBy('id DESC'); $notice->orderBy('created DESC, id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$notice->limit($offset, $limit); $notice->limit($offset, $limit);
@ -668,13 +668,8 @@ class Notice extends Memcached_DataObject
$notice->whereAdd('is_local !='. Notice::GATEWAY); $notice->whereAdd('is_local !='. Notice::GATEWAY);
} }
if ($since_id != 0) { Notice::addWhereSinceId($notice, $since_id);
$notice->whereAdd('id > ' . $since_id); Notice::addWhereMaxId($notice, $max_id);
}
if ($max_id != 0) {
$notice->whereAdd('id <= ' . $max_id);
}
$ids = array(); $ids = array();
@ -709,19 +704,14 @@ class Notice extends Memcached_DataObject
$notice->conversation = $id; $notice->conversation = $id;
$notice->orderBy('id DESC'); $notice->orderBy('created DESC, id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$notice->limit($offset, $limit); $notice->limit($offset, $limit);
} }
if ($since_id != 0) { Notice::addWhereSinceId($notice, $since_id);
$notice->whereAdd('id > ' . $since_id); Notice::addWhereMaxId($notice, $max_id);
}
if ($max_id != 0) {
$notice->whereAdd('id <= ' . $max_id);
}
$ids = array(); $ids = array();
@ -1695,10 +1685,10 @@ class Notice extends Memcached_DataObject
$notice->repeat_of = $this->id; $notice->repeat_of = $this->id;
$notice->orderBy('created'); // NB: asc! $notice->orderBy('created, id'); // NB: asc!
if (!is_null($offset)) { if (!is_null($limit)) {
$notice->limit($offset, $limit); $notice->limit(0, $limit);
} }
$ids = array(); $ids = array();
@ -1978,4 +1968,108 @@ class Notice extends Memcached_DataObject
$d = new DateTime($dateStr, new DateTimeZone('UTC')); $d = new DateTime($dateStr, new DateTimeZone('UTC'));
return $d->format(DATE_W3C); return $d->format(DATE_W3C);
} }
/**
* Look up the creation timestamp for a given notice ID, even
* if it's been deleted.
*
* @param int $id
* @return mixed string recorded creation timestamp, or false if can't be found
*/
public static function getAsTimestamp($id)
{
if (!$id) {
return false;
}
$notice = Notice::staticGet('id', $id);
if ($notice) {
return $notice->created;
}
$deleted = Deleted_notice::staticGet('id', $id);
if ($deleted) {
return $deleted->created;
}
return false;
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a since_id
* parameter, matching notices posted after the given one (exclusive).
*
* If the referenced notice can't be found, will return false.
*
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function whereSinceId($id, $idField='id', $createdField='created')
{
$since = Notice::getAsTimestamp($id);
if ($since) {
return sprintf("($createdField = '%s' and $idField > %d) or ($createdField > '%s')", $since, $id, $since);
}
return false;
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a since_id
* parameter, matching notices posted after the given one (exclusive), and
* if necessary add it to the data object's query.
*
* @param DB_DataObject $obj
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function addWhereSinceId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
{
$since = self::whereSinceId($id);
if ($since) {
$obj->whereAdd($since);
}
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a max_id
* parameter, matching notices posted before the given one (inclusive).
*
* If the referenced notice can't be found, will return false.
*
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function whereMaxId($id, $idField='id', $createdField='created')
{
$max = Notice::getAsTimestamp($id);
if ($max) {
return sprintf("($createdField < '%s') or ($createdField = '%s' and $idField <= %d)", $max, $max, $id);
}
return false;
}
/**
* Build an SQL 'where' fragment for timestamp-based sorting from a max_id
* parameter, matching notices posted before the given one (inclusive), and
* if necessary add it to the data object's query.
*
* @param DB_DataObject $obj
* @param int $id
* @param string $idField
* @param string $createdField
* @return mixed string or false if no match
*/
public static function addWhereMaxId(DB_DataObject $obj, $id, $idField='id', $createdField='created')
{
$max = self::whereMaxId($id);
if ($max) {
$obj->whereAdd($max);
}
}
} }

View File

@ -55,15 +55,10 @@ class Notice_tag extends Memcached_DataObject
$nt->selectAdd(); $nt->selectAdd();
$nt->selectAdd('notice_id'); $nt->selectAdd('notice_id');
if ($since_id != 0) { Notice::addWhereSinceId($nt, $since_id, 'notice_id');
$nt->whereAdd('notice_id > ' . $since_id); Notice::addWhereMaxId($nt, $max_id, 'notice_id');
}
if ($max_id != 0) { $nt->orderBy('created DESC, notice_id DESC');
$nt->whereAdd('notice_id <= ' . $max_id);
}
$nt->orderBy('notice_id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$nt->limit($offset, $limit); $nt->limit($offset, $limit);

View File

@ -215,26 +215,29 @@ class Profile extends Memcached_DataObject
function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id) function _streamTaggedDirect($tag, $offset, $limit, $since_id, $max_id)
{ {
// XXX It would be nice to do this without a join // XXX It would be nice to do this without a join
// (necessary to do it efficiently on accounts with long history)
$notice = new Notice(); $notice = new Notice();
$query = $query =
"select id from notice join notice_tag on id=notice_id where tag='". "select id from notice join notice_tag on id=notice_id where tag='".
$notice->escape($tag) . $notice->escape($tag) .
"' and profile_id=" . $notice->escape($this->id); "' and profile_id=" . intval($this->id);
if ($since_id != 0) { $since = Notice::whereSinceId($since_id, 'id', 'notice.created');
$query .= " and id > $since_id"; if ($since) {
$query .= " and ($since)";
} }
if ($max_id != 0) { $max = Notice::whereMaxId($max_id, 'id', 'notice.created');
$query .= " and id <= $max_id"; if ($max) {
$query .= " and ($max)";
} }
$query .= ' order by id DESC'; $query .= ' order by notice.created DESC, id DESC';
if (!is_null($offset)) { if (!is_null($offset)) {
$query .= " LIMIT $limit OFFSET $offset"; $query .= " LIMIT " . intval($limit) . " OFFSET " . intval($offset);
} }
$notice->query($query); $notice->query($query);
@ -252,58 +255,22 @@ class Profile extends Memcached_DataObject
{ {
$notice = new Notice(); $notice = new Notice();
// Temporary hack until notice_profile_id_idx is updated $notice->profile_id = $this->id;
// to (profile_id, id) instead of (profile_id, created, id).
// It's been falling back to PRIMARY instead, which is really
// very inefficient for a profile that hasn't posted in a few
// months. Even though forcing the index will cause a filesort,
// it's usually going to be better.
if (common_config('db', 'type') == 'mysql') {
$index = '';
$query =
"select id from notice force index (notice_profile_id_idx) ".
"where profile_id=" . $notice->escape($this->id);
if ($since_id != 0) { $notice->selectAdd();
$query .= " and id > $since_id"; $notice->selectAdd('id');
}
if ($max_id != 0) { Notice::addWhereSinceId($notice, $since_id);
$query .= " and id <= $max_id"; Notice::addWhereMaxId($notice, $max_id);
}
$query .= ' order by id DESC'; $notice->orderBy('created DESC, id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$query .= " LIMIT $limit OFFSET $offset"; $notice->limit($offset, $limit);
}
$notice->query($query);
} else {
$index = '';
$notice->profile_id = $this->id;
$notice->selectAdd();
$notice->selectAdd('id');
if ($since_id != 0) {
$notice->whereAdd('id > ' . $since_id);
}
if ($max_id != 0) {
$notice->whereAdd('id <= ' . $max_id);
}
$notice->orderBy('id DESC');
if (!is_null($offset)) {
$notice->limit($offset, $limit);
}
$notice->find();
} }
$notice->find();
$ids = array(); $ids = array();
while ($notice->fetch()) { while ($notice->fetch()) {

View File

@ -50,15 +50,10 @@ class Reply extends Memcached_DataObject
$reply = new Reply(); $reply = new Reply();
$reply->profile_id = $user_id; $reply->profile_id = $user_id;
if ($since_id != 0) { Notice::addWhereSinceId($reply, $since_id, 'notice_id', 'modified');
$reply->whereAdd('notice_id > ' . $since_id); Notice::addWhereMaxId($reply, $max_id, 'notice_id', 'modified');
}
if ($max_id != 0) { $reply->orderBy('modified DESC, notice_id DESC');
$reply->whereAdd('notice_id <= ' . $max_id);
}
$reply->orderBy('notice_id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$reply->limit($offset, $limit); $reply->limit($offset, $limit);

View File

@ -750,19 +750,14 @@ class User extends Memcached_DataObject
$notice->profile_id = $this->id; $notice->profile_id = $this->id;
$notice->whereAdd('repeat_of IS NOT NULL'); $notice->whereAdd('repeat_of IS NOT NULL');
$notice->orderBy('id DESC'); $notice->orderBy('created DESC, id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$notice->limit($offset, $limit); $notice->limit($offset, $limit);
} }
if ($since_id != 0) { Notice::addWhereSinceId($notice, $since_id);
$notice->whereAdd('id > ' . $since_id); Notice::addWhereMaxId($notice, $max_id);
}
if ($max_id != 0) {
$notice->whereAdd('id <= ' . $max_id);
}
$ids = array(); $ids = array();
@ -795,17 +790,17 @@ class User extends Memcached_DataObject
'FROM notice original JOIN notice rept ON original.id = rept.repeat_of ' . 'FROM notice original JOIN notice rept ON original.id = rept.repeat_of ' .
'WHERE original.profile_id = ' . $this->id . ' '; 'WHERE original.profile_id = ' . $this->id . ' ';
if ($since_id != 0) { $since = Notice::whereSinceId($since_id, 'original.id', 'original.created');
$qry .= 'AND original.id > ' . $since_id . ' '; if ($since) {
$qry .= "AND ($since) ";
} }
if ($max_id != 0) { $max = Notice::whereMaxId($max_id, 'original.id', 'original.created');
$qry .= 'AND original.id <= ' . $max_id . ' '; if ($max) {
$qry .= "AND ($max) ";
} }
// NOTE: we sort by fave time, not by notice time! $qry .= 'ORDER BY original.created, original.id DESC ';
$qry .= 'ORDER BY original.id DESC ';
if (!is_null($offset)) { if (!is_null($offset)) {
$qry .= "LIMIT $limit OFFSET $offset"; $qry .= "LIMIT $limit OFFSET $offset";

View File

@ -100,15 +100,10 @@ class User_group extends Memcached_DataObject
$inbox->selectAdd(); $inbox->selectAdd();
$inbox->selectAdd('notice_id'); $inbox->selectAdd('notice_id');
if ($since_id != 0) { Notice::addWhereSinceId($inbox, $since_id, 'notice_id');
$inbox->whereAdd('notice_id > ' . $since_id); Notice::addWhereMaxId($inbox, $max_id, 'notice_id');
}
if ($max_id != 0) { $inbox->orderBy('created DESC, notice_id DESC');
$inbox->whereAdd('notice_id <= ' . $max_id);
}
$inbox->orderBy('notice_id DESC');
if (!is_null($offset)) { if (!is_null($offset)) {
$inbox->limit($offset, $limit); $inbox->limit($offset, $limit);

26
db/096to097.sql Normal file
View File

@ -0,0 +1,26 @@
-- Add indexes for sorting changes in 0.9.7
-- Allows sorting public timeline, api/statuses/repeats, and conversations by timestamp efficiently
alter table notice
add index notice_created_id_is_local_idx (created,id,is_local),
add index notice_repeat_of_created_id_idx (repeat_of, created, id),
drop index notice_repeatof_idx,
add index notice_conversation_created_id_idx (conversation, created, id),
drop index notice_conversation_idx;
-- Allows sorting tag-filtered public timeline by timestamp efficiently
alter table notice_tag add index notice_tag_tag_created_notice_id_idx (tag, created, notice_id);
-- Needed for sorting reply/mentions timelines
alter table reply add index reply_profile_id_modified_notice_id_idx (profile_id, modified, notice_id);
-- Needed for sorting group messages by timestamp
alter table group_inbox add index group_inbox_group_id_created_notice_id_idx (group_id, created, notice_id);
-- Helps make some reverse role lookups more efficient if there's a lot of assigned accounts
alter table profile_role add index profile_role_role_created_profile_id_idx (role, created, profile_id);
-- Fix for sorting a user's group memberships by order joined
alter table group_member add index group_member_profile_id_created_idx (profile_id, created);

View File

@ -126,11 +126,21 @@ create table notice (
location_ns integer comment 'namespace for location', location_ns integer comment 'namespace for location',
repeat_of integer comment 'notice this is a repeat of' references notice (id), repeat_of integer comment 'notice this is a repeat of' references notice (id),
-- For public timeline...
index notice_created_id_is_local_idx (created,id,is_local),
-- For profile timelines...
index notice_profile_id_idx (profile_id,created,id), index notice_profile_id_idx (profile_id,created,id),
index notice_conversation_idx (conversation),
index notice_created_idx (created), -- For api/statuses/repeats...
index notice_repeat_of_created_id_idx (repeat_of, created, id),
-- For conversation views
index notice_conversation_created_id_idx (conversation, created, id),
-- Are these needed/used?
index notice_replyto_idx (reply_to), index notice_replyto_idx (reply_to),
index notice_repeatof_idx (repeat_of),
FULLTEXT(content) FULLTEXT(content)
) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci; ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
@ -151,7 +161,10 @@ create table reply (
constraint primary key (notice_id, profile_id), constraint primary key (notice_id, profile_id),
index reply_notice_id_idx (notice_id), index reply_notice_id_idx (notice_id),
index reply_profile_id_idx (profile_id), index reply_profile_id_idx (profile_id),
index reply_replied_id_idx (replied_id) index reply_replied_id_idx (replied_id),
-- Needed for sorting reply/mentions timelines
index reply_profile_id_modified_notice_id_idx (profile_id, modified, notice_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
@ -296,7 +309,10 @@ create table notice_tag (
constraint primary key (tag, notice_id), constraint primary key (tag, notice_id),
index notice_tag_created_idx (created), index notice_tag_created_idx (created),
index notice_tag_notice_id_idx (notice_id) index notice_tag_notice_id_idx (notice_id),
-- For sorting tag-filtered public timeline
index notice_tag_tag_created_notice_id_idx (tag, created, notice_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
/* Synching with foreign services */ /* Synching with foreign services */
@ -442,7 +458,10 @@ create table group_member (
constraint primary key (group_id, profile_id), constraint primary key (group_id, profile_id),
index group_member_profile_id_idx (profile_id), index group_member_profile_id_idx (profile_id),
index group_member_created_idx (created) index group_member_created_idx (created),
-- To pull up a list of someone's groups in order joined
index group_member_profile_id_created_idx (profile_id, created)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
@ -463,7 +482,10 @@ create table group_inbox (
constraint primary key (group_id, notice_id), constraint primary key (group_id, notice_id),
index group_inbox_created_idx (created), index group_inbox_created_idx (created),
index group_inbox_notice_id_idx (notice_id) index group_inbox_notice_id_idx (notice_id),
-- Needed for sorting group messages by timestamp
index group_inbox_group_id_created_notice_id_idx (group_id, created, notice_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
@ -603,7 +625,8 @@ create table profile_role (
role varchar(32) not null comment 'string representing the role', role varchar(32) not null comment 'string representing the role',
created datetime not null comment 'date the role was granted', created datetime not null comment 'date the role was granted',
constraint primary key (profile_id, role) constraint primary key (profile_id, role),
index profile_role_role_created_profile_id_idx (role, created, profile_id)
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin; ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;

View File

@ -529,6 +529,11 @@ class Router
'id' => Nickname::INPUT_FMT, 'id' => Nickname::INPUT_FMT,
'format' => '(xml|json)')); 'format' => '(xml|json)'));
$m->connect('api/users/profile_image/:screen_name.:format',
array('action' => 'ApiUserProfileImage',
'screen_name' => Nickname::DISPLAY_FMT,
'format' => '(xml|json)'));
// direct messages // direct messages
$m->connect('api/direct_messages.:format', $m->connect('api/direct_messages.:format',

View File

@ -140,7 +140,7 @@ class LdapCommon
function checkPassword($username, $password) function checkPassword($username, $password)
{ {
$entry = $this->get_user($username); $entry = $this->get_user($username,array('dn' => 'dn'));
if(!$entry){ if(!$entry){
return false; return false;
}else{ }else{
@ -168,7 +168,7 @@ class LdapCommon
//throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time')); //throw new Exception(_('Sorry, changing LDAP passwords is not supported at this time'));
return false; return false;
} }
$entry = $this->get_user($username); $entry = $this->get_user($username,array('dn' => 'dn'));
if(!$entry){ if(!$entry){
return false; return false;
}else{ }else{

View File

@ -0,0 +1,66 @@
<?php
/*
* 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);
}
/**
* Check DB queries for filesorts and such and log em.
*
* @package SQLProfilePlugin
* @maintainer Brion Vibber <brion@status.net>
*/
class SQLProfilePlugin extends Plugin
{
private $recursionGuard = false;
function onPluginVersion(&$versions)
{
$versions[] = array('name' => 'SQLProfile',
'version' => STATUSNET_VERSION,
'author' => 'Brion Vibber',
'homepage' => 'http://status.net/wiki/Plugin:SQLProfile',
'rawdescription' =>
_m('Debug tool to watch for poorly indexed DB queries'));
return true;
}
function onStartDBQuery($obj, $query, &$result)
{
if (!$this->recursionGuard && preg_match('/\bselect\b/i', $query)) {
$this->recursionGuard = true;
$xobj = clone($obj);
$explain = $xobj->query('EXPLAIN ' . $query);
$this->recursionGuard = false;
while ($xobj->fetch()) {
$extra = $xobj->Extra;
$evil = (strpos($extra, 'Using filesort') !== false) ||
(strpos($extra, 'Using temporary') !== false);
if ($evil) {
$xquery = $xobj->sanitizeQuery($query);
common_log(LOG_DEBUG, "$extra | $xquery");
}
}
}
return true;
}
}

View File

@ -44,7 +44,7 @@ $n->query('SELECT notice.id, notice.uri ' .
'AND notice_to_status.status_id IS NULL'); 'AND notice_to_status.status_id IS NULL');
while ($n->fetch()) { while ($n->fetch()) {
if (preg_match('#^http://twitter.com/[\w_.]+/status/(\d+)$#', $n->uri, $match)) { if (preg_match('/^http://twitter.com(/#!)?/[\w_.]+/status/(\d+)$/', $n->uri, $match)) {
$status_id = $match[1]; $status_id = $match[1];
Notice_to_status::saveNew($n->id, $status_id); Notice_to_status::saveNew($n->id, $status_id);
} }

View File

@ -45,7 +45,7 @@ function add_twitter_user($twitter_id, $screen_name)
$fuser = new Foreign_user(); $fuser = new Foreign_user();
$fuser->nickname = $screen_name; $fuser->nickname = $screen_name;
$fuser->uri = 'http://twitter.com/' . $screen_name; $fuser->uri = 'http://twitter.com/#!/' . $screen_name;
$fuser->id = $twitter_id; $fuser->id = $twitter_id;
$fuser->service = TWITTER_SERVICE; $fuser->service = TWITTER_SERVICE;
$fuser->created = common_sql_now(); $fuser->created = common_sql_now();

View File

@ -207,7 +207,7 @@ class TwitterImport
*/ */
function makeStatusURI($username, $id) function makeStatusURI($username, $id)
{ {
return 'http://twitter.com/' return 'http://twitter.com/#!/'
. $username . $username
. '/status/' . '/status/'
. $id; . $id;
@ -264,7 +264,7 @@ class TwitterImport
function ensureProfile($user) function ensureProfile($user)
{ {
// check to see if there's already a profile for this user // check to see if there's already a profile for this user
$profileurl = 'http://twitter.com/' . $user->screen_name; $profileurl = 'http://twitter.com/#!/' . $user->screen_name;
$profile = $this->getProfileByUrl($user->screen_name, $profileurl); $profile = $this->getProfileByUrl($user->screen_name, $profileurl);
if (!empty($profile)) { if (!empty($profile)) {
@ -618,15 +618,15 @@ class TwitterImport
static function tagLink($tag) static function tagLink($tag)
{ {
return "<a href='https://twitter.com/search?q=%23{$tag}' class='hashtag'>{$tag}</a>"; return "<a href='https://search.twitter.com/search?q=%23{$tag}' class='hashtag'>{$tag}</a>";
} }
static function atLink($screenName, $fullName=null) static function atLink($screenName, $fullName=null)
{ {
if (!empty($fullName)) { if (!empty($fullName)) {
return "<a href='http://twitter.com/{$screenName}' title='{$fullName}'>{$screenName}</a>"; return "<a href='http://twitter.com/#!/{$screenName}' title='{$fullName}'>{$screenName}</a>";
} else { } else {
return "<a href='http://twitter.com/{$screenName}'>{$screenName}</a>"; return "<a href='http://twitter.com/#!/{$screenName}'>{$screenName}</a>";
} }
} }

View File

@ -43,10 +43,10 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
*/ */
class TwitterOAuthClient extends OAuthClient class TwitterOAuthClient extends OAuthClient
{ {
public static $requestTokenURL = 'https://twitter.com/oauth/request_token'; public static $requestTokenURL = 'https://api.twitter.com/oauth/request_token';
public static $authorizeURL = 'https://twitter.com/oauth/authorize'; public static $authorizeURL = 'https://api.twitter.com/oauth/authorize';
public static $signinUrl = 'https://twitter.com/oauth/authenticate'; public static $signinUrl = 'https://api.twitter.com/oauth/authenticate';
public static $accessTokenURL = 'https://twitter.com/oauth/access_token'; public static $accessTokenURL = 'https://api.twitter.com/oauth/access_token';
/** /**
* Constructor * Constructor
@ -157,7 +157,7 @@ class TwitterOAuthClient extends OAuthClient
*/ */
function verifyCredentials() function verifyCredentials()
{ {
$url = 'https://twitter.com/account/verify_credentials.json'; $url = 'https://api.twitter.com/1/account/verify_credentials.json';
$response = $this->oAuthGet($url); $response = $this->oAuthGet($url);
$twitter_user = json_decode($response); $twitter_user = json_decode($response);
return $twitter_user; return $twitter_user;
@ -175,7 +175,7 @@ class TwitterOAuthClient extends OAuthClient
*/ */
function statusesUpdate($status, $params=array()) function statusesUpdate($status, $params=array())
{ {
$url = 'https://twitter.com/statuses/update.json'; $url = 'https://api.twitter.com/1/statuses/update.json';
if (is_numeric($params)) { if (is_numeric($params)) {
$params = array('in_reply_to_status_id' => intval($params)); $params = array('in_reply_to_status_id' => intval($params));
} }
@ -200,7 +200,7 @@ class TwitterOAuthClient extends OAuthClient
function statusesHomeTimeline($since_id = null, $max_id = null, function statusesHomeTimeline($since_id = null, $max_id = null,
$cnt = null, $page = null) $cnt = null, $page = null)
{ {
$url = 'https://twitter.com/statuses/home_timeline.json'; $url = 'https://api.twitter.com/1/statuses/home_timeline.json';
$params = array('include_entities' => 'true'); $params = array('include_entities' => 'true');
@ -235,7 +235,7 @@ class TwitterOAuthClient extends OAuthClient
function statusesFriends($id = null, $user_id = null, $screen_name = null, function statusesFriends($id = null, $user_id = null, $screen_name = null,
$page = null) $page = null)
{ {
$url = "https://twitter.com/statuses/friends.json"; $url = "https://api.twitter.com/1/statuses/friends.json";
$params = array(); $params = array();
@ -273,7 +273,7 @@ class TwitterOAuthClient extends OAuthClient
function friendsIds($id = null, $user_id = null, $screen_name = null, function friendsIds($id = null, $user_id = null, $screen_name = null,
$page = null) $page = null)
{ {
$url = "https://twitter.com/friends/ids.json"; $url = "https://api.twitter.com/1/friends/ids.json";
$params = array(); $params = array();