Merge branch 'temp'

This commit is contained in:
Zach Copley 2010-02-05 03:19:12 +00:00
commit 23802e58d6
19 changed files with 530 additions and 81 deletions

View File

@ -66,18 +66,21 @@ class ApiAccountVerifyCredentialsAction extends ApiAuthAction
{
parent::handle($args);
switch ($this->format) {
case 'xml':
case 'json':
$args['id'] = $this->auth_user->id;
$action_obj = new ApiUserShowAction();
if ($action_obj->prepare($args)) {
$action_obj->handle($args);
if (!in_array($this->format, array('xml', 'json'))) {
$this->clientError(_('API method not found.'), $code = 404);
return;
}
break;
default:
header('Content-Type: text/html; charset=utf-8');
print 'Authorized';
$twitter_user = $this->twitterUserArray($this->auth_user->getProfile(), true);
if ($this->format == 'xml') {
$this->initDocument('xml');
$this->showTwitterXmlUser($twitter_user);
$this->endDocument('xml');
} elseif ($this->format == 'json') {
$this->initDocument('json');
$this->showJsonObjects($twitter_user);
$this->endDocument('json');
}
}

View File

@ -67,8 +67,6 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
{
parent::prepare($args);
common_debug("apioauthauthorize");
$this->nickname = $this->trimmed('nickname');
$this->password = $this->arg('password');
$this->oauth_token = $this->arg('oauth_token');
@ -99,24 +97,17 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
} else {
// XXX: make better error messages
if (empty($this->oauth_token)) {
common_debug("No request token found.");
$this->clientError(_('Bad request.'));
$this->clientError(_('No oauth_token parameter provided.'));
return;
}
if (empty($this->app)) {
common_debug('No app for that token.');
$this->clientError(_('Bad request.'));
$this->clientError(_('Invalid token.'));
return;
}
$name = $this->app->name;
common_debug("Requesting auth for app: " . $name);
$this->showForm();
}
@ -124,8 +115,6 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
function handlePost()
{
common_debug("handlePost()");
// check session token for CSRF protection.
$token = $this->trimmed('token');
@ -202,21 +191,15 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
// A callback specified in the app setup overrides whatever
// is passed in with the request.
common_debug("Req token is authorized - doing callback");
if (!empty($this->app->callback_url)) {
$this->callback = $this->app->callback_url;
}
if (!empty($this->callback)) {
// XXX: Need better way to build this redirect url.
$target_url = $this->getCallback($this->callback,
array('oauth_token' => $this->oauth_token));
common_debug("Doing callback to $target_url");
common_redirect($target_url, 303);
} else {
common_debug("callback was empty!");
@ -236,9 +219,12 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
} else if ($this->arg('deny')) {
$datastore = new ApiStatusNetOAuthDataStore();
$datastore->revoke_token($this->oauth_token, 0);
$this->elementStart('p');
$this->raw(sprintf(_("The request token %s has been denied."),
$this->raw(sprintf(_("The request token %s has been denied and revoked."),
$this->oauth_token));
$this->elementEnd('p');
@ -305,12 +291,15 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
$msg = _('The application <strong>%1$s</strong> by ' .
'<strong>%2$s</strong> would like the ability ' .
'to <strong>%3$s</strong> your account data.');
'to <strong>%3$s</strong> your %4$s account data. ' .
'You should only give access to your %4$s account ' .
'to third parties you trust.');
$this->raw(sprintf($msg,
$this->app->name,
$this->app->organization,
$access));
$access,
common_config('site', 'name')));
$this->elementEnd('p');
$this->elementEnd('li');
$this->elementEnd('ul');
@ -372,6 +361,31 @@ class ApiOauthAuthorizeAction extends ApiOauthAction
function showLocalNav()
{
// NOP
}
/**
* Show site notice.
*
* @return nothing
*/
function showSiteNotice()
{
// NOP
}
/**
* Show notice form.
*
* Show the form for posting a new notice
*
* @return nothing
*/
function showNoticeForm()
{
// NOP
}
}

View File

@ -0,0 +1,176 @@
<?php
/**
* StatusNet, the distributed open-source microblogging tool
*
* Action class to delete an OAuth application
*
* 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 Action
* @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') && !defined('LACONICA')) {
exit(1);
}
/**
* Delete an OAuth appliction
*
* @category Action
* @package StatusNet
* @author Zach Copley <zach@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://status.net/
*/
class DeleteapplicationAction extends Action
{
var $app = null;
/**
* Take arguments for running
*
* @param array $args $_REQUEST args
*
* @return boolean success flag
*/
function prepare($args)
{
if (!parent::prepare($args)) {
return false;
}
if (!common_logged_in()) {
$this->clientError(_('You must be logged in to delete an application.'));
return false;
}
$id = (int)$this->arg('id');
$this->app = Oauth_application::staticGet('id', $id);
if (empty($this->app)) {
$this->clientError(_('Application not found.'));
return false;
}
$cur = common_current_user();
if ($cur->id != $this->app->owner) {
$this->clientError(_('You are not the owner of this application.'), 401);
return false;
}
return true;
}
/**
* Handle request
*
* Shows a page with list of favorite notices
*
* @param array $args $_REQUEST args; handled in prepare()
*
* @return void
*/
function handle($args)
{
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// CSRF protection
$token = $this->trimmed('token');
if (!$token || $token != common_session_token()) {
$this->clientError(_('There was a problem with your session token.'));
return;
}
if ($this->arg('no')) {
common_redirect(common_local_url('showapplication',
array('id' => $this->app->id)), 303);
} elseif ($this->arg('yes')) {
$this->handlePost();
common_redirect(common_local_url('oauthappssettings'), 303);
} else {
$this->showPage();
}
}
}
function showContent() {
$this->areYouSureForm();
}
function title() {
return _('Delete application');
}
function showNoticeForm() {
// nop
}
/**
* Confirm with user.
*
* Shows a confirmation form.
*
* @return void
*/
function areYouSureForm()
{
$id = $this->app->id;
$this->elementStart('form', array('id' => 'deleteapplication-' . $id,
'method' => 'post',
'class' => 'form_settings form_entity_block',
'action' => common_local_url('deleteapplication',
array('id' => $this->app->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->element('legend', _('Delete application'));
$this->element('p', null,
_('Are you sure you want to delete this application? '.
'This will clear all data about the application from the '.
'database, including all existing user connections.'));
$this->submit('form_action-no',
_('No'),
'submit form_action-primary',
'no',
_("Do not delete this application"));
$this->submit('form_action-yes',
_('Yes'),
'submit form_action-secondary',
'yes', _('Delete this application'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
}
/**
* Actually delete the app
*
* @return void
*/
function handlePost()
{
$this->app->delete();
}
}

View File

@ -179,6 +179,9 @@ class EditApplicationAction extends OwnerDesignAction
} elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).'));
return;
} else if ($this->nameExists($name)) {
$this->showForm(_('Name already in use. Try another one.'));
return;
} elseif (empty($description)) {
$this->showForm(_('Description is required.'));
return;
@ -260,5 +263,26 @@ class EditApplicationAction extends OwnerDesignAction
common_redirect(common_local_url('oauthappssettings'), 303);
}
/**
* Does the app name already exist?
*
* Checks the DB to see someone has already registered an app
* with the same name.
*
* @param string $name app name to check
*
* @return boolean true if the name already exists
*/
function nameExists($name)
{
$newapp = Oauth_application::staticGet('name', $name);
if (!$newapp) {
return false;
} else {
return $newapp->id != $this->app->id;
}
}
}

View File

@ -158,6 +158,9 @@ class NewApplicationAction extends OwnerDesignAction
if (empty($name)) {
$this->showForm(_('Name is required.'));
return;
} else if ($this->nameExists($name)) {
$this->showForm(_('Name already in use. Try another one.'));
return;
} elseif (mb_strlen($name) > 255) {
$this->showForm(_('Name is too long (max 255 chars).'));
return;
@ -273,5 +276,22 @@ class NewApplicationAction extends OwnerDesignAction
}
/**
* Does the app name already exist?
*
* Checks the DB to see someone has already registered an app
* with the same name.
*
* @param string $name app name to check
*
* @return boolean true if the name already exists
*/
function nameExists($name)
{
$app = Oauth_application::staticGet('name', $name);
return ($app !== false);
}
}

View File

@ -33,6 +33,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
require_once INSTALLDIR . '/lib/connectsettingsaction.php';
require_once INSTALLDIR . '/lib/applicationlist.php';
require_once INSTALLDIR . '/lib/apioauthstore.php';
/**
* Show connected OAuth applications
@ -71,11 +72,6 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
return _('Connected applications');
}
function isReadOnly($args)
{
return true;
}
/**
* Instructions for use
*
@ -153,6 +149,13 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
}
}
/**
* Revoke access to an authorized OAuth application
*
* @param int $appId the ID of the application
*
*/
function revokeAccess($appId)
{
$cur = common_current_user();
@ -164,6 +167,8 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
return false;
}
// XXX: Transaction here?
$appUser = Oauth_application_user::getByKeys($cur, $app);
if (empty($appUser)) {
@ -171,12 +176,13 @@ class OauthconnectionssettingsAction extends ConnectSettingsAction
return false;
}
$orig = clone($appUser);
$appUser->access_type = 0; // No access
$result = $appUser->update();
$datastore = new ApiStatusNetOAuthDataStore();
$datastore->revoke_token($appUser->token, 1);
$result = $appUser->delete();
if (!$result) {
common_log_db_error($orig, 'UPDATE', __FILE__);
common_log_db_error($orig, 'DELETE', __FILE__);
$this->clientError(_('Unable to revoke access for app: ' . $app->id));
return false;
}

View File

@ -149,7 +149,6 @@ class ShowApplicationAction extends OwnerDesignAction
function showContent()
{
$cur = common_current_user();
$consumer = $this->application->getConsumer();
@ -201,7 +200,7 @@ class ShowApplicationAction extends OwnerDesignAction
$userCnt = $appUsers->count();
$this->raw(sprintf(
_('created by %1$s - %2$s access by default - %3$d users'),
_('Created by %1$s - %2$s access by default - %3$d users'),
$profile->getBestName(),
$defaultAccess,
$userCnt
@ -222,18 +221,39 @@ class ShowApplicationAction extends OwnerDesignAction
$this->elementStart('li', 'entity_reset_keysecret');
$this->elementStart('form', array(
'id' => 'forma_reset_key',
'id' => 'form_reset_key',
'class' => 'form_reset_key',
'method' => 'POST',
'action' => common_local_url('showapplication',
array('id' => $this->application->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->submit('reset', _('Reset key & secret'));
$this->element('input', array('type' => 'submit',
'id' => 'reset',
'name' => 'reset',
'class' => 'submit',
'value' => _('Reset key & secret'),
'onClick' => 'return confirmReset()'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
$this->elementEnd('li');
$this->elementStart('li', 'entity_delete');
$this->elementStart('form', array(
'id' => 'form_delete_application',
'class' => 'form_delete_application',
'method' => 'POST',
'action' => common_local_url('deleteapplication',
array('id' => $this->application->id))));
$this->elementStart('fieldset');
$this->hidden('token', common_session_token());
$this->submit('delete', _('Delete'));
$this->elementEnd('fieldset');
$this->elementEnd('form');
$this->elementEnd('li');
$this->elementEnd('ul');
$this->elementEnd('div');
@ -276,14 +296,53 @@ class ShowApplicationAction extends OwnerDesignAction
$this->elementEnd('p');
}
/**
* Add a confirm script for Consumer key/secret reset
*
* @return void
*/
function showScripts()
{
parent::showScripts();
$msg = _('Are you sure you want to reset your consumer key and secret?');
$js = 'function confirmReset() { ';
$js .= ' var agree = confirm("' . $msg . '"); ';
$js .= ' return agree;';
$js .= '}';
$this->inlineScript($js);
}
/**
* Reset an application's Consumer key and secret
*
* XXX: Should this be moved to its own page with a confirm?
*
*/
function resetKey()
{
$this->application->query('BEGIN');
$oauser = new Oauth_application_user();
$oauser->application_id = $this->application->id;
$result = $oauser->delete();
if ($result === false) {
common_log_db_error($oauser, 'DELETE', __FILE__);
$this->success = false;
$this->msg = ('Unable to reset consumer key and secret.');
$this->showPage();
return;
}
$consumer = $this->application->getConsumer();
$result = $consumer->delete();
if (!$result) {
if ($result === false) {
common_log_db_error($consumer, 'DELETE', __FILE__);
$this->success = false;
$this->msg = ('Unable to reset consumer key and secret.');
@ -295,7 +354,7 @@ class ShowApplicationAction extends OwnerDesignAction
$result = $consumer->insert();
if (!$result) {
if (empty($result)) {
common_log_db_error($consumer, 'INSERT', __FILE__);
$this->application->query('ROLLBACK');
$this->success = false;
@ -308,7 +367,7 @@ class ShowApplicationAction extends OwnerDesignAction
$this->application->consumer_key = $consumer->consumer_key;
$result = $this->application->update($orig);
if (!$result) {
if ($result === false) {
common_log_db_error($application, 'UPDATE', __FILE__);
$this->application->query('ROLLBACK');
$this->success = false;

View File

@ -36,4 +36,34 @@ class Consumer extends Memcached_DataObject
return $cons;
}
/**
* Delete a Consumer and related tokens and nonces
*
* XXX: Should this happen in an OAuthDataStore instead?
*
*/
function delete()
{
// XXX: Is there any reason NOT to do this kind of cleanup?
$this->_deleteTokens();
$this->_deleteNonces();
parent::delete();
}
function _deleteTokens()
{
$token = new Token();
$token->consumer_key = $this->consumer_key;
$token->delete();
}
function _deleteNonces()
{
$nonce = new Nonce();
$nonce->consumer_key = $this->consumer_key;
$nonce->delete();
}
}

View File

@ -137,4 +137,21 @@ class Oauth_application extends Memcached_DataObject
}
}
function delete()
{
$this->_deleteAppUsers();
$consumer = $this->getConsumer();
$consumer->delete();
parent::delete();
}
function _deleteAppUsers()
{
$oauser = new Oauth_application_user();
$oauser->application_id = $this->id;
$oauser->delete();
}
}

View File

@ -367,6 +367,7 @@ modified = 384
[oauth_application__keys]
id = N
name = U
[oauth_application_user]
profile_id = 129

View File

@ -214,7 +214,7 @@ create table oauth_application (
id integer auto_increment primary key comment 'unique identifier',
owner integer not null comment 'owner of the application' references profile (id),
consumer_key varchar(255) not null comment 'application consumer key' references consumer (consumer_key),
name varchar(255) not null comment 'name of the application',
name varchar(255) not null unique key comment 'name of the application',
description varchar(255) comment 'description of the application',
icon varchar(255) not null comment 'application icon',
source_url varchar(255) comment 'application homepage - used for source link',
@ -230,7 +230,7 @@ create table oauth_application (
create table oauth_application_user (
profile_id integer not null comment 'user of the application' references profile (id),
application_id integer not null comment 'id of the application' references oauth_application (id),
access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write, bit 3 = revoked',
access_type tinyint default 0 comment 'access type, bit 1 = read, bit 2 = write',
token varchar(255) comment 'request or access token',
created datetime not null comment 'date this record was created',
modified timestamp comment 'date this record was modified',

View File

@ -1249,10 +1249,27 @@ class ApiAction extends Action
case 'api':
break;
default:
$name = null;
$url = null;
$ns = Notice_source::staticGet($source);
if ($ns) {
$source_name = '<a href="' . $ns->url . '">' . $ns->name . '</a>';
$name = $ns->name;
$url = $ns->url;
} else {
$app = Oauth_application::staticGet('name', $source);
if ($app) {
$name = $app->name;
$url = $app->source_url;
}
}
if (!empty($name) && !empty($url)) {
$source_name = '<a href="' . $url . '">' . $name . '</a>';
}
break;
}
return $source_name;

View File

@ -55,6 +55,7 @@ class ApiAuthAction extends ApiAction
{
var $auth_user_nickname = null;
var $auth_user_password = null;
var $oauth_source = null;
/**
* Take arguments for running, looks for an OAuth request,
@ -73,21 +74,19 @@ class ApiAuthAction extends ApiAction
// NOTE: $this->auth_user has to get set in prepare(), not handle(),
// because subclasses do stuff with it in their prepares.
if ($this->requiresAuth()) {
$oauthReq = $this->getOAuthRequest();
if (!$oauthReq) {
if ($this->requiresAuth()) {
$this->checkBasicAuthUser(true);
} else {
$this->checkOAuthRequest($oauthReq);
}
} else {
// Check to see if a basic auth user is there even
// if one's not required
$this->checkBasicAuthUser(false);
}
} else {
$this->checkOAuthRequest($oauthReq);
}
// Reject API calls with the wrong access level
@ -108,7 +107,6 @@ class ApiAuthAction extends ApiAction
* This is to avoid doign any unnecessary DB lookups.
*
* @return mixed the OAuthRequest or false
*
*/
function getOAuthRequest()
@ -137,7 +135,6 @@ class ApiAuthAction extends ApiAction
* @param OAuthRequest $request the OAuth Request
*
* @return nothing
*
*/
function checkOAuthRequest($request)

View File

@ -159,5 +159,32 @@ class ApiStatusNetOAuthDataStore extends StatusNetOAuthDataStore
}
}
/**
* Revoke specified access token
*
* Revokes the token specified by $token_key.
* Throws exceptions in case of error.
*
* @param string $token_key the token to be revoked
* @param int $type type of token (0 = req, 1 = access)
*
* @access public
*
* @return void
*/
public function revoke_token($token_key, $type = 0) {
$rt = new Token();
$rt->tok = $token_key;
$rt->type = $type;
$rt->state = 0;
if (!$rt->find(true)) {
throw new Exception('Tried to revoke unknown token');
}
if (!$rt->delete()) {
throw new Exception('Failed to delete revoked token');
}
}
}

View File

@ -486,12 +486,28 @@ class NoticeListItem extends Widget
$this->out->element('span', 'device', $source_name);
break;
default:
$name = null;
$url = null;
$ns = Notice_source::staticGet($this->notice->source);
if ($ns) {
$name = $ns->name;
$url = $ns->url;
} else {
$app = Oauth_application::staticGet('name', $this->notice->source);
if ($app) {
$name = $app->name;
$url = $app->source_url;
}
}
if (!empty($name) && !empty($url)) {
$this->out->elementStart('span', 'device');
$this->out->element('a', array('href' => $ns->url,
$this->out->element('a', array('href' => $url,
'rel' => 'external'),
$ns->name);
$name);
$this->out->elementEnd('span');
} else {
$this->out->element('span', 'device', $source_name);

View File

@ -65,7 +65,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore
{
$n = new Nonce();
$n->consumer_key = $consumer->key;
$n->ts = $timestamp;
$n->ts = common_sql_date($timestamp);
$n->nonce = $nonce;
if ($n->find(true)) {
return true;
@ -362,7 +362,6 @@ class StatusNetOAuthDataStore extends OAuthDataStore
array('is_local' => Notice::REMOTE_OMB,
'uri' => $omb_notice->getIdentifierURI()));
}
/**

View File

@ -152,6 +152,10 @@ class Router
array('action' => 'editapplication'),
array('id' => '[0-9]+')
);
$m->connect('settings/oauthapps/delete/:id',
array('action' => 'deleteapplication'),
array('id' => '[0-9]+')
);
// search

View File

@ -2,7 +2,7 @@
<?php
/**
* StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
* Copyright (C) 2008-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
@ -262,7 +262,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$notice->is_local = Notice::GATEWAY;
if (Event::handle('StartNoticeSave', array(&$notice))) {
$id = $notice->insert();
$notice->insert();
Event::handle('EndNoticeSave', array($notice));
}
@ -270,17 +270,41 @@ class TwitterStatusFetcher extends ParallelizingDaemon
Inbox::insertNotice($flink->user_id, $notice->id);
$notice->blowCaches();
$notice->blowOnInsert();
return $notice;
}
/**
* Look up a Profile by profileurl field. Profile::staticGet() was
* not working consistently.
*
* @param string $url the profile url
*
* @return mixed the first profile with that url, or null
*/
function getProfileByUrl($nickname, $profileurl)
{
$profile = new Profile();
$profile->nickname = $nickname;
$profile->profileurl = $profileurl;
$profile->limit(1);
if ($profile->find()) {
$profile->fetch();
return $profile;
}
return null;
}
function ensureProfile($user)
{
// check to see if there's already a profile for this user
$profileurl = 'http://twitter.com/' . $user->screen_name;
$profile = Profile::staticGet('profileurl', $profileurl);
$profile = $this->getProfileByUrl($user->screen_name, $profileurl);
if (!empty($profile)) {
common_debug($this->name() .
@ -292,6 +316,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
return $profile->id;
} else {
common_debug($this->name() . ' - Adding profile and remote profile ' .
"for Twitter user: $profileurl.");
@ -306,7 +331,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$profile->profileurl = $profileurl;
$profile->created = common_sql_now();
try {
$id = $profile->insert();
} catch(Exception $e) {
common_log(LOG_WARNING, $this->name . ' Couldn\'t insert profile - ' . $e->getMessage());
}
if (empty($id)) {
common_log_db_error($profile, 'INSERT', __FILE__);
@ -326,7 +355,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$remote_pro->uri = $profileurl;
$remote_pro->created = common_sql_now();
try {
$rid = $remote_pro->insert();
} catch (Exception $e) {
common_log(LOG_WARNING, $this->name() . ' Couldn\'t save remote profile - ' . $e->getMessage());
}
if (empty($rid)) {
common_log_db_error($profile, 'INSERT', __FILE__);
@ -446,7 +479,7 @@ class TwitterStatusFetcher extends ParallelizingDaemon
if ($this->fetchAvatar($url, $filename)) {
$this->newAvatar($id, $size, $mediatype, $filename);
} else {
common_log(LOG_WARNING, $this->id() .
common_log(LOG_WARNING, $id() .
" - Problem fetching Avatar: $url");
}
}
@ -507,7 +540,11 @@ class TwitterStatusFetcher extends ParallelizingDaemon
$avatar->created = common_sql_now();
try {
$id = $avatar->insert();
} catch (Exception $e) {
common_log(LOG_WARNING, $this->name() . ' Couldn\'t insert avatar - ' . $e->getMessage());
}
if (empty($id)) {
common_log_db_error($avatar, 'INSERT', __FILE__);

View File

@ -632,7 +632,8 @@ margin-bottom:18px;
.entity_profile .entity_url,
.entity_profile .entity_note,
.entity_profile .entity_tags,
.entity_profile .entity_aliases {
.entity_profile .entity_aliases,
.entity_profile .entity_statistics {
margin-left:113px;
margin-bottom:4px;
}
@ -1023,6 +1024,7 @@ float:none;
}
#content .notice .entry-title {
margin-left:59px;
margin-right:7px;
}
.vcard .url {