Merge branch 'master' of /var/www/trunk

This commit is contained in:
Robin Millette 2009-01-23 01:01:01 +00:00
commit 8a65c5175c
28 changed files with 873 additions and 534 deletions

View File

@ -23,6 +23,9 @@ require_once(INSTALLDIR.'/lib/openid.php');
class FinishopenidloginAction extends Action class FinishopenidloginAction extends Action
{ {
var $error = null;
var $username = null;
var $message = null;
function handle($args) function handle($args)
{ {
@ -32,32 +35,32 @@ class FinishopenidloginAction extends Action
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') { } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. Try again, please.')); $this->showForm(_('There was a problem with your session token. Try again, please.'));
return; return;
} }
if ($this->arg('create')) { if ($this->arg('create')) {
if (!$this->boolean('license')) { if (!$this->boolean('license')) {
$this->show_form(_('You can\'t register if you don\'t agree to the license.'), $this->showForm(_('You can\'t register if you don\'t agree to the license.'),
$this->trimmed('newname')); $this->trimmed('newname'));
return; return;
} }
$this->create_new_user(); $this->createNewUser();
} else if ($this->arg('connect')) { } else if ($this->arg('connect')) {
$this->connect_user(); $this->connectUser();
} else { } else {
common_debug(print_r($this->args, true), __FILE__); common_debug(print_r($this->args, true), __FILE__);
$this->show_form(_('Something weird happened.'), $this->showForm(_('Something weird happened.'),
$this->trimmed('newname')); $this->trimmed('newname'));
} }
} else { } else {
$this->try_login(); $this->tryLogin();
} }
} }
function show_top($error=null) function showPageNotice()
{ {
if ($error) { if ($this->error) {
$this->element('div', array('class' => 'error'), $error); $this->element('div', array('class' => 'error'), $this->error);
} else { } else {
global $config; global $config;
$this->element('div', 'instructions', $this->element('div', 'instructions',
@ -65,21 +68,36 @@ class FinishopenidloginAction extends Action
} }
} }
function show_form($error=null, $username=null) function title()
{ {
common_show_header(_('OpenID Account Setup'), null, $error, return _('OpenID Account Setup');
array($this, 'show_top')); }
function showForm($error=null, $username=null)
{
$this->error = $error;
$this->username = $username;
$this->showPage();
}
function showContent()
{
if ($this->message_text) {
$this->element('p', null, $this->message);
return;
}
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'account_connect', 'id' => 'account_connect',
'action' => common_local_url('finishopenidlogin'))); 'action' => common_local_url('finishopenidlogin')));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->element('h2', null, $this->element('h2', null,
_('Create new account')); _('Create new account'));
$this->element('p', null, $this->element('p', null,
_('Create a new user with this nickname.')); _('Create a new user with this nickname.'));
$this->input('newname', _('New nickname'), $this->input('newname', _('New nickname'),
($username) ? $username : '', ($this->username) ? $this->username : '',
_('1-64 lowercase letters or numbers, no punctuation or spaces')); _('1-64 lowercase letters or numbers, no punctuation or spaces'));
$this->elementStart('p'); $this->elementStart('p');
$this->element('input', array('type' => 'checkbox', $this->element('input', array('type' => 'checkbox',
@ -87,7 +105,7 @@ class FinishopenidloginAction extends Action
'name' => 'license', 'name' => 'license',
'value' => 'true')); 'value' => 'true'));
$this->text(_('My text and files are available under ')); $this->text(_('My text and files are available under '));
$this->element('a', array(href => common_config('license', 'url')), $this->element('a', array('href' => common_config('license', 'url')),
common_config('license', 'title')); common_config('license', 'title'));
$this->text(_(' except this private data: password, email address, IM address, phone number.')); $this->text(_(' except this private data: password, email address, IM address, phone number.'));
$this->elementEnd('p'); $this->elementEnd('p');
@ -100,12 +118,10 @@ class FinishopenidloginAction extends Action
$this->password('password', _('Password')); $this->password('password', _('Password'));
$this->submit('connect', _('Connect')); $this->submit('connect', _('Connect'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function try_login() function tryLogin()
{ {
$consumer = oid_consumer(); $consumer = oid_consumer();
$response = $consumer->complete(common_local_url('finishopenidlogin')); $response = $consumer->complete(common_local_url('finishopenidlogin'));
@ -143,22 +159,21 @@ class FinishopenidloginAction extends Action
common_rememberme($user); common_rememberme($user);
} }
unset($_SESSION['openid_rememberme']); unset($_SESSION['openid_rememberme']);
$this->go_home($user->nickname); $this->goHome($user->nickname);
} else { } else {
$this->save_values($display, $canonical, $sreg); $this->saveValues($display, $canonical, $sreg);
$this->show_form(null, $this->best_new_nickname($display, $sreg)); $this->showForm(null, $this->bestNewNickname($display, $sreg));
} }
} }
} }
function message($msg) function message($msg)
{ {
common_show_header(_('OpenID Login')); $this->message_text = $msg;
$this->element('p', null, $msg); $this->showPage();
common_show_footer();
} }
function save_values($display, $canonical, $sreg) function saveValues($display, $canonical, $sreg)
{ {
common_ensure_session(); common_ensure_session();
$_SESSION['openid_display'] = $display; $_SESSION['openid_display'] = $display;
@ -166,16 +181,15 @@ class FinishopenidloginAction extends Action
$_SESSION['openid_sreg'] = $sreg; $_SESSION['openid_sreg'] = $sreg;
} }
function get_saved_values() function getSavedValues()
{ {
return array($_SESSION['openid_display'], return array($_SESSION['openid_display'],
$_SESSION['openid_canonical'], $_SESSION['openid_canonical'],
$_SESSION['openid_sreg']); $_SESSION['openid_sreg']);
} }
function create_new_user() function createNewUser()
{ {
# FIXME: save invite code before redirect, and check here # FIXME: save invite code before redirect, and check here
if (common_config('site', 'closed') || common_config('site', 'inviteonly')) { if (common_config('site', 'closed') || common_config('site', 'inviteonly')) {
@ -188,21 +202,21 @@ class FinishopenidloginAction extends Action
if (!Validate::string($nickname, array('min_length' => 1, if (!Validate::string($nickname, array('min_length' => 1,
'max_length' => 64, 'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
$this->show_form(_('Nickname must have only lowercase letters and numbers and no spaces.')); $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
return; return;
} }
if (!User::allowed_nickname($nickname)) { if (!User::allowed_nickname($nickname)) {
$this->show_form(_('Nickname not allowed.')); $this->showForm(_('Nickname not allowed.'));
return; return;
} }
if (User::staticGet('nickname', $nickname)) { if (User::staticGet('nickname', $nickname)) {
$this->show_form(_('Nickname already in use. Try another one.')); $this->showForm(_('Nickname already in use. Try another one.'));
return; return;
} }
list($display, $canonical, $sreg) = $this->get_saved_values(); list($display, $canonical, $sreg) = $this->getSavedValues();
if (!$display || !$canonical) { if (!$display || !$canonical) {
$this->serverError(_('Stored OpenID not found.')); $this->serverError(_('Stored OpenID not found.'));
@ -256,14 +270,13 @@ class FinishopenidloginAction extends Action
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname))); common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)));
} }
function connect_user() function connectUser()
{ {
$nickname = $this->trimmed('nickname'); $nickname = $this->trimmed('nickname');
$password = $this->trimmed('password'); $password = $this->trimmed('password');
if (!common_check_user($nickname, $password)) { if (!common_check_user($nickname, $password)) {
$this->show_form(_('Invalid username or password.')); $this->showForm(_('Invalid username or password.'));
return; return;
} }
@ -271,7 +284,7 @@ class FinishopenidloginAction extends Action
$user = User::staticGet('nickname', $nickname); $user = User::staticGet('nickname', $nickname);
list($display, $canonical, $sreg) = $this->get_saved_values(); list($display, $canonical, $sreg) = $this->getSavedValues();
if (!$display || !$canonical) { if (!$display || !$canonical) {
$this->serverError(_('Stored OpenID not found.')); $this->serverError(_('Stored OpenID not found.'));
@ -293,10 +306,10 @@ class FinishopenidloginAction extends Action
common_rememberme($user); common_rememberme($user);
} }
unset($_SESSION['openid_rememberme']); unset($_SESSION['openid_rememberme']);
$this->go_home($user->nickname); $this->goHome($user->nickname);
} }
function go_home($nickname) function goHome($nickname)
{ {
$url = common_get_returnto(); $url = common_get_returnto();
if ($url) { if ($url) {
@ -310,14 +323,14 @@ class FinishopenidloginAction extends Action
common_redirect($url); common_redirect($url);
} }
function best_new_nickname($display, $sreg) function bestNewNickname($display, $sreg)
{ {
# Try the passed-in nickname # Try the passed-in nickname
if ($sreg['nickname']) { if ($sreg['nickname']) {
$nickname = $this->nicknamize($sreg['nickname']); $nickname = $this->nicknamize($sreg['nickname']);
if ($this->is_new_nickname($nickname)) { if ($this->isNewNickname($nickname)) {
return $nickname; return $nickname;
} }
} }
@ -326,16 +339,16 @@ class FinishopenidloginAction extends Action
if ($sreg['fullname']) { if ($sreg['fullname']) {
$fullname = $this->nicknamize($sreg['fullname']); $fullname = $this->nicknamize($sreg['fullname']);
if ($this->is_new_nickname($fullname)) { if ($this->isNewNickname($fullname)) {
return $fullname; return $fullname;
} }
} }
# Try the URL # Try the URL
$from_url = $this->openid_to_nickname($display); $from_url = $this->openidToNickname($display);
if ($from_url && $this->is_new_nickname($from_url)) { if ($from_url && $this->isNewNickname($from_url)) {
return $from_url; return $from_url;
} }
@ -344,14 +357,14 @@ class FinishopenidloginAction extends Action
return null; return null;
} }
function is_new_nickname($str) function isNewNickname($str)
{ {
if (!Validate::string($str, array('min_length' => 1, if (!Validate::string($str, array('min_length' => 1,
'max_length' => 64, 'max_length' => 64,
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) { 'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
return false; return false;
} }
if (!User::allowed_nickname($str)) { if (!User::allowed_nickname($str)) {
return false; return false;
} }
if (User::staticGet('nickname', $str)) { if (User::staticGet('nickname', $str)) {
@ -360,12 +373,12 @@ class FinishopenidloginAction extends Action
return true; return true;
} }
function openid_to_nickname($openid) function openidToNickname($openid)
{ {
if (Auth_Yadis_identifierScheme($openid) == 'XRI') { if (Auth_Yadis_identifierScheme($openid) == 'XRI') {
return $this->xri_to_nickname($openid); return $this->xriToNickname($openid);
} else { } else {
return $this->url_to_nickname($openid); return $this->urlToNickname($openid);
} }
} }
@ -374,7 +387,7 @@ class FinishopenidloginAction extends Action
# 2. One element in path, like http://profile.typekey.com/EvanProdromou/ # 2. One element in path, like http://profile.typekey.com/EvanProdromou/
# or http://getopenid.com/evanprodromou # or http://getopenid.com/evanprodromou
function url_to_nickname($openid) function urlToNickname($openid)
{ {
static $bad = array('query', 'user', 'password', 'port', 'fragment'); static $bad = array('query', 'user', 'password', 'port', 'fragment');
@ -421,9 +434,9 @@ class FinishopenidloginAction extends Action
return null; return null;
} }
function xri_to_nickname($xri) function xriToNickname($xri)
{ {
$base = $this->xri_base($xri); $base = $this->xriBase($xri);
if (!$base) { if (!$base) {
return null; return null;
@ -435,7 +448,7 @@ class FinishopenidloginAction extends Action
} }
} }
function xri_base($xri) function xriBase($xri)
{ {
if (substr($xri, 0, 6) == 'xri://') { if (substr($xri, 0, 6) == 'xri://') {
return substr($xri, 6); return substr($xri, 6);

View File

@ -25,35 +25,40 @@ define('BOTH', 0);
class FoafAction extends Action class FoafAction extends Action
{ {
function isReadOnly() function isReadOnly()
{ {
return true; return true;
} }
function prepare($args)
{
parent::prepare($args);
$this->nickname = $this->trimmed('nickname');
$this->user = User::staticGet('nickname', $this->nickname);
if (!$this->user) {
$this->clientError(_('No such user.'), 404);
return false;
}
$this->profile = $this->user->getProfile();
if (!$this->profile) {
$this->serverError(_('User has no profile.'), 500);
return false;
}
return true;
}
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$nickname = $this->trimmed('nickname');
$user = User::staticGet('nickname', $nickname);
if (!$user) {
$this->clientError(_('No such user.'), 404);
return;
}
$profile = $user->getProfile();
if (!$profile) {
$this->serverError(_('User has no profile.'), 500);
return;
}
header('Content-Type: application/rdf+xml'); header('Content-Type: application/rdf+xml');
common_start_xml(); $this->startXML();
$this->elementStart('rdf:RDF', array('xmlns:rdf' => $this->elementStart('rdf:RDF', array('xmlns:rdf' =>
'http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'xmlns:rdfs' => 'xmlns:rdfs' =>
@ -62,42 +67,42 @@ class FoafAction extends Action
'http://www.w3.org/2003/01/geo/wgs84_pos#', 'http://www.w3.org/2003/01/geo/wgs84_pos#',
'xmlns' => 'http://xmlns.com/foaf/0.1/')); 'xmlns' => 'http://xmlns.com/foaf/0.1/'));
# This is the document about the user // This is the document about the user
$this->show_ppd('', $user->uri); $this->showPpd('', $this->user->uri);
# XXX: might not be a person // XXX: might not be a person
$this->elementStart('Person', array('rdf:about' => $this->elementStart('Person', array('rdf:about' =>
$user->uri)); $this->user->uri));
$this->element('mbox_sha1sum', null, sha1('mailto:' . $user->email)); $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email));
if ($profile->fullname) { if ($this->profile->fullname) {
$this->element('name', null, $profile->fullname); $this->element('name', null, $this->profile->fullname);
} }
if ($profile->homepage) { if ($this->profile->homepage) {
$this->element('homepage', array('rdf:resource' => $profile->homepage)); $this->element('homepage', array('rdf:resource' => $this->profile->homepage));
} }
if ($profile->bio) { if ($this->profile->bio) {
$this->element('rdfs:comment', null, $profile->bio); $this->element('rdfs:comment', null, $this->profile->bio);
} }
# XXX: more structured location data // XXX: more structured location data
if ($profile->location) { if ($this->profile->location) {
$this->elementStart('based_near'); $this->elementStart('based_near');
$this->elementStart('geo:SpatialThing'); $this->elementStart('geo:SpatialThing');
$this->element('name', null, $profile->location); $this->element('name', null, $this->profile->location);
$this->elementEnd('geo:SpatialThing'); $this->elementEnd('geo:SpatialThing');
$this->elementEnd('based_near'); $this->elementEnd('based_near');
} }
$this->show_microblogging_account($profile, common_root_url()); $this->showMicrobloggingAccount($this->profile, common_root_url());
$avatar = $profile->getOriginalAvatar(); $avatar = $this->profile->getOriginalAvatar();
if ($avatar) { if ($avatar) {
$this->elementStart('img'); $this->elementStart('img');
$this->elementStart('Image', array('rdf:about' => $avatar->url)); $this->elementStart('Image', array('rdf:about' => $avatar->url));
foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) { foreach (array(AVATAR_PROFILE_SIZE, AVATAR_STREAM_SIZE, AVATAR_MINI_SIZE) as $size) {
$scaled = $profile->getAvatar($size); $scaled = $this->profile->getAvatar($size);
if (!$scaled->original) { # sometimes the original has one of our scaled sizes if (!$scaled->original) { // sometimes the original has one of our scaled sizes
$this->elementStart('thumbnail'); $this->elementStart('thumbnail');
$this->element('Image', array('rdf:about' => $scaled->url)); $this->element('Image', array('rdf:about' => $scaled->url));
$this->elementEnd('thumbnail'); $this->elementEnd('thumbnail');
@ -107,14 +112,14 @@ class FoafAction extends Action
$this->elementEnd('img'); $this->elementEnd('img');
} }
# Get people user is subscribed to // Get people user is subscribed to
$person = array(); $person = array();
$sub = new Subscription(); $sub = new Subscription();
$sub->subscriber = $profile->id; $sub->subscriber = $this->profile->id;
$sub->whereAdd('subscriber != subscribed'); $sub->whereAdd('subscriber != subscribed');
if ($sub->find()) { if ($sub->find()) {
while ($sub->fetch()) { while ($sub->fetch()) {
if ($sub->token) { if ($sub->token) {
@ -131,10 +136,10 @@ class FoafAction extends Action
} }
} }
# Get people who subscribe to user // Get people who subscribe to user
$sub = new Subscription(); $sub = new Subscription();
$sub->subscribed = $profile->id; $sub->subscribed = $this->profile->id;
$sub->whereAdd('subscriber != subscribed'); $sub->whereAdd('subscriber != subscribed');
if ($sub->find()) { if ($sub->find()) {
@ -163,26 +168,27 @@ class FoafAction extends Action
if ($p[1] instanceof User) { if ($p[1] instanceof User) {
$foaf_url = common_local_url('foaf', array('nickname' => $p[1]->nickname)); $foaf_url = common_local_url('foaf', array('nickname' => $p[1]->nickname));
} }
$profile = Profile::staticGet($p[1]->id); $this->profile = Profile::staticGet($p[1]->id);
$this->elementStart('Person', array('rdf:about' => $uri)); $this->elementStart('Person', array('rdf:about' => $uri));
if ($p[0] == LISTENER || $p[0] == BOTH) { if ($p[0] == LISTENER || $p[0] == BOTH) {
$this->element('knows', array('rdf:resource' => $user->uri)); $this->element('knows', array('rdf:resource' => $this->user->uri));
} }
$this->show_microblogging_account($profile, ($p[1] instanceof User) ? $this->showMicrobloggingAccount($this->profile, ($p[1] instanceof User) ?
common_root_url() : null); common_root_url() : null);
if ($foaf_url) { if ($foaf_url) {
$this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url)); $this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
} }
$this->elementEnd('Person'); $this->elementEnd('Person');
if ($foaf_url) { if ($foaf_url) {
$this->show_ppd($foaf_url, $uri); $this->showPpd($foaf_url, $uri);
} }
} }
$this->elementEnd('rdf:RDF'); $this->elementEnd('rdf:RDF');
$this->endXML();
} }
function show_ppd($foaf_url, $person_uri) function showPpd($foaf_url, $person_uri)
{ {
$this->elementStart('PersonalProfileDocument', array('rdf:about' => $foaf_url)); $this->elementStart('PersonalProfileDocument', array('rdf:about' => $foaf_url));
$this->element('maker', array('rdf:resource' => $person_uri)); $this->element('maker', array('rdf:resource' => $person_uri));
@ -190,9 +196,9 @@ class FoafAction extends Action
$this->elementEnd('PersonalProfileDocument'); $this->elementEnd('PersonalProfileDocument');
} }
function show_microblogging_account($profile, $service=null) function showMicrobloggingAccount($profile, $service=null)
{ {
# Their account // Their account
$this->elementStart('holdsAccount'); $this->elementStart('holdsAccount');
$this->elementStart('OnlineAccount'); $this->elementStart('OnlineAccount');
if ($service) { if ($service) {

View File

@ -21,6 +21,11 @@ if (!defined('LACONICA')) { exit(1); }
class InviteAction extends Action class InviteAction extends Action
{ {
var $mode = null;
var $error = null;
var $already = null;
var $subbed = null;
var $sent = null;
function isReadOnly() function isReadOnly()
{ {
@ -35,19 +40,18 @@ class InviteAction extends Action
common_config('site', 'name'))); common_config('site', 'name')));
return; return;
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') { } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->send_invitations(); $this->sendInvitations();
} else { } else {
$this->show_form(); $this->showForm();
} }
} }
function send_invitations() function sendInvitations()
{ {
# CSRF protection # CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. Try again, please.')); $this->showForm(_('There was a problem with your session token. Try again, please.'));
return; return;
} }
@ -63,78 +67,105 @@ class InviteAction extends Action
foreach ($addresses as $email) { foreach ($addresses as $email) {
$email = trim($email); $email = trim($email);
if (!Validate::email($email, true)) { if (!Validate::email($email, true)) {
$this->show_form(sprintf(_('Invalid email address: %s'), $email)); $this->showForm(sprintf(_('Invalid email address: %s'), $email));
return; return;
} }
} }
$already = array(); $this->already = array();
$subbed = array(); $this->subbed = array();
foreach ($addresses as $email) { foreach ($addresses as $email) {
$email = common_canonical_email($email); $email = common_canonical_email($email);
$other = User::staticGet('email', $email); $other = User::staticGet('email', $email);
if ($other) { if ($other) {
if ($user->isSubscribed($other)) { if ($user->isSubscribed($other)) {
$already[] = $other; $this->already[] = $other;
} else { } else {
subs_subscribe_to($user, $other); subs_subscribe_to($user, $other);
$subbed[] = $other; $this->subbed[] = $other;
} }
} else { } else {
$sent[] = $email; $this->sent[] = $email;
$this->send_invitation($email, $user, $personal); $this->sendInvitation($email, $user, $personal);
} }
} }
common_show_header(_('Invitation(s) sent')); $this->mode = 'sent';
if ($already) {
$this->showPage();
}
function title()
{
if ($this->mode == 'sent') {
return _('Invitation(s) sent');
} else {
return _('Invite new users');
}
}
function showContent()
{
if ($this->mode == 'sent') {
$this->showInvitationSuccess();
} else {
$this->showInviteForm();
}
}
function showInvitationSuccess()
{
if ($this->already) {
$this->element('p', null, _('You are already subscribed to these users:')); $this->element('p', null, _('You are already subscribed to these users:'));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($already as $other) { foreach ($this->already as $other) {
$this->element('li', null, sprintf(_('%s (%s)'), $other->nickname, $other->email)); $this->element('li', null, sprintf(_('%s (%s)'), $other->nickname, $other->email));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
if ($subbed) { if ($this->subbed) {
$this->element('p', null, _('These people are already users and you were automatically subscribed to them:')); $this->element('p', null, _('These people are already users and you were automatically subscribed to them:'));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($subbed as $other) { foreach ($this->subbed as $other) {
$this->element('li', null, sprintf(_('%s (%s)'), $other->nickname, $other->email)); $this->element('li', null, sprintf(_('%s (%s)'), $other->nickname, $other->email));
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
} }
if ($sent) { if ($this->sent) {
$this->element('p', null, _('Invitation(s) sent to the following people:')); $this->element('p', null, _('Invitation(s) sent to the following people:'));
$this->elementStart('ul'); $this->elementStart('ul');
foreach ($sent as $other) { foreach ($this->sent as $other) {
$this->element('li', null, $other); $this->element('li', null, $other);
} }
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!')); $this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!'));
} }
common_show_footer();
} }
function show_top($error=null) function showPageNotice()
{ {
if ($error) { if ($this->mode != 'sent') {
$this->element('p', 'error', $error); if ($this->error) {
} else { $this->element('p', 'error', $this->error);
$this->elementStart('div', 'instructions'); } else {
$this->element('p', null, $this->elementStart('div', 'instructions');
_('Use this form to invite your friends and colleagues to use this service.')); $this->element('p', null,
$this->elementEnd('div'); _('Use this form to invite your friends and colleagues to use this service.'));
$this->elementEnd('div');
}
} }
} }
function show_form($error=null) function showForm($error=null)
{ {
$this->mode = 'form';
$this->error = $error;
$this->showPage();
}
global $config; function showInviteForm()
{
common_show_header(_('Invite new users'), null, $error, array($this, 'show_top'));
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'invite', 'id' => 'invite',
'action' => common_local_url('invite'))); 'action' => common_local_url('invite')));
@ -151,13 +182,10 @@ class InviteAction extends Action
$this->submit('send', _('Send')); $this->submit('send', _('Send'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function send_invitation($email, $user, $personal) function sendInvitation($email, $user, $personal)
{ {
$profile = $user->getProfile(); $profile = $user->getProfile();
$bestname = $profile->getBestName(); $bestname = $profile->getBestName();
@ -203,4 +231,9 @@ class InviteAction extends Action
mail_send($recipients, $headers, $body); mail_send($recipients, $headers, $body);
} }
function showLocalNav()
{
$nav = new SubGroupNav($this, common_current_user());
$nav->show();
}
} }

View File

@ -23,7 +23,6 @@ require_once(INSTALLDIR.'/lib/openid.php');
class OpenidloginAction extends Action class OpenidloginAction extends Action
{ {
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
@ -35,40 +34,40 @@ class OpenidloginAction extends Action
# CSRF protection # CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. Try again, please.'), $openid_url); $this->showForm(_('There was a problem with your session token. Try again, please.'), $openid_url);
return; return;
} }
$rememberme = $this->boolean('rememberme'); $rememberme = $this->boolean('rememberme');
common_ensure_session(); common_ensure_session();
$_SESSION['openid_rememberme'] = $rememberme; $_SESSION['openid_rememberme'] = $rememberme;
$result = oid_authenticate($openid_url, $result = oid_authenticate($openid_url,
'finishopenidlogin'); 'finishopenidlogin');
if (is_string($result)) { # error message if (is_string($result)) { # error message
unset($_SESSION['openid_rememberme']); unset($_SESSION['openid_rememberme']);
$this->show_form($result, $openid_url); $this->showForm($result, $openid_url);
} }
} else { } else {
$openid_url = oid_get_last(); $openid_url = oid_get_last();
$this->show_form(null, $openid_url); $this->showForm(null, $openid_url);
} }
} }
function get_instructions() function getInstructions()
{ {
return _('Login with an [OpenID](%%doc.openid%%) account.'); return _('Login with an [OpenID](%%doc.openid%%) account.');
} }
function show_top($error=null) function showPageNotice()
{ {
if ($error) { if ($this->error) {
$this->element('div', array('class' => 'error'), $error); $this->element('div', array('class' => 'error'), $this->error);
} else { } else {
$instr = $this->get_instructions(); $instr = $this->getInstructions();
$output = common_markup_to_html($instr); $output = common_markup_to_html($instr);
$this->elementStart('div', 'instructions'); $this->elementStart('div', 'instructions');
$this->raw($output); $this->raw($output);
@ -76,22 +75,37 @@ class OpenidloginAction extends Action
} }
} }
function show_form($error=null, $openid_url) function title()
{ {
common_show_header(_('OpenID Login'), null, $error, array($this, 'show_top')); return _('OpenID Login');
}
function showForm($error=null, $openid_url)
{
$this->error = $error;
$this->openid_url = $openid_url;
$this->showPage();
}
function showContent() {
$formaction = common_local_url('openidlogin'); $formaction = common_local_url('openidlogin');
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'openidlogin', 'id' => 'openidlogin',
'action' => $formaction)); 'action' => $formaction));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->input('openid_url', _('OpenID URL'), $this->input('openid_url', _('OpenID URL'),
$openid_url, $this->openid_url,
_('Your OpenID URL')); _('Your OpenID URL'));
$this->checkbox('rememberme', _('Remember me'), false, $this->checkbox('rememberme', _('Remember me'), false,
_('Automatically login in the future; ' . _('Automatically login in the future; ' .
'not for shared computers!')); 'not for shared computers!'));
$this->submit('submit', _('Login')); $this->submit('submit', _('Login'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer(); }
function showLocalNav()
{
$nav = new LoginGroupNav($this);
$nav->show();
} }
} }

View File

@ -206,5 +206,7 @@ class PublicAction extends Action
$pop->show(); $pop->show();
$gbp = new GroupsByPostsSection($this); $gbp = new GroupsByPostsSection($this);
$gbp->show(); $gbp->show();
$feat = new FeaturedUsersSection($this);
$feat->show();
} }
} }

View File

@ -25,6 +25,9 @@ define(MAX_RECOVERY_TIME, 24 * 60 * 60);
class RecoverpasswordAction extends Action class RecoverpasswordAction extends Action
{ {
var $mode = null;
var $msg = null;
var $success = null;
function handle($args) function handle($args)
{ {
@ -34,22 +37,22 @@ class RecoverpasswordAction extends Action
return; return;
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') { } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if ($this->arg('recover')) { if ($this->arg('recover')) {
$this->recover_password(); $this->recoverPassword();
} else if ($this->arg('reset')) { } else if ($this->arg('reset')) {
$this->reset_password(); $this->resetPassword();
} else { } else {
$this->clientError(_('Unexpected form submission.')); $this->clientError(_('Unexpected form submission.'));
} }
} else { } else {
if ($this->trimmed('code')) { if ($this->trimmed('code')) {
$this->check_code(); $this->checkCode();
} else { } else {
$this->show_form(); $this->showForm();
} }
} }
} }
function check_code() function checkCode()
{ {
$code = $this->trimmed('code'); $code = $this->trimmed('code');
@ -88,7 +91,7 @@ class RecoverpasswordAction extends Action
# Note: it's still deleted; let's avoid a second attempt! # Note: it's still deleted; let's avoid a second attempt!
if ((time() - $touched) > MAX_RECOVERY_TIME) { if ((time() - $touched) > MAX_RECOVERY_TIME) {
common_log(LOG_WARNING, common_log(LOG_WARNING,
'Attempted redemption on recovery code ' . 'Attempted redemption on recovery code ' .
'that is ' . $touched . ' seconds old. '); 'that is ' . $touched . ' seconds old. ');
$this->clientError(_('This confirmation code is too old. ' . $this->clientError(_('This confirmation code is too old. ' .
@ -112,17 +115,17 @@ class RecoverpasswordAction extends Action
# Success! # Success!
$this->set_temp_user($user); $this->setTempUser($user);
$this->show_password_form(); $this->showPasswordForm();
} }
function set_temp_user(&$user) function setTempUser(&$user)
{ {
common_ensure_session(); common_ensure_session();
$_SESSION['tempuser'] = $user->id; $_SESSION['tempuser'] = $user->id;
} }
function get_temp_user() function getTempUser()
{ {
common_ensure_session(); common_ensure_session();
$user_id = $_SESSION['tempuser']; $user_id = $_SESSION['tempuser'];
@ -132,44 +135,51 @@ class RecoverpasswordAction extends Action
return $user; return $user;
} }
function clear_temp_user() function clearTempUser()
{ {
common_ensure_session(); common_ensure_session();
unset($_SESSION['tempuser']); unset($_SESSION['tempuser']);
} }
function show_top($msg=null) function showPageNotice()
{ {
if ($msg) { if ($this->msg) {
$this->element('div', 'error', $msg); $this->element('div', ($this->success) ? 'success' : 'error', $this->msg);
} else { } else {
$this->elementStart('div', 'instructions'); $this->elementStart('div', 'instructions');
$this->element('p', null, if ($this->mode == 'recover') {
_('If you\'ve forgotten or lost your' . $this->element('p', null,
' password, you can get a new one sent to' . _('If you\'ve forgotten or lost your' .
' the email address you have stored ' . ' password, you can get a new one sent to' .
' in your account.')); ' the email address you have stored ' .
' in your account.'));
} else if ($this->mode == 'reset') {
$this->element('p', null,
_('You\'ve been identified. Enter a ' .
' new password below. '));
}
$this->elementEnd('div'); $this->elementEnd('div');
} }
} }
function show_password_top($msg=null) function showForm($msg=null)
{ {
if ($msg) { $this->msg = $msg;
$this->element('div', 'error', $msg); $this->mode = 'recover';
} else { $this->showPage();
$this->element('div', 'instructions', }
_('You\'ve been identified. Enter a ' .
' new password below. ')); function showContent()
{
if ($this->mode == 'recover') {
$this->showRecoverForm();
} else if ($this->mode == 'reset') {
$this->showResetForm();
} }
} }
function show_form($msg=null) function showRecoverForm()
{ {
common_show_header(_('Recover password'), null,
$msg, array($this, 'show_top'));
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'recoverpassword', 'id' => 'recoverpassword',
'action' => common_local_url('recoverpassword'))); 'action' => common_local_url('recoverpassword')));
@ -179,15 +189,29 @@ class RecoverpasswordAction extends Action
'or your registered email address.')); 'or your registered email address.'));
$this->submit('recover', _('Recover')); $this->submit('recover', _('Recover'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function show_password_form($msg=null) function title()
{ {
switch ($this->mode) {
case 'reset': return _('Reset password');
case 'recover': return _('Recover password');
case 'sent': return _('Password recovery requested');
case 'saved': return _('Password saved.');
default:
return _('Unknown action');
}
}
common_show_header(_('Reset password'), null, function showPasswordForm($msg=null)
$msg, array($this, 'show_password_top')); {
$this->msg = $msg;
$this->mode = 'reset';
$this->showPage();
}
function showResetForm()
{
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'recoverpassword', 'id' => 'recoverpassword',
'action' => common_local_url('recoverpassword'))); 'action' => common_local_url('recoverpassword')));
@ -198,14 +222,13 @@ class RecoverpasswordAction extends Action
_('Same as password above')); _('Same as password above'));
$this->submit('reset', _('Reset')); $this->submit('reset', _('Reset'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function recover_password() function recoverPassword()
{ {
$nore = $this->trimmed('nicknameoremail'); $nore = $this->trimmed('nicknameoremail');
if (!$nore) { if (!$nore) {
$this->show_form(_('Enter a nickname or email address.')); $this->showForm(_('Enter a nickname or email address.'));
return; return;
} }
@ -225,7 +248,7 @@ class RecoverpasswordAction extends Action
} }
if (!$user) { if (!$user) {
$this->show_form(_('No user with that email address or username.')); $this->showForm(_('No user with that email address or username.'));
return; return;
} }
@ -277,25 +300,24 @@ class RecoverpasswordAction extends Action
mail_to_user($user, _('Password recovery requested'), $body, $confirm->address); mail_to_user($user, _('Password recovery requested'), $body, $confirm->address);
common_show_header(_('Password recovery requested')); $this->mode = 'sent';
$this->element('p', null, $this->msg = _('Instructions for recovering your password ' .
_('Instructions for recovering your password ' .
'have been sent to the email address registered to your ' . 'have been sent to the email address registered to your ' .
'account.')); 'account.');
common_show_footer(); $this->success = true;
$this->showPage();
} }
function reset_password() function resetPassword()
{ {
# CSRF protection # CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. Try again, please.')); $this->showForm(_('There was a problem with your session token. Try again, please.'));
return; return;
} }
$user = $this->get_temp_user(); $user = $this->getTempUser();
if (!$user) { if (!$user) {
$this->clientError(_('Unexpected password reset.')); $this->clientError(_('Unexpected password reset.'));
@ -306,11 +328,11 @@ class RecoverpasswordAction extends Action
$confirm = $this->trimmed('confirm'); $confirm = $this->trimmed('confirm');
if (!$newpassword || strlen($newpassword) < 6) { if (!$newpassword || strlen($newpassword) < 6) {
$this->show_password_form(_('Password must be 6 chars or more.')); $this->showPasswordForm(_('Password must be 6 chars or more.'));
return; return;
} }
if ($newpassword != $confirm) { if ($newpassword != $confirm) {
$this->show_password_form(_('Password and confirmation do not match.')); $this->showPasswordForm(_('Password and confirmation do not match.'));
return; return;
} }
@ -326,7 +348,7 @@ class RecoverpasswordAction extends Action
return; return;
} }
$this->clear_temp_user(); $this->clearTempUser();
if (!common_set_user($user->nickname)) { if (!common_set_user($user->nickname)) {
$this->serverError(_('Error setting user.')); $this->serverError(_('Error setting user.'));
@ -335,9 +357,10 @@ class RecoverpasswordAction extends Action
common_real_login(true); common_real_login(true);
common_show_header(_('Password saved.')); $this->mode = 'saved';
$this->element('p', null, _('New password successfully saved. ' . $this->msg = _('New password successfully saved. ' .
'You are now logged in.')); 'You are now logged in.');
common_show_footer(); $this->success = true;
$this->showPage();
} }
} }

