Merge branch 'testing' of git@gitorious.org:statusnet/mainline into testing

This commit is contained in:
Zach Copley 2010-02-05 02:08:37 +00:00
commit 8d320d7cc2
25 changed files with 263 additions and 45 deletions

View File

@ -145,7 +145,7 @@ class ApiGroupJoinAction extends ApiAuthAction
switch($this->format) { switch($this->format) {
case 'xml': case 'xml':
$this->show_single_xml_group($this->group); $this->showSingleXmlGroup($this->group);
break; break;
case 'json': case 'json':
$this->showSingleJsonGroup($this->group); $this->showSingleJsonGroup($this->group);

View File

@ -131,7 +131,7 @@ class ApiGroupLeaveAction extends ApiAuthAction
switch($this->format) { switch($this->format) {
case 'xml': case 'xml':
$this->show_single_xml_group($this->group); $this->showSingleXmlGroup($this->group);
break; break;
case 'json': case 'json':
$this->showSingleJsonGroup($this->group); $this->showSingleJsonGroup($this->group);

View File

@ -186,10 +186,13 @@ class FavoritedAction extends Action
function showContent() function showContent()
{ {
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
$cutoff = sprintf("fave.modified > '%s'",
common_sql_date(time() - common_config('popular', 'cutoff')));
$qry = 'SELECT notice.*, '. $qry = 'SELECT notice.*, '.
$weightexpr . ' as weight ' . $weightexpr . ' as weight ' .
'FROM notice JOIN fave ON notice.id = fave.notice_id ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
"WHERE $cutoff " .
'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' . 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
'ORDER BY weight DESC'; 'ORDER BY weight DESC';

View File

@ -106,7 +106,10 @@ class PublictagcloudAction extends Action
#Add the aggregated columns... #Add the aggregated columns...
$tags->selectAdd('max(notice_id) as last_notice_id'); $tags->selectAdd('max(notice_id) as last_notice_id');
$calc = common_sql_weight('created', common_config('tag', 'dropoff')); $calc = common_sql_weight('created', common_config('tag', 'dropoff'));
$cutoff = sprintf("notice_tag.created > '%s'",
common_sql_date(time() - common_config('tag', 'cutoff')));
$tags->selectAdd($calc . ' as weight'); $tags->selectAdd($calc . ' as weight');
$tags->addWhere($cutoff);
$tags->groupBy('tag'); $tags->groupBy('tag');
$tags->orderBy('weight DESC'); $tags->orderBy('weight DESC');

View File

@ -280,7 +280,7 @@ class RegisterAction extends Action
function nicknameExists($nickname) function nicknameExists($nickname)
{ {
$user = User::staticGet('nickname', $nickname); $user = User::staticGet('nickname', $nickname);
return ($user !== false); return is_object($user);
} }
/** /**
@ -300,7 +300,7 @@ class RegisterAction extends Action
return false; return false;
} }
$user = User::staticGet('email', $email); $user = User::staticGet('email', $email);
return ($user !== false); return is_object($user);
} }
// overrrided to add entry-title class // overrrided to add entry-title class

View File

@ -127,10 +127,10 @@ class UserauthorizationAction extends Action
$location = $params->getLocation(); $location = $params->getLocation();
$avatar = $params->getAvatarURL(); $avatar = $params->getAvatarURL();
$this->elementStart('div', array('class' => 'profile'));
$this->elementStart('div', 'entity_profile vcard'); $this->elementStart('div', 'entity_profile vcard');
$this->elementStart('a', array('href' => $profile, $this->elementStart('dl', 'entity_depiction');
'class' => 'url')); $this->element('dt', null, _('Photo'));
$this->elementStart('dd');
if ($avatar) { if ($avatar) {
$this->element('img', array('src' => $avatar, $this->element('img', array('src' => $avatar,
'class' => 'photo avatar', 'class' => 'photo avatar',
@ -138,11 +138,19 @@ class UserauthorizationAction extends Action
'height' => AVATAR_PROFILE_SIZE, 'height' => AVATAR_PROFILE_SIZE,
'alt' => $nickname)); 'alt' => $nickname));
} }
$this->elementEnd('dd');
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_nickname');
$this->element('dt', null, _('Nickname'));
$this->elementStart('dd');
$hasFN = ($fullname !== '') ? 'nickname' : 'fn nickname'; $hasFN = ($fullname !== '') ? 'nickname' : 'fn nickname';
$this->elementStart('span', $hasFN); $this->elementStart('a', array('href' => $profile,
'class' => 'url '.$hasFN));
$this->raw($nickname); $this->raw($nickname);
$this->elementEnd('span');
$this->elementEnd('a'); $this->elementEnd('a');
$this->elementEnd('dd');
$this->elementEnd('dl');
if (!is_null($fullname)) { if (!is_null($fullname)) {
$this->elementStart('dl', 'entity_fn'); $this->elementStart('dl', 'entity_fn');
@ -214,7 +222,6 @@ class UserauthorizationAction extends Action
$this->elementEnd('li'); $this->elementEnd('li');
$this->elementEnd('ul'); $this->elementEnd('ul');
$this->elementEnd('div'); $this->elementEnd('div');
$this->elementEnd('div');
} }
function sendAuthorization() function sendAuthorization()

View File

@ -32,6 +32,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
class Inbox extends Memcached_DataObject class Inbox extends Memcached_DataObject
{ {
const BOXCAR = 128; const BOXCAR = 128;
const MAX_NOTICES = 1024;
###START_AUTOCODE ###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */ /* the code below is auto generated do not remove the above tag */
@ -81,7 +82,7 @@ class Inbox extends Memcached_DataObject
$ni->selectAdd(); $ni->selectAdd();
$ni->selectAdd('notice_id'); $ni->selectAdd('notice_id');
$ni->orderBy('notice_id DESC'); $ni->orderBy('notice_id DESC');
$ni->limit(0, 1024); $ni->limit(0, self::MAX_NOTICES);
if ($ni->find()) { if ($ni->find()) {
while($ni->fetch()) { while($ni->fetch()) {
@ -115,9 +116,11 @@ class Inbox extends Memcached_DataObject
$result = $inbox->query(sprintf('UPDATE inbox '. $result = $inbox->query(sprintf('UPDATE inbox '.
'set notice_ids = concat(cast(0x%08x as binary(4)), '. 'set notice_ids = concat(cast(0x%08x as binary(4)), '.
'substr(notice_ids, 1, 4092)) '. 'substr(notice_ids, 1, %d)) '.
'WHERE user_id = %d', 'WHERE user_id = %d',
$notice_id, $user_id)); $notice_id,
4 * (self::MAX_NOTICES - 1),
$user_id));
if ($result) { if ($result) {
self::blow('inbox:user_id:%d', $user_id); self::blow('inbox:user_id:%d', $user_id);
@ -173,4 +176,57 @@ class Inbox extends Memcached_DataObject
return $ids; return $ids;
} }
/**
* Wrapper for Inbox::stream() and Notice::getStreamByIds() returning
* additional items up to the limit if we were short due to deleted
* notices still being listed in the inbox.
*
* The fast path (when no items are deleted) should be just as fast; the
* offset parameter is applied *before* lookups for maximum efficiency.
*
* This means offset-based paging may show duplicates, but similar behavior
* already exists when new notices are posted between page views, so we
* think people will be ok with this until id-based paging is introduced
* to the user interface.
*
* @param int $user_id
* @param int $offset skip past the most recent N notices (after since_id checks)
* @param int $limit
* @param mixed $since_id return only notices after but not including this id
* @param mixed $max_id return only notices up to and including this id
* @param mixed $since obsolete/ignored
* @param mixed $own ignored?
* @return array of Notice objects
*
* @todo consider repacking the inbox when this happens?
*/
function streamNotices($user_id, $offset, $limit, $since_id, $max_id, $since, $own=false)
{
$ids = self::stream($user_id, $offset, self::MAX_NOTICES, $since_id, $max_id, $since, $own);
// Do a bulk lookup for the first $limit items
// Fast path when nothing's deleted.
$firstChunk = array_slice($ids, 0, $limit);
$notices = Notice::getStreamByIds($firstChunk);
$wanted = count($firstChunk); // raw entry count in the inbox up to our $limit
if ($notices->N >= $wanted) {
return $notices;
}
// There were deleted notices, we'll need to look for more.
assert($notices instanceof ArrayWrapper);
$items = $notices->_items;
$remainder = array_slice($ids, $limit);
while (count($items) < $wanted && count($remainder) > 0) {
$notice = Notice::staticGet(array_shift($remainder));
if ($notice) {
$items[] = $notice;
} else {
}
}
return new ArrayWrapper($items);
}
} }

View File

@ -1468,4 +1468,25 @@ class Notice extends Memcached_DataObject
$handler->handle($this); $handler->handle($this);
} }
} }
function insert()
{
$result = parent::insert();
if ($result) {
// Profile::hasRepeated() abuses pkeyGet(), so we
// have to clear manually
if (!empty($this->repeat_of)) {
$c = self::memcache();
if (!empty($c)) {
$ck = self::multicacheKey('Notice',
array('profile_id' => $this->profile_id,
'repeat_of' => $this->repeat_of));
$c->delete($ck);
}
}
}
return $result;
}
} }

View File

@ -502,28 +502,22 @@ class User extends Memcached_DataObject
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{ {
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false); return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, false);
return Notice::getStreamByIds($ids);
} }
function noticeInbox($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) function noticeInbox($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{ {
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true); return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, true);
return Notice::getStreamByIds($ids);
} }
function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) function friendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{ {
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, false); return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, false);
return Notice::getStreamByIds($ids);
} }
function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) function ownFriendsTimeline($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null)
{ {
$ids = Inbox::stream($this->id, $offset, $limit, $since_id, $before_id, $since, true); return Inbox::streamNotices($this->id, $offset, $limit, $since_id, $before_id, $since, true);
return Notice::getStreamByIds($ids);
} }
function blowFavesCache() function blowFavesCache()