View File

@ -23,100 +23,112 @@ require_once(INSTALLDIR.'/lib/omb.php');
class RemotesubscribeAction extends Action class RemotesubscribeAction extends Action
{ {
var $nickname;
var $profile_url;
var $err;
function handle($args) function prepare($args)
{ {
parent::prepare($args);
parent::handle($args);
if (common_logged_in()) { if (common_logged_in()) {
$this->clientError(_('You can use the local subscription!')); $this->clientError(_('You can use the local subscription!'));
return; return false;
} }
if ($_SERVER['REQUEST_METHOD'] == 'POST') { $this->nickname = $this->trimmed('nickname');
$this->profile_url = $this->trimmed('profile_url');
return true;
}
function handle($args)
{
parent::handle($args);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
# CSRF protection # CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. Try again, please.')); $this->showForm(_('There was a problem with your session token. '.
'Try again, please.'));
return; return;
} }
$this->remoteSubscription();
$this->remote_subscription();
} else { } else {
$this->show_form(); $this->showForm();
} }
} }
function get_instructions() function showForm($err=null)
{ {
return _('To subscribe, you can [login](%%action.login%%),' . $this->err = $err;
' or [register](%%action.register%%) a new ' . $this->showPage();
' account. If you already have an account ' .
' on a [compatible microblogging site](%%doc.openmublog%%), ' .
' enter your profile URL below.');
} }
function show_top($err=null) function showPageNotice()
{ {
if ($err) { if ($this->err) {
$this->element('div', 'error', $err); $this->element('div', 'error', $this->err);
} else { } else {
$instructions = $this->get_instructions(); $inst = _('To subscribe, you can [login](%%action.login%%),' .
$output = common_markup_to_html($instructions); ' or [register](%%action.register%%) a new ' .
' account. If you already have an account ' .
' on a [compatible microblogging site](%%doc.openmublog%%), ' .
' enter your profile URL below.');
$output = common_markup_to_html($inst);
$this->elementStart('div', 'instructions'); $this->elementStart('div', 'instructions');
$this->raw($output); $this->raw($output);
$this->elementEnd('p'); $this->elementEnd('div');
} }
} }
function show_form($err=null) function title()
{
return _('Remote subscribe');
}
function showContent()
{ {
$nickname = $this->trimmed('nickname');
$profile = $this->trimmed('profile_url');
common_show_header(_('Remote subscribe'), null, $err,
array($this, 'show_top'));
# id = remotesubscribe conflicts with the # id = remotesubscribe conflicts with the
# button on profile page # button on profile page
$this->elementStart('form', array('id' => 'remsub', 'method' => 'post', $this->elementStart('form', array('id' => 'remsub', 'method' => 'post',
'action' => common_local_url('remotesubscribe'))); 'action' => common_local_url('remotesubscribe')));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->input('nickname', _('User nickname'), $nickname, $this->input('nickname', _('User nickname'), $this->nickname,
_('Nickname of the user you want to follow')); _('Nickname of the user you want to follow'));
$this->input('profile_url', _('Profile URL'), $profile, $this->input('profile_url', _('Profile URL'), $this->profile_url,
_('URL of your profile on another compatible microblogging service')); _('URL of your profile on another compatible microblogging service'));
$this->submit('submit', _('Subscribe')); $this->submit('submit', _('Subscribe'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function remote_subscription() function remoteSubscription()
{ {
$user = $this->get_user(); $user = $this->getUser();
if (!$user) { if (!$user) {
$this->show_form(_('No such user.')); $this->showForm(_('No such user.'));
return; return;
} }
$profile = $this->trimmed('profile_url'); $this->profile_url = $this->trimmed('profile_url');
if (!$profile) { if (!$this->profile_url) {
$this->show_form(_('No such user.')); $this->showForm(_('No such user.'));
return; return;
} }
if (!Validate::uri($profile, array('allowed_schemes' => array('http', 'https')))) { if (!Validate::uri($this->profile_url, array('allowed_schemes' => array('http', 'https')))) {
$this->show_form(_('Invalid profile URL (bad format)')); $this->showForm(_('Invalid profile URL (bad format)'));
return; return;
} }
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$yadis = Auth_Yadis_Yadis::discover($profile, $fetcher); $yadis = Auth_Yadis_Yadis::discover($this->profile_url, $fetcher);
if (!$yadis || $yadis->failed) { if (!$yadis || $yadis->failed) {
$this->show_form(_('Not a valid profile URL (no YADIS document).')); $this->showForm(_('Not a valid profile URL (no YADIS document).'));
return; return;
} }
@ -125,52 +137,50 @@ class RemotesubscribeAction extends Action
$xrds =& Auth_Yadis_XRDS::parseXRDS(trim($yadis->response_text)); $xrds =& Auth_Yadis_XRDS::parseXRDS(trim($yadis->response_text));
if (!$xrds) { if (!$xrds) {
$this->show_form(_('Not a valid profile URL (no XRDS defined).')); $this->showForm(_('Not a valid profile URL (no XRDS defined).'));
return; return;
} }
$omb = $this->getOmb($xrds); $omb = $this->getOmb($xrds);
if (!$omb) { if (!$omb) {
$this->show_form(_('Not a valid profile URL (incorrect services).')); $this->showForm(_('Not a valid profile URL (incorrect services).'));
return; return;
} }
if (omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]) == if (omb_service_uri($omb[OAUTH_ENDPOINT_REQUEST]) ==
common_local_url('requesttoken')) common_local_url('requesttoken'))
{ {
$this->show_form(_('That\'s a local profile! Login to subscribe.')); $this->showForm(_('That\'s a local profile! Login to subscribe.'));
return; return;
} }
if (User::staticGet('uri', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]))) { if (User::staticGet('uri', omb_local_id($omb[OAUTH_ENDPOINT_REQUEST]))) {
$this->show_form(_('That\'s a local profile! Login to subscribe.')); $this->showForm(_('That\'s a local profile! Login to subscribe.'));
return; return;
} }
list($token, $secret) = $this->request_token($omb); list($token, $secret) = $this->requestToken($omb);
if (!$token || !$secret) { if (!$token || !$secret) {
$this->show_form(_('Couldn\'t get a request token.')); $this->showForm(_('Couldn\'t get a request token.'));
return; return;
} }
$this->request_authorization($user, $omb, $token, $secret); $this->requestAuthorization($user, $omb, $token, $secret);
} }
function get_user() function getUser()
{ {
$user = null; $user = null;
$nickname = $this->trimmed('nickname'); if ($this->nickname) {
if ($nickname) { $user = User::staticGet('nickname', $this->nickname);
$user = User::staticGet('nickname', $nickname);
} }
return $user; return $user;
} }
function getOmb($xrds) function getOmb($xrds)
{ {
static $omb_endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE); static $omb_endpoints = array(OMB_ENDPOINT_UPDATEPROFILE, OMB_ENDPOINT_POSTNOTICE);
static $oauth_endpoints = array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE, static $oauth_endpoints = array(OAUTH_ENDPOINT_REQUEST, OAUTH_ENDPOINT_AUTHORIZE,
OAUTH_ENDPOINT_ACCESS); OAUTH_ENDPOINT_ACCESS);
@ -265,7 +275,7 @@ class RemotesubscribeAction extends Action
return true; return true;
} }
function request_token($omb) function requestToken($omb)
{ {
$con = omb_oauth_consumer(); $con = omb_oauth_consumer();
@ -310,7 +320,7 @@ class RemotesubscribeAction extends Action
return array($return['oauth_token'], $return['oauth_token_secret']); return array($return['oauth_token'], $return['oauth_token_secret']);
} }
function request_authorization($user, $omb, $token, $secret) function requestAuthorization($user, $omb, $token, $secret)
{ {
global $config; # for license URL global $config; # for license URL
@ -391,9 +401,4 @@ class RemotesubscribeAction extends Action
common_redirect($req->to_url()); common_redirect($req->to_url());
return; return;
} }
function make_nonce()
{
return common_good_rand(16);
}
} }

View File

@ -333,6 +333,8 @@ class ShowgroupAction extends Action
function showSections() function showSections()
{ {
$this->showMembers(); $this->showMembers();
$cloud = new GroupTagCloudSection($this, $this->group);
$cloud->show();
} }
/** /**
@ -349,7 +351,7 @@ class ShowgroupAction extends Action
return; return;
} }
$this->elementStart('div', array('id' => 'entity_subscriptions', $this->elementStart('div', array('id' => 'entity_members',
'class' => 'section')); 'class' => 'section'));
$this->element('h2', null, _('Members')); $this->element('h2', null, _('Members'));
@ -367,5 +369,7 @@ class ShowgroupAction extends Action
array('nickname' => $this->group->nickname))), array('nickname' => $this->group->nickname))),
_('All members')); _('All members'));
} }
$this->elementEnd('div');
} }
} }

View File

@ -75,7 +75,11 @@ class SubscribersAction extends GalleryAction
$offset = ($this->page-1) * PROFILES_PER_PAGE; $offset = ($this->page-1) * PROFILES_PER_PAGE;
$limit = PROFILES_PER_PAGE + 1; $limit = PROFILES_PER_PAGE + 1;
$subscribers = $this->user->getSubscribers($offset, $limit); if ($this->tag) {
$subscribers = $this->user->getTaggedSubscribers($this->tag, $offset, $limit);
} else {
$subscribers = $this->user->getSubscribers($offset, $limit);
}
if ($subscribers) { if ($subscribers) {
$subscribers_list = new SubscribersList($subscribers, $this->user, $this); $subscribers_list = new SubscribersList($subscribers, $this->user, $this);

View File

@ -84,7 +84,11 @@ class SubscriptionsAction extends GalleryAction
$offset = ($this->page-1) * PROFILES_PER_PAGE; $offset = ($this->page-1) * PROFILES_PER_PAGE;
$limit = PROFILES_PER_PAGE + 1; $limit = PROFILES_PER_PAGE + 1;
$subscriptions = $this->user->getSubscriptions($offset, $limit); if ($this->tag) {
$subscriptions = $this->user->getTaggedSubscriptions($this->tag, $offset, $limit);
} else {
$subscriptions = $this->user->getSubscriptions($offset, $limit);
}
if ($subscriptions) { if ($subscriptions) {
$subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this); $subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this);

View File

@ -21,44 +21,42 @@ if (!defined('LACONICA')) { exit(1); }
class SupAction extends Action class SupAction extends Action
{ {
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
$seconds = $this->trimmed('seconds'); $seconds = $this->trimmed('seconds');
if (!$seconds) { if (!$seconds) {
$seconds = 15; $seconds = 15;
} }
$updates = $this->get_updates($seconds); $updates = $this->getUpdates($seconds);
header('Content-Type: application/json; charset=utf-8'); header('Content-Type: application/json; charset=utf-8');
print json_encode(array('updated_time' => date('c'), print json_encode(array('updated_time' => date('c'),
'since_time' => date('c', time() - $seconds), 'since_time' => date('c', time() - $seconds),
'available_periods' => $this->available_periods(), 'available_periods' => $this->availablePeriods(),
'period' => $seconds, 'period' => $seconds,
'updates' => $updates)); 'updates' => $updates));
} }
function available_periods() function availablePeriods()
{ {
static $periods = array(86400, 43200, 21600, 7200, static $periods = array(86400, 43200, 21600, 7200,
3600, 1800, 600, 300, 120, 3600, 1800, 600, 300, 120,
60, 30, 15); 60, 30, 15);
$available = array(); $available = array();
foreach ($periods as $period) { foreach ($periods as $period) {
$available[$period] = common_local_url('sup', $available[$period] = common_local_url('sup',
array('seconds' => $period)); array('seconds' => $period));
} }
return $available; return $available;
} }
function get_updates($seconds) function getUpdates($seconds)
{ {
$notice = new Notice(); $notice = new Notice();
@ -69,16 +67,16 @@ class SupAction extends Action
'FROM notice ' . 'FROM notice ' .
'WHERE created > (now() - ' . $seconds . ') ' . 'WHERE created > (now() - ' . $seconds . ') ' .
'GROUP BY profile_id'); 'GROUP BY profile_id');
$updates = array(); $updates = array();
while ($notice->fetch()) { while ($notice->fetch()) {
$updates[] = array($notice->profile_id, $notice->max_id); $updates[] = array($notice->profile_id, $notice->max_id);
} }
return $updates; return $updates;
} }
function isReadOnly() function isReadOnly()
{ {
return true; return true;

View File

@ -23,71 +23,85 @@ require_once(INSTALLDIR.'/lib/settingsaction.php');
class TagotherAction extends Action class TagotherAction extends Action
{ {
var $profile = null;
var $error = null;
function prepare($args)
{
parent::prepare($args);
if (!common_logged_in()) {
$this->clientError(_('Not logged in'), 403);
return false;
}
$id = $this->trimmed('id');
if (!$id) {
$this->clientError(_('No id argument.'));
return false;
}
$this->profile = Profile::staticGet('id', $id);
if (!$this->profile) {
$this->clientError(_('No profile with that ID.'));
return false;
}
return true;
}
function handle($args) function handle($args)
{ {
parent::handle($args); parent::handle($args);
if (!common_logged_in()) {
$this->clientError(_('Not logged in'), 403);
return;
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$this->save_tags(); $this->saveTags();
} else { } else {
$id = $this->trimmed('id'); $this->showForm($profile);
if (!$id) {
$this->clientError(_('No id argument.'));
return;
}
$profile = Profile::staticGet('id', $id);
if (!$profile) {
$this->clientError(_('No profile with that ID.'));
return;
}
$this->show_form($profile);
} }
} }
function show_form($profile, $error=null) function title()
{ {
return sprintf(_('Tag %s'), $this->profile->nickname);
}
$user = common_current_user(); function showForm($error=null)
{
$this->error = $error;
$this->showPage();
}
common_show_header(_('Tag a person'), function showContent()
null, array($profile, $error), array($this, 'show_top')); {
$avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
$this->element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_PROFILE_SIZE), $this->element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_PROFILE_SIZE),
'class' => 'avatar stream', 'class' => 'avatar stream',
'width' => AVATAR_PROFILE_SIZE, 'width' => AVATAR_PROFILE_SIZE,
'height' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE,
'alt' => 'alt' =>
($profile->fullname) ? $profile->fullname : ($this->profile->fullname) ? $this->profile->fullname :
$profile->nickname)); $this->profile->nickname));
$this->element('a', array('href' => $profile->profileurl, $this->element('a', array('href' => $this->profile->profileurl,
'class' => 'external profile nickname'), 'class' => 'external profile nickname'),
$profile->nickname); $this->profile->nickname);
if ($profile->fullname) { if ($this->profile->fullname) {
$this->elementStart('div', 'fullname'); $this->elementStart('div', 'fullname');
if ($profile->homepage) { if ($this->profile->homepage) {
$this->element('a', array('href' => $profile->homepage), $this->element('a', array('href' => $this->profile->homepage),
$profile->fullname); $this->profile->fullname);
} else { } else {
$this->text($profile->fullname); $this->text($this->profile->fullname);
} }
$this->elementEnd('div'); $this->elementEnd('div');
} }
if ($profile->location) { if ($this->profile->location) {
$this->element('div', 'location', $profile->location); $this->element('div', 'location', $this->profile->location);
} }
if ($profile->bio) { if ($this->profile->bio) {
$this->element('div', 'bio', $profile->bio); $this->element('div', 'bio', $this->profile->bio);
} }
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
@ -95,33 +109,24 @@ class TagotherAction extends Action
'name' => 'tagother', 'name' => 'tagother',
'action' => $this->selfUrl())); 'action' => $this->selfUrl()));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->hidden('id', $profile->id); $this->hidden('id', $this->profile->id);
$this->input('tags', _('Tags'), $this->input('tags', _('Tags'),
($this->arg('tags')) ? $this->arg('tags') : implode(' ', Profile_tag::getTags($user->id, $profile->id)), ($this->arg('tags')) ? $this->arg('tags') : implode(' ', Profile_tag::getTags($user->id, $this->profile->id)),
_('Tags for this user (letters, numbers, -, ., and _), comma- or space- separated')); _('Tags for this user (letters, numbers, -, ., and _), comma- or space- separated'));
$this->submit('save', _('Save')); $this->submit('save', _('Save'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function save_tags() function saveTags()
{ {
$id = $this->trimmed('id'); $id = $this->trimmed('id');
$tagstring = $this->trimmed('tags'); $tagstring = $this->trimmed('tags');
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$this->show_form(_('There was a problem with your session token. Try again, please.')); $this->showForm(_('There was a problem with your session token.'.
return; ' Try again, please.'));
}
$profile = Profile::staticGet('id', $id);
if (!$profile) {
$this->clientError(_('No such profile.'));
return; return;
} }
@ -132,7 +137,7 @@ class TagotherAction extends Action
foreach ($tags as $tag) { foreach ($tags as $tag) {
if (!common_valid_profile_tag($tag)) { if (!common_valid_profile_tag($tag)) {
$this->show_form($profile, sprintf(_('Invalid tag: "%s"'), $tag)); $this->showForm(sprintf(_('Invalid tag: "%s"'), $tag));
return; return;
} }
} }
@ -143,22 +148,22 @@ class TagotherAction extends Action
$user = common_current_user(); $user = common_current_user();
if (!Subscription::pkeyGet(array('subscriber' => $user->id, if (!Subscription::pkeyGet(array('subscriber' => $user->id,
'subscribed' => $profile->id)) && 'subscribed' => $this->profile->id)) &&
!Subscription::pkeyGet(array('subscriber' => $profile->id, !Subscription::pkeyGet(array('subscriber' => $this->profile->id,
'subscribed' => $user->id))) 'subscribed' => $user->id)))
{ {
$this->clientError(_('You can only tag people you are subscribed to or who are subscribed to you.')); $this->clientError(_('You can only tag people you are subscribed to or who are subscribed to you.'));
return; return;
} }
$result = Profile_tag::setTags($user->id, $profile->id, $tags); $result = Profile_tag::setTags($user->id, $this->profile->id, $tags);
if (!$result) { if (!$result) {
$this->clientError(_('Could not save tags.')); $this->clientError(_('Could not save tags.'));
return; return;
} }
$action = $user->isSubscribed($profile) ? 'subscriptions' : 'subscribers'; $action = $user->isSubscribed($this->profile) ? 'subscriptions' : 'subscribers';
if ($this->boolean('ajax')) { if ($this->boolean('ajax')) {
common_start_html('text/xml'); common_start_html('text/xml');
@ -182,11 +187,10 @@ class TagotherAction extends Action
} }
} }
function show_top($arr = null) function showPageNotice()
{ {
list($profile, $error) = $arr; if ($this->error) {
if ($error) { $this->element('p', 'error', $this->error);
$this->element('p', 'error', $error);
} else { } else {
$this->elementStart('div', 'instructions'); $this->elementStart('div', 'instructions');
$this->element('p', null, $this->element('p', null,

View File

@ -24,6 +24,8 @@ define('TIMESTAMP_THRESHOLD', 300);
class UserauthorizationAction extends Action class UserauthorizationAction extends Action
{ {
var $error;
var $req;
function handle($args) function handle($args)
{ {
@ -33,37 +35,33 @@ class UserauthorizationAction extends Action
# CSRF protection # CSRF protection
$token = $this->trimmed('token'); $token = $this->trimmed('token');
if (!$token || $token != common_session_token()) { if (!$token || $token != common_session_token()) {
$req = $this->get_stored_request(); $req = $this->getStoredRequest();
$this->show_form(_('There was a problem with your session token. Try again, please.'), $req); $this->showForm($req, _('There was a problem with your session token. '.
'Try again, please.'));
return; return;
} }
# We've shown the form, now post user's choice # We've shown the form, now post user's choice
$this->send_authorization(); $this->sendAuthorization();
} else { } else {
if (!common_logged_in()) { if (!common_logged_in()) {
# Go log in, and then come back # Go log in, and then come back
common_debug('saving URL for returnto', __FILE__);
common_set_returnto($_SERVER['REQUEST_URI']); common_set_returnto($_SERVER['REQUEST_URI']);
common_debug('redirecting to login', __FILE__);
common_redirect(common_local_url('login')); common_redirect(common_local_url('login'));
return; return;
} }
try { try {
# this must be a new request # this must be a new request
common_debug('getting new request', __FILE__); $req = $this->getNewRequest();
$req = $this->get_new_request();
if (!$req) { if (!$req) {
$this->clientError(_('No request found!')); $this->clientError(_('No request found!'));
} }
common_debug('validating request', __FILE__);
# XXX: only validate new requests, since nonce is one-time use # XXX: only validate new requests, since nonce is one-time use
$this->validate_request($req); $this->validateRequest($req);
common_debug('showing form', __FILE__); $this->storeRequest($req);
$this->store_request($req); $this->showForm($req);
$this->show_form($req);
} catch (OAuthException $e) { } catch (OAuthException $e) {
$this->clear_request(); $this->clearRequest();
$this->clientError($e->getMessage()); $this->clientError($e->getMessage());
return; return;
} }
@ -71,8 +69,29 @@ class UserauthorizationAction extends Action
} }
} }
function show_form($req) function showForm($req, $error=null)
{ {
$this->req = $req;
$this->error = $error;
$this->showPage();
}
function title()
{
return _('Authorize subscription');
}
function showPageNotice()
{
$this->element('p', null, _('Please check these details to make sure '.
'that you want to subscribe to this user\'s notices. '.
'If you didn\'t just ask to subscribe to someone\'s notices, '.
'click "Cancel".'));
}
function showContent()
{
$req = $this->req;
$nickname = $req->get_parameter('omb_listenee_nickname'); $nickname = $req->get_parameter('omb_listenee_nickname');
$profile = $req->get_parameter('omb_listenee_profile'); $profile = $req->get_parameter('omb_listenee_profile');
@ -83,11 +102,6 @@ class UserauthorizationAction extends Action
$location = $req->get_parameter('omb_listenee_location'); $location = $req->get_parameter('omb_listenee_location');
$avatar = $req->get_parameter('omb_listenee_avatar'); $avatar = $req->get_parameter('omb_listenee_avatar');
common_show_header(_('Authorize subscription'));
$this->element('p', null, _('Please check these details to make sure '.
'that you want to subscribe to this user\'s notices. '.
'If you didn\'t just ask to subscribe to someone\'s notices, '.
'click "Cancel".'));
$this->elementStart('div', 'profile'); $this->elementStart('div', 'profile');
if ($avatar) { if ($avatar) {
$this->element('img', array('src' => $avatar, $this->element('img', array('src' => $avatar,
@ -122,19 +136,18 @@ class UserauthorizationAction extends Action
$this->elementEnd('div'); $this->elementEnd('div');
$this->elementEnd('div'); $this->elementEnd('div');
$this->elementStart('form', array('method' => 'post', $this->elementStart('form', array('method' => 'post',
'id' => 'userauthorization', 'id' => 'userauthorization',
'name' => 'userauthorization', 'name' => 'userauthorization',
'action' => common_local_url('userauthorization'))); 'action' => common_local_url('userauthorization')));
$this->hidden('token', common_session_token()); $this->hidden('token', common_session_token());
$this->submit('accept', _('Accept')); $this->submit('accept', _('Accept'));
$this->submit('reject', _('Reject')); $this->submit('reject', _('Reject'));
$this->elementEnd('form'); $this->elementEnd('form');
common_show_footer();
} }
function send_authorization() function sendAuthorization()
{ {
$req = $this->get_stored_request(); $req = $this->getStoredRequest();
if (!$req) { if (!$req) {
$this->clientError(_('No authorization request!')); $this->clientError(_('No authorization request!'));
@ -144,14 +157,14 @@ class UserauthorizationAction extends Action
$callback = $req->get_parameter('oauth_callback'); $callback = $req->get_parameter('oauth_callback');
if ($this->arg('accept')) { if ($this->arg('accept')) {
if (!$this->authorize_token($req)) { if (!$this->authorizeToken($req)) {
$this->clientError(_('Error authorizing token')); $this->clientError(_('Error authorizing token'));
} }
if (!$this->save_remote_profile($req)) { if (!$this->saveRemoteProfile($req)) {
$this->clientError(_('Error saving remote profile')); $this->clientError(_('Error saving remote profile'));
} }
if (!$callback) { if (!$callback) {
$this->show_accept_message($req->get_parameter('oauth_token')); $this->showAcceptMessage($req->get_parameter('oauth_token'));
} else { } else {
$params = array(); $params = array();
$params['oauth_token'] = $req->get_parameter('oauth_token'); $params['oauth_token'] = $req->get_parameter('oauth_token');
@ -193,7 +206,7 @@ class UserauthorizationAction extends Action
} }
} else { } else {
if (!$callback) { if (!$callback) {
$this->show_reject_message(); $this->showRejectMessage();
} else { } else {
# XXX: not 100% sure how to signal failure... just redirect without token? # XXX: not 100% sure how to signal failure... just redirect without token?
common_redirect($callback, 303); common_redirect($callback, 303);
@ -201,24 +214,19 @@ class UserauthorizationAction extends Action
} }
} }
function authorize_token(&$req) function authorizeToken(&$req)
{ {
$consumer_key = $req->get_parameter('oauth_consumer_key'); $consumer_key = $req->get_parameter('oauth_consumer_key');
$token_field = $req->get_parameter('oauth_token'); $token_field = $req->get_parameter('oauth_token');
common_debug('consumer key = "'.$consumer_key.'"', __FILE__);
common_debug('token field = "'.$token_field.'"', __FILE__);
$rt = new Token(); $rt = new Token();
$rt->consumer_key = $consumer_key; $rt->consumer_key = $consumer_key;
$rt->tok = $token_field; $rt->tok = $token_field;
$rt->type = 0; $rt->type = 0;
$rt->state = 0; $rt->state = 0;
common_debug('request token to look up: "'.print_r($rt,true).'"');
if ($rt->find(true)) { if ($rt->find(true)) {
common_debug('found request token to authorize', __FILE__);
$orig_rt = clone($rt); $orig_rt = clone($rt);
$rt->state = 1; # Authorized but not used $rt->state = 1; # Authorized but not used
if ($rt->update($orig_rt)) { if ($rt->update($orig_rt)) {
common_debug('updated request token so it is authorized', __FILE__);
return true; return true;
} }
} }
@ -227,7 +235,7 @@ class UserauthorizationAction extends Action
# XXX: refactor with similar code in finishremotesubscribe.php # XXX: refactor with similar code in finishremotesubscribe.php
function save_remote_profile(&$req) function saveRemoteProfile(&$req)
{ {
# FIXME: we should really do this when the consumer comes # FIXME: we should really do this when the consumer comes
# back for an access token. If they never do, we've got stuff in a # back for an access token. If they never do, we've got stuff in a
@ -295,15 +303,15 @@ class UserauthorizationAction extends Action
} }
if ($avatar_url) { if ($avatar_url) {
if (!$this->add_avatar($profile, $avatar_url)) { if (!$this->addAvatar($profile, $avatar_url)) {
return false; return false;
} }
} }
$user = common_current_user(); $user = common_current_user();
$datastore = omb_oauth_datastore(); $datastore = omb_oauth_datastore();
$consumer = $this->get_consumer($datastore, $req); $consumer = $this->getConsumer($datastore, $req);
$token = $this->get_token($datastore, $req, $consumer); $token = $this->getToken($datastore, $req, $consumer);
$sub = new Subscription(); $sub = new Subscription();
$sub->subscriber = $user->id; $sub->subscriber = $user->id;
@ -318,54 +326,54 @@ class UserauthorizationAction extends Action
return true; return true;
} }
function add_avatar($profile, $url) function addAvatar($profile, $url)
{ {
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar'); $temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
copy($url, $temp_filename); copy($url, $temp_filename);
return $profile->setOriginal($temp_filename); return $profile->setOriginal($temp_filename);
} }
function show_accept_message($tok) function showAcceptMessage($tok)
{ {
common_show_header(_('Subscription authorized')); common_show_header(_('Subscription authorized'));
$this->element('p', null, $this->element('p', null,
_('The subscription has been authorized, but no '. _('The subscription has been authorized, but no '.
'callback URL was passed. Check with the site\'s instructions for '. 'callback URL was passed. Check with the site\'s instructions for '.
'details on how to authorize the subscription. Your subscription token is:')); 'details on how to authorize the subscription. Your subscription token is:'));
$this->element('blockquote', 'token', $tok); $this->element('blockquote', 'token', $tok);
common_show_footer(); common_show_footer();
} }
function show_reject_message($tok) function showRejectMessage($tok)
{ {
common_show_header(_('Subscription rejected')); common_show_header(_('Subscription rejected'));
$this->element('p', null, $this->element('p', null,
_('The subscription has been rejected, but no '. _('The subscription has been rejected, but no '.
'callback URL was passed. Check with the site\'s instructions for '. 'callback URL was passed. Check with the site\'s instructions for '.
'details on how to fully reject the subscription.')); 'details on how to fully reject the subscription.'));
common_show_footer(); common_show_footer();
} }
function store_request($req) function storeRequest($req)
{ {
common_ensure_session(); common_ensure_session();
$_SESSION['userauthorizationrequest'] = $req; $_SESSION['userauthorizationrequest'] = $req;
} }
function clear_request() function clearRequest()
{ {
common_ensure_session(); common_ensure_session();
unset($_SESSION['userauthorizationrequest']); unset($_SESSION['userauthorizationrequest']);
} }
function get_stored_request() function getStoredRequest()
{ {
common_ensure_session(); common_ensure_session();
$req = $_SESSION['userauthorizationrequest']; $req = $_SESSION['userauthorizationrequest'];
return $req; return $req;
} }
function get_new_request() function getNewRequest()
{ {
common_remove_magic_from_request(); common_remove_magic_from_request();
$req = OAuthRequest::from_request(); $req = OAuthRequest::from_request();
@ -374,31 +382,22 @@ class UserauthorizationAction extends Action
# Throws an OAuthException if anything goes wrong # Throws an OAuthException if anything goes wrong
function validate_request(&$req) function validateRequest(&$req)
{ {
# OAuth stuff -- have to copy from OAuth.php since they're # OAuth stuff -- have to copy from OAuth.php since they're
# all private methods, and there's no user-authentication method # all private methods, and there's no user-authentication method
common_debug('checking version', __FILE__); $this->checkVersion($req);
$this->check_version($req);
common_debug('getting datastore', __FILE__);
$datastore = omb_oauth_datastore(); $datastore = omb_oauth_datastore();
common_debug('getting consumer', __FILE__); $consumer = $this->getConsumer($datastore, $req);
$consumer = $this->get_consumer($datastore, $req); $token = $this->getToken($datastore, $req, $consumer);
common_debug('getting token', __FILE__); $this->checkTimestamp($req);
$token = $this->get_token($datastore, $req, $consumer); $this->checkNonce($datastore, $req, $consumer, $token);
common_debug('checking timestamp', __FILE__); $this->checkSignature($req, $consumer, $token);
$this->check_timestamp($req); $this->validateOmb($req);
common_debug('checking nonce', __FILE__);
$this->check_nonce($datastore, $req, $consumer, $token);
common_debug('checking signature', __FILE__);
$this->check_signature($req, $consumer, $token);
common_debug('validating omb stuff', __FILE__);
$this->validate_omb($req);
common_debug('done validating', __FILE__);
return true; return true;
} }
function validate_omb(&$req) function validateOmb(&$req)
{ {
foreach (array('omb_version', 'omb_listener', 'omb_listenee', foreach (array('omb_version', 'omb_listener', 'omb_listenee',
'omb_listenee_profile', 'omb_listenee_nickname', 'omb_listenee_profile', 'omb_listenee_nickname',
@ -513,7 +512,7 @@ class UserauthorizationAction extends Action
# Snagged from OAuthServer # Snagged from OAuthServer
function check_version(&$req) function checkVersion(&$req)
{ {
$version = $req->get_parameter("oauth_version"); $version = $req->get_parameter("oauth_version");
if (!$version) { if (!$version) {
@ -527,7 +526,7 @@ class UserauthorizationAction extends Action
# Snagged from OAuthServer # Snagged from OAuthServer
function get_consumer($datastore, $req) function getConsumer($datastore, $req)
{ {
$consumer_key = @$req->get_parameter("oauth_consumer_key"); $consumer_key = @$req->get_parameter("oauth_consumer_key");
if (!$consumer_key) { if (!$consumer_key) {
@ -543,7 +542,7 @@ class UserauthorizationAction extends Action
# Mostly cadged from OAuthServer # Mostly cadged from OAuthServer
function get_token($datastore, &$req, $consumer) function getToken($datastore, &$req, $consumer)
{/*{{{*/ {/*{{{*/
$token_field = @$req->get_parameter('oauth_token'); $token_field = @$req->get_parameter('oauth_token');
$token = $datastore->lookup_token($consumer, 'request', $token_field); $token = $datastore->lookup_token($consumer, 'request', $token_field);
@ -553,7 +552,7 @@ class UserauthorizationAction extends Action
return $token; return $token;
} }
function check_timestamp(&$req) function checkTimestamp(&$req)
{ {
$timestamp = @$req->get_parameter('oauth_timestamp'); $timestamp = @$req->get_parameter('oauth_timestamp');
$now = time(); $now = time();
@ -563,7 +562,7 @@ class UserauthorizationAction extends Action
} }
# NOTE: don't call twice on the same request; will fail! # NOTE: don't call twice on the same request; will fail!
function check_nonce(&$datastore, &$req, $consumer, $token) function checkNonce(&$datastore, &$req, $consumer, $token)
{ {
$timestamp = @$req->get_parameter('oauth_timestamp'); $timestamp = @$req->get_parameter('oauth_timestamp');
$nonce = @$req->get_parameter('oauth_nonce'); $nonce = @$req->get_parameter('oauth_nonce');
@ -574,9 +573,9 @@ class UserauthorizationAction extends Action
return true; return true;
} }
function check_signature(&$req, $consumer, $token) function checkSignature(&$req, $consumer, $token)
{ {
$signature_method = $this->get_signature_method($req); $signature_method = $this->getSignatureMethod($req);
$signature = $req->get_parameter('oauth_signature'); $signature = $req->get_parameter('oauth_signature');
$valid_sig = $signature_method->check_signature($req, $valid_sig = $signature_method->check_signature($req,
$consumer, $consumer,
@ -587,7 +586,7 @@ class UserauthorizationAction extends Action
} }
} }
function get_signature_method(&$req) function getSignatureMethod(&$req)
{ {
$signature_method = @$req->get_parameter("oauth_signature_method"); $signature_method = @$req->get_parameter("oauth_signature_method");
if (!$signature_method) { if (!$signature_method) {

View File

@ -49,17 +49,17 @@ class XrdsAction extends Action
{ {
/** /**
* Is read only? * Is read only?
* *
* @return boolean true * @return boolean true
*/ */
function isReadOnly() function isReadOnly()
{ {
return true; return true;
} }
/** /**
* Class handler. * Class handler.
* *
* @param array $args query arguments * @param array $args query arguments
* *
* @return void * @return void
@ -78,7 +78,7 @@ class XrdsAction extends Action
/** /**
* Show XRDS for a user. * Show XRDS for a user.
* *
* @param class $user XRDS for this user. * @param class $user XRDS for this user.
* *
* @return void * @return void
@ -86,7 +86,7 @@ class XrdsAction extends Action
function showXrds($user) function showXrds($user)
{ {
header('Content-Type: application/xrds+xml'); header('Content-Type: application/xrds+xml');
common_start_xml(); $this->startXML();
$this->elementStart('XRDS', array('xmlns' => 'xri://$xrds')); $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)', $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
@ -133,12 +133,12 @@ class XrdsAction extends Action
'#omb'); '#omb');
$this->elementEnd('XRD'); $this->elementEnd('XRD');
$this->elementEnd('XRDS'); $this->elementEnd('XRDS');
common_end_xml(); $this->endXML();
} }
/** /**
* Show service. * Show service.
* *
* @param string $type XRDS type * @param string $type XRDS type
* @param string $uri URI * @param string $uri URI
* @param array $params type parameters, null by default * @param array $params type parameters, null by default

View File

@ -218,10 +218,7 @@ class Memcached_DataObject extends DB_DataObject
} }
$inst = new $cls(); $inst = new $cls();
$result = $inst->query($qry); $inst->query($qry);
if (!$result) {
return $inst;
}
$cached = array(); $cached = array();
while ($inst->fetch()) { while ($inst->fetch()) {
$cached[] = clone($inst); $cached[] = clone($inst);

View File

@ -575,4 +575,58 @@ class User extends Memcached_DataObject
return $profile; return $profile;
} }
function getTaggedSubscribers($tag, $offset=0, $limit=null)
{
$qry =
'SELECT profile.* ' .
'FROM profile JOIN subscription ' .
'ON profile.id = subscription.subscriber ' .
'JOIN profile_tag ON (profile_tag.tagged = subscription.subscriber ' .
'AND profile_tag.tagger = subscription.subscribed) ' .
'WHERE subscription.subscribed = %d ' .
'AND profile_tag.tag = "%s" ' .
'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC ';
if ($offset) {
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
}
$profile = new Profile();
$cnt = $profile->query(sprintf($qry, $this->id, $tag));
return $profile;
}
function getTaggedSubscriptions($tag, $offset=0, $limit=null)
{
$qry =
'SELECT profile.* ' .
'FROM profile JOIN subscription ' .
'ON profile.id = subscription.subscribed ' .
'JOIN profile_tag on (profile_tag.tagged = subscription.subscribed ' .
'AND profile_tag.tagger = subscription.subscriber) ' .
'WHERE subscription.subscriber = %d ' .
'AND profile_tag.tag = "%s" ' .
'AND subscription.subscribed != subscription.subscriber ' .
'ORDER BY subscription.created DESC ';
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = new Profile();
$profile->query(sprintf($qry, $this->id, $tag));
return $profile;
}
} }

View File

@ -184,7 +184,7 @@ $(document).ready(function(){
$("#form_notice").ajaxForm(PostNotice); $("#form_notice").ajaxForm(PostNotice);
$("#form_notice").each(addAjaxHidden); $("#form_notice").each(addAjaxHidden);
$(".notice").hover( $("#content .notice").hover(
function () { function () {
$(this).addClass('hover'); $(this).addClass('hover');
}, },

View File

@ -0,0 +1,89 @@
<?php
/**
* Laconica, the distributed open-source microblogging tool
*
* Section for featured users
*
* 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 Widget
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @copyright 2009 Control Yourself, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
if (!defined('LACONICA')) {
exit(1);
}
/**
* Section for featured users
*
* @category Widget
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
class FeaturedUsersSection extends ProfileSection
{
function getProfiles()
{
$featured_nicks = common_config('nickname', 'featured');
if (!$featured_nicks) {
return null;
}
$quoted = array();
foreach ($featured_nicks as $nick) {
$quoted[] = "'$nick'";
}
$qry = 'SELECT profile.* ' .
'FROM profile JOIN user on profile.id = user.id ' .
'WHERE user.nickname in (' . implode(',', $quoted) . ') ' .
'ORDER BY profile.created DESC ';
$limit = PROFILES_PER_SECTION + 1;
$offset = 0;
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$profile = Memcached_DataObject::cachedQuery('Profile',
$qry,
6 * 3600);
return $profile;
}
function title()
{
return _('Featured users');
}
function divId()
{
return 'featured_users';
}
}

View File

@ -32,6 +32,7 @@ class GalleryAction extends Action
var $profile = null; var $profile = null;
var $user = null; var $user = null;
var $page = null; var $page = null;
var $tag = null;
function prepare($args) function prepare($args)
{ {
@ -69,6 +70,8 @@ class GalleryAction extends Action
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
$this->tag = $this->trimmed('tag');
return true; return true;
} }
@ -84,7 +87,7 @@ class GalleryAction extends Action
# Post from the tag dropdown; redirect to a GET # Post from the tag dropdown; redirect to a GET
if ($_SERVER['REQUEST_METHOD'] == 'POST') { if ($_SERVER['REQUEST_METHOD'] == 'POST') {
common_redirect($this->self_url(), 307); common_redirect($this->selfUrl(), 307);
return; return;
} }
@ -124,7 +127,7 @@ class GalleryAction extends Action
array('href' => array('href' =>
common_local_url($this->trimmed('action'), common_local_url($this->trimmed('action'),
array('nickname' => array('nickname' =>
$profile->nickname))), $this->user->nickname))),
_('All')); _('All'));
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementStart('li', array('id'=>'filter_tags_item')); $this->elementStart('li', array('id'=>'filter_tags_item'));

View File

@ -58,13 +58,13 @@ class GroupSection extends Section
$cnt = 0; $cnt = 0;
$this->out->elementStart('ul', 'entities group xoxo'); $this->out->elementStart('table');
while ($profiles->fetch() && ++$cnt <= GROUPS_PER_SECTION) { while ($profiles->fetch() && ++$cnt <= GROUPS_PER_SECTION) {
$this->showGroup($profiles); $this->showGroup($profiles);
} }
$this->out->elementEnd('ul'); $this->out->elementEnd('table');
return ($cnt > GROUPS_PER_SECTION); return ($cnt > GROUPS_PER_SECTION);
} }
@ -76,7 +76,9 @@ class GroupSection extends Section
function showGroup($group) function showGroup($group)
{ {
$this->out->elementStart('li', 'vcard'); $this->out->elementStart('tr');
$this->out->elementStart('td');
$this->out->elementStart('span', 'vcard');
$this->out->elementStart('a', array('title' => ($group->fullname) ? $this->out->elementStart('a', array('title' => ($group->fullname) ?
$group->fullname : $group->fullname :
$group->nickname, $group->nickname,
@ -95,9 +97,11 @@ class GroupSection extends Section
$group->nickname)); $group->nickname));
$this->out->element('span', 'fn org nickname', $group->nickname); $this->out->element('span', 'fn org nickname', $group->nickname);
$this->out->elementEnd('a'); $this->out->elementEnd('a');
$this->out->elementEnd('span');
$this->out->elementEnd('td');
if ($group->value) { if ($group->value) {
$this->out->element('span', 'value', $group->value); $this->out->element('td', 'value', $group->value);
} }
$this->out->elementEnd('li'); $this->out->elementEnd('tr');
} }
} }

View File

@ -0,0 +1,87 @@
<?php
/**
* Laconica, the distributed open-source microblogging tool
*
* Personal tag cloud section
*
* 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 Widget
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @copyright 2009 Control Yourself, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
if (!defined('LACONICA')) {
exit(1);
}
/**
* Personal tag cloud section
*
* @category Widget
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://laconi.ca/
*/
class GroupTagCloudSection extends TagCloudSection
{
var $group = null;
function __construct($out=null, $group=null)
{
parent::__construct($out);
$this->group = $group;
}
function title()
{
return sprintf(_('Tags in %s group\'s notices'), $this->group->nickname);
}
function getTags()
{
$qry = 'SELECT notice_tag.tag, '.
'sum(exp(-(now() - notice_tag.created)/%s)) as weight ' .
'FROM notice_tag JOIN notice ' .
'ON notice_tag.notice_id = notice.id ' .
'JOIN group_inbox on group_inbox.notice_id = notice.id ' .
'WHERE group_inbox.group_id = %d ' .
'GROUP BY notice_tag.tag ' .
'ORDER BY weight DESC ';
$limit = TAGS_PER_SECTION;
$offset = 0;
if (common_config('db','type') == 'pgsql') {
$qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
$qry .= ' LIMIT ' . $offset . ', ' . $limit;
}
$tag = Memcached_DataObject::cachedQuery('Notice_tag',
sprintf($qry,
common_config('tag', 'dropoff'),
$this->group->id),
3600);
return $tag;
}
}

View File

@ -54,13 +54,13 @@ class NoticeSection extends Section
$cnt = 0; $cnt = 0;
$this->out->elementStart('table', 'notices'); $this->out->elementStart('ul', 'notices');
while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) { while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) {
$this->showNotice($notices); $this->showNotice($notices);
} }
$this->out->elementEnd('table'); $this->out->elementEnd('ul');
return ($cnt > NOTICES_PER_SECTION); return ($cnt > NOTICES_PER_SECTION);
} }
@ -73,9 +73,15 @@ class NoticeSection extends Section
function showNotice($notice) function showNotice($notice)
{ {
$profile = $notice->getProfile(); $profile = $notice->getProfile();
$this->out->elementStart('tr'); $this->out->elementStart('li', 'hentry notice');
$this->out->elementStart('td'); $this->out->elementStart('div', 'entry-title');
$avatar = $profile->getAvatar(AVATAR_MINI_SIZE); $avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
$this->out->elementStart('span', 'vcard author');
$this->out->elementStart('a', array('title' => ($profile->fullname) ?
$profile->fullname :
$profile->nickname,
'href' => $profile->noticeurl,
'class' => 'url'));
$this->out->element('img', array('src' => (($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_MINI_SIZE)), $this->out->element('img', array('src' => (($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_MINI_SIZE)),
'width' => AVATAR_MINI_SIZE, 'width' => AVATAR_MINI_SIZE,
'height' => AVATAR_MINI_SIZE, 'height' => AVATAR_MINI_SIZE,
@ -83,25 +89,19 @@ class NoticeSection extends Section
'alt' => ($profile->fullname) ? 'alt' => ($profile->fullname) ?
$profile->fullname : $profile->fullname :
$profile->nickname)); $profile->nickname));
$this->out->elementEnd('a');
$this->out->elementEnd('td');
$this->out->elementStart('td');
$this->out->elementStart('a', array('title' => ($profile->fullname) ?
$profile->fullname :
$profile->nickname,
'href' => $profile->noticeurl,
'rel' => 'contact member',
'class' => 'url'));
$this->out->element('span', 'fn nickname', $profile->nickname); $this->out->element('span', 'fn nickname', $profile->nickname);
$this->out->elementEnd('td'); $this->out->elementEnd('a');
$this->out->elementStart('td'); $this->out->elementEnd('span');
$this->out->elementStart('p', 'entry-content');
$this->out->raw($notice->rendered); $this->out->raw($notice->rendered);
$this->out->elementEnd('td'); $this->out->elementEnd('p');
if ($notice->value) { if ($notice->value) {
$this->out->elementStart('td'); $this->out->elementStart('p');
$this->out->text($notice->value); $this->out->text($notice->value);
$this->out->elementEnd('td'); $this->out->elementEnd('p');
} }
$this->out->elementEnd('tr'); $this->out->elementEnd('div');
$this->out->elementEnd('li');
} }
} }