View File

@ -586,6 +586,7 @@ modified = 384
[user_group__keys] [user_group__keys]
id = N id = N
nickname = U
[user_openid] [user_openid]
canonical = 130 canonical = 130

View File

@ -144,9 +144,11 @@ $default =
'invite' => 'invite' =>
array('enabled' => true), array('enabled' => true),
'tag' => 'tag' =>
array('dropoff' => 864000.0), array('dropoff' => 864000.0, # controls weighting based on age
'cutoff' => 86400 * 90), # only look at notices posted in last 90 days
'popular' => 'popular' =>
array('dropoff' => 864000.0), array('dropoff' => 864000.0, # controls weighting based on age
'cutoff' => 86400 * 90), # only look at notices favorited in last 90 days
'daemon' => 'daemon' =>
array('piddir' => '/var/run', array('piddir' => '/var/run',
'user' => false, 'user' => false,

View File

@ -59,6 +59,7 @@ class GroupTagCloudSection extends TagCloudSection
function getTags() function getTags()
{ {
$weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
// @fixme should we use the cutoff too? Doesn't help with indexing per-group.
$names = $this->group->getAliases(); $names = $this->group->getAliases();

View File

@ -59,6 +59,7 @@ class PersonalTagCloudSection extends TagCloudSection
function getTags() function getTags()
{ {
$weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff')); $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
// @fixme should we use the cutoff too? Doesn't help with indexing per-user.
$qry = 'SELECT notice_tag.tag, '. $qry = 'SELECT notice_tag.tag, '.
$weightexpr . ' as weight ' . $weightexpr . ' as weight ' .

View File

@ -59,12 +59,15 @@ class PopularNoticeSection extends NoticeSection
} }
} }
$weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff')); $weightexpr = common_sql_weight('fave.modified', common_config('popular', 'dropoff'));
$cutoff = sprintf("fave.modified > '%s'",
common_sql_date(time() - common_config('popular', 'cutoff')));
$qry = "SELECT notice.*, $weightexpr as weight "; $qry = "SELECT notice.*, $weightexpr as weight ";
if(isset($tag)) { if(isset($tag)) {
$qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' . $qry .= 'FROM notice_tag, notice JOIN fave ON notice.id = fave.notice_id ' .
"WHERE notice.id = notice_tag.notice_id and '$tag' = notice_tag.tag"; "WHERE $cutoff and notice.id = notice_tag.notice_id and '$tag' = notice_tag.tag";
} else { } else {
$qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id'; $qry .= 'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
"WHERE $cutoff";
} }
$qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . $qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' .
'notice.rendered,notice.url,notice.created,notice.modified,' . 'notice.rendered,notice.url,notice.created,notice.modified,' .

View File

@ -240,6 +240,8 @@ class MobileProfilePlugin extends WAP20Plugin
return true; return true;
} }
$action->cssLink('css/display.css');
if (file_exists(Theme::file('css/mp-screen.css'))) { if (file_exists(Theme::file('css/mp-screen.css'))) {
$action->cssLink('css/mp-screen.css', null, 'screen'); $action->cssLink('css/mp-screen.css', null, 'screen');
} else { } else {
@ -256,6 +258,14 @@ class MobileProfilePlugin extends WAP20Plugin
} }
function onStartShowUAStyles($action) {
if (!$this->serveMobile) {
return true;
}
return false;
}
function onStartShowHeader($action) function onStartShowHeader($action)
{ {
if (!$this->serveMobile) { if (!$this->serveMobile) {

View File

@ -1,15 +1,12 @@
/** theme: mobile profile screen /** theme: mobile profile screen
* *
* @package StatusNet * @package StatusNet
* @author Sarven Capadisli <csarven@status.net> * @author Sarven Capadisli <csarven@status.net>
* @copyright 2009 StatusNet, Inc. * @copyright 2009 StatusNet, Inc.
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
* @link http://status.net/ * @link http://status.net/
*/ */
@import url(../../theme/base/css/display.css);
@import url(../../theme/identica/css/display.css);
#wrap { #wrap {
min-width:0; min-width:0;
max-width:100%; max-width:100%;

View File

@ -20,35 +20,35 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = "t:c:v:k:"; $shortoptions = "t:l:v:k:";
$helptext = <<<ENDOFHELP $helptext = <<<END_OF_CLEARCACHE_HELP
USAGE: clearcache.php <args> USAGE: clearcache.php <args>
clears the cached object based on the args clears the cached object based on the args
-t table Table to look up -t table Table to look up
-c column Column to look up, default "id" -l column Column to look up, default "id"
-v value Value to look up -v value Value to look up
-k key Key to look up; other args are ignored -k key Key to look up; other args are ignored
ENDOFHELP; END_OF_CLEARCACHE_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc'; require_once INSTALLDIR.'/scripts/commandline.inc';
$karg = get_option_value('k'); $karg = get_option_value('k', 'key');
if (!empty($karg)) { if (!empty($karg)) {
$k = common_cache_key($karg); $k = common_cache_key($karg);
} else { } else {
$table = get_option_value('t'); $table = get_option_value('t', 'table');
if (empty($table)) { if (empty($table)) {
die("No table or key specified\n"); die("No table or key specified\n");
} }
$column = get_option_value('c'); $column = get_option_value('l', 'column');
if (empty($column)) { if (empty($column)) {
$column = 'id'; $column = 'id';
} }
$value = get_option_value('v'); $value = get_option_value('v', 'value');
$k = Memcached_DataObject::cacheKey($table, $column, $value); $k = Memcached_DataObject::cacheKey($table, $column, $value);
} }

View File

@ -13,6 +13,11 @@ export sitename="$2"
export tags="$3" export tags="$3"
export email="$4" export email="$4"
export fullname="$5" export fullname="$5"
export siteplan="$6"
if [ "$siteplan" == '' ]; then
siteplan='single-user'
fi
# Fixme: if this is changed later we need to update profile URLs # Fixme: if this is changed later we need to update profile URLs
# for the created user. # for the created user.
@ -71,6 +76,7 @@ then
sed "s/\$nickname/$nickname/" | \ sed "s/\$nickname/$nickname/" | \
sed "s/\$sitename/$sitename/" | \ sed "s/\$sitename/$sitename/" | \
sed "s/\$userpass/$userpass/" | \ sed "s/\$userpass/$userpass/" | \
sed "s/\$siteplan/$siteplan/" | \
php $PHPBASE/scripts/sendemail.php \ php $PHPBASE/scripts/sendemail.php \
-s"$server" \ -s"$server" \
-n"$nickname" \ -n"$nickname" \

View File

@ -20,14 +20,14 @@
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = "t:c:v:k:"; $shortoptions = "t:l:v:k:";
$helptext = <<<ENDOFHELP $helptext = <<<ENDOFHELP
USAGE: showcache.php <args> USAGE: showcache.php <args>
shows the cached object based on the args shows the cached object based on the args
-t table Table to look up -t table Table to look up
-c column Column to look up, default "id" -l column Column to look up, default "id"
-v value Value to look up -v value Value to look up
-k key Key to look up; other args are ignored -k key Key to look up; other args are ignored
@ -44,7 +44,7 @@ if (!empty($karg)) {
if (empty($table)) { if (empty($table)) {
die("No table or key specified\n"); die("No table or key specified\n");
} }
$column = get_option_value('c'); $column = get_option_value('l');
if (empty($column)) { if (empty($column)) {
$column = 'id'; $column = 'id';
} }

View File

@ -0,0 +1,99 @@
#!/usr/bin/env php
<?php
/*
* StatusNet - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'i:n:a';
$longoptions = array('id=', 'nickname=', 'all');
$helptext = <<<END_OF_UPDATEPROFILEURL_HELP
updateprofileurl.php [options]
update the URLs of all avatars in the system
-i --id ID of user to update
-n --nickname nickname of the user to update
-a --all update all
END_OF_UPDATEPROFILEURL_HELP;
require_once INSTALLDIR.'/scripts/commandline.inc';
try {
$user = null;
if (have_option('i', 'id')) {
$id = get_option_value('i', 'id');
$user = User::staticGet('id', $id);
if (empty($user)) {
throw new Exception("Can't find user with id '$id'.");
}
updateProfileURL($user);
} else if (have_option('n', 'nickname')) {
$nickname = get_option_value('n', 'nickname');
$user = User::staticGet('nickname', $nickname);
if (empty($user)) {
throw new Exception("Can't find user with nickname '$nickname'");
}
updateProfileURL($user);
} else if (have_option('a', 'all')) {
$user = new User();
if ($user->find()) {
while ($user->fetch()) {
updateProfileURL($user);
}
}
} else {
show_help();
exit(1);
}
} catch (Exception $e) {
print $e->getMessage()."\n";
exit(1);
}
function updateProfileURL($user)
{
$profile = $user->getProfile();
if (empty($profile)) {
throw new Exception("Can't find profile for user $user->nickname ($user->id)");
}
$orig = clone($profile);
$profile->profileurl = common_profile_url($user->nickname);
if (!have_option('q', 'quiet')) {
print "Updating profile url for $user->nickname ($user->id) ".
"from $orig->profileurl to $profile->profileurl...";
}
$result = $profile->update($orig);
if (!$result) {
print "FAIL.\n";
common_log_db_error($profile, 'UPDATE', __FILE__);
throw new Exception("Can't update profile for user $user->nickname ($user->id)");
}
common_broadcast_profile($profile);
print "OK.\n";
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 B

View File

@ -192,7 +192,8 @@ button.minimize,
.form_reset_key input.submit, .form_reset_key input.submit,
.entity_clear input.submit, .entity_clear input.submit,
.entity_flag input.submit, .entity_flag input.submit,
.entity_flag p { .entity_flag p,
.entity_subscribe input.submit {
background-image:url(../../base/images/icons/icons-01.gif); background-image:url(../../base/images/icons/icons-01.gif);
background-repeat:no-repeat; background-repeat:no-repeat;
background-color:transparent; background-color:transparent;
@ -348,6 +349,12 @@ background-position: 5px -2039px;
.entity_flag p { .entity_flag p {
background-position: 5px -2105px; background-position: 5px -2105px;
} }
.entity_subscribe input.accept {
background-position: 5px -2171px;
}
.entity_subscribe input.reject {
background-position: 5px -2237px;
}
/* NOTICES */ /* NOTICES */
.notice .attachment { .notice .attachment {

View File

@ -192,7 +192,8 @@ button.minimize,
.form_reset_key input.submit, .form_reset_key input.submit,
.entity_clear input.submit, .entity_clear input.submit,
.entity_flag input.submit, .entity_flag input.submit,
.entity_flag p { .entity_flag p,
.entity_subscribe input.submit {
background-image:url(../../base/images/icons/icons-01.gif); background-image:url(../../base/images/icons/icons-01.gif);
background-repeat:no-repeat; background-repeat:no-repeat;
background-color:transparent; background-color:transparent;
@ -347,6 +348,12 @@ background-position: 5px -2039px;
.entity_flag p { .entity_flag p {
background-position: 5px -2105px; background-position: 5px -2105px;
} }
.entity_subscribe input.accept {
background-position: 5px -2171px;
}
.entity_subscribe input.reject {
background-position: 5px -2237px;
}
/* NOTICES */ /* NOTICES */
.notice .attachment { .notice .attachment {