View File

@ -169,9 +169,9 @@ class ProfileList extends Widget
$this->out->elementStart('ul', 'tags xoxo'); $this->out->elementStart('ul', 'tags xoxo');
foreach ($tags as $tag) { foreach ($tags as $tag) {
$this->out->elementStart('li'); $this->out->elementStart('li');
$this->element('span', 'mark_hash', '#'); $this->out->element('span', 'mark_hash', '#');
$this->out->element('a', array('rel' => 'tag', $this->out->element('a', array('rel' => 'tag',
'href' => common_local_url($this->action, 'href' => common_local_url($this->action->trimmed('action'),
array('nickname' => $this->owner->nickname, array('nickname' => $this->owner->nickname,
'tag' => $tag))), 'tag' => $tag))),
$tag); $tag);

View File

@ -76,7 +76,9 @@ class ProfileSection extends Section
function showProfile($profile) function showProfile($profile)
{ {
$this->out->elementStart('li', 'vcard'); $this->out->elementStart('tr');
$this->out->elementStart('td');
$this->out->elementStart('span', 'vcard');
$this->out->elementStart('a', array('title' => ($profile->fullname) ? $this->out->elementStart('a', array('title' => ($profile->fullname) ?
$profile->fullname : $profile->fullname :
$profile->nickname, $profile->nickname,
@ -92,10 +94,13 @@ class ProfileSection extends Section
$profile->fullname : $profile->fullname :
$profile->nickname)); $profile->nickname));
$this->out->element('span', 'fn nickname', $profile->nickname); $this->out->element('span', 'fn nickname', $profile->nickname);
$this->out->elementEnd('span');
$this->out->elementEnd('a'); $this->out->elementEnd('a');
$this->out->elementEnd('td');
if ($profile->value) { if ($profile->value) {
$this->out->element('span', 'value', $profile->value); $this->out->element('td', 'value', $profile->value);
} }
$this->out->elementEnd('li');
$this->out->elementEnd('tr');
} }
} }

View File

@ -53,6 +53,7 @@ class TagCloudSection extends Section
$tags = $this->getTags(); $tags = $this->getTags();
if (!$tags) { if (!$tags) {
$this->out->element('p', null, _('None'));
return false; return false;
} }
@ -66,6 +67,11 @@ class TagCloudSection extends Section
$sum += $tags->weight; $sum += $tags->weight;
} }
if ($cnt == 0) {
$this->out->element('p', null, _('(None)'));
return false;
}
ksort($tw); ksort($tw);
$this->out->elementStart('ul', 'tags xoxo tag-cloud'); $this->out->elementStart('ul', 'tags xoxo tag-cloud');
@ -110,4 +116,9 @@ class TagCloudSection extends Section
{ {
return common_local_url('tag', array('tag' => $tag)); return common_local_url('tag', array('tag' => $tag));
} }
function divId()
{
return 'tagcloud';
}
} }

View File

@ -69,36 +69,6 @@ class TopPostersSection extends ProfileSection
return $profile; return $profile;
} }
function showProfile($profile)
{
$this->out->elementStart('tr');
$this->out->elementStart('td');
$this->out->elementStart('span', 'vcard');
$this->out->elementStart('a', array('title' => ($profile->fullname) ?
$profile->fullname :
$profile->nickname,
'href' => $profile->profileurl,
'rel' => 'contact member',
'class' => 'url'));
$avatar = $profile->getAvatar(AVATAR_MINI_SIZE);
$this->out->element('img', array('src' => (($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_MINI_SIZE)),
'width' => AVATAR_MINI_SIZE,
'height' => AVATAR_MINI_SIZE,
'class' => 'avatar photo',
'alt' => ($profile->fullname) ?
$profile->fullname :
$profile->nickname));
$this->out->element('span', 'fn nickname', $profile->nickname);
$this->out->elementEnd('span');
$this->out->elementEnd('a');
$this->out->elementEnd('td');
if ($profile->value) {
$this->out->element('td', 'value', $profile->value);
}
$this->out->elementEnd('tr');
}
function title() function title()
{ {
return _('Top posters'); return _('Top posters');

View File

@ -393,7 +393,7 @@ border-radius:7px;
-webkit-border-radius:7px; -webkit-border-radius:7px;
width:377px; width:377px;
width:370px; width:370px;
height:86px; height:67px;
line-height:1.5; line-height:1.5;
padding:7px 7px 16px 7px; padding:7px 7px 16px 7px;
} }
@ -418,7 +418,7 @@ margin-left:4px;
#form_notice .form_note { #form_notice .form_note {
position:absolute; position:absolute;
top:118px; top:99px;
right:98px; right:98px;
z-index:9; z-index:9;
} }
@ -709,14 +709,15 @@ margin-right:11px;
.notice, .notice,
.profile { .profile {
position:relative; position:relative;
padding-top:18px; padding-top:11px;
padding-bottom:18px; padding-bottom:11px;
clear:both; clear:both;
float:left; float:left;
width:644px; width:644px;
width:96.699%; width:96.699%;
width:100%; width:100%;
border-top:1px dashed #D1D9E4; border-top-width:1px;
border-top-style:dashed;
/*-moz-border-radius:7px;*/ /*-moz-border-radius:7px;*/
} }
.notices li { .notices li {
@ -799,7 +800,7 @@ display:inline;
#laconicat .notice p.entry-content { #laconicat .notice p.entry-content {
/*margin-left:199px;*/ /*margin-left:199px;*/
} }
.notice p.entry-content a:visited { #content .notice p.entry-content a:visited {
border-radius:4px; border-radius:4px;
-moz-border-radius:4px; -moz-border-radius:4px;
-webkit-border-radius:4px; -webkit-border-radius:4px;
@ -811,35 +812,27 @@ border-radius:4px;
} }
.notice div.entry-content { .notice div.entry-content {
/*border:1px solid blue;*/
clear:left; clear:left;
float:left; float:left;
/*width:48%;*/
font-size:0.95em; font-size:0.95em;
margin-left:59px;
width:70%;
}
#showstream .notice div.entry-content {
margin-left:0;
} }
.notice div.entry-content a,
.notice .notice-options a,
.notice .notice-options input {
}
.notice .notice-options a, .notice .notice-options a,
.notice .notice-options input { .notice .notice-options input {
float:left; float:left;
font-size:1.025em; font-size:1.025em;
} }
#laconicat .notice div.entry-content {
/*margin-left:0;*/
}
.notice div.entry-content dl, .notice div.entry-content dl,
.notice div.entry-content dt, .notice div.entry-content dt,
.notice div.entry-content dd { .notice div.entry-content dd {
display:inline; display:inline;
} }
.notice div.entry-content .timestamp {
margin-left:59px;
}
.notice div.entry-content .timestamp dt, .notice div.entry-content .timestamp dt,
.notice div.entry-content .response dt { .notice div.entry-content .response dt {
@ -851,14 +844,6 @@ display:inline-block;
.notice div.entry-content .device dt { .notice div.entry-content .device dt {
text-transform:lowercase; text-transform:lowercase;
} }
.notice div.entry-content a {
}
.notice div.entry-content a:hover {
}
@ -1061,7 +1046,6 @@ background-color:#fff;
text-align:left; text-align:left;
text-transform:uppercase; text-transform:uppercase;
} }
#top_posters thead { #top_posters thead {
display:none; display:none;
} }
@ -1071,15 +1055,31 @@ width:199px;
#top_poster_number-of-notices { #top_poster_number-of-notices {
width:123px; width:123px;
} }
#top_posters tbody td {
.section tbody td {
padding-right:11px; padding-right:11px;
padding-bottom:4px; padding-bottom:11px;
} }
#top_posters img { .section .vcard .photo {
margin-right:7px; margin-right:7px;
margin-bottom:0; margin-bottom:0;
} }
.section .notice {
padding-top:11px;
padding-bottom:11px;
}
.section .notice:first-child {
padding-top:0;
border-top:0;
}
/* tagcloud */ /* tagcloud */
.tag-cloud { .tag-cloud {
list-style-type:none; list-style-type:none;

View File

@ -49,7 +49,17 @@ div.notice-options input,
color:#002E6E; color:#002E6E;
} }
.notice p.entry-content a:visited { .notice,
.profile {
border-top-color:#D1D9E4;
}
.section .notice,
.section .profile {
border-top-color:#97BFD1;
}
#content .notice p.entry-content a:visited {
background-color:#fcfcfc; background-color:#fcfcfc;
} }
.notice p.entry-content .vcard a { .notice p.entry-content .vcard a {
@ -216,7 +226,7 @@ background:transparent url(../images/icons/twotone/green/trash.gif) no-repeat 0
.notices div.entry-content, .notices div.entry-content,
.notices div.notice-options { .notices div.notice-options {
opacity:0.3; opacity:0.4;
} }
.notices li.hover div.entry-content, .notices li.hover div.entry-content,
.notices li.hover div.notice-options { .notices li.hover div.notice-options {