Merge branch '0.9.x' into 1.0.x
This commit is contained in:
commit
5224c7d6c2
@ -115,11 +115,11 @@ class ApiAccountUpdateProfileAction extends ApiAuthAction
|
||||
|
||||
$original = clone($profile);
|
||||
|
||||
if (empty($this->name)) {
|
||||
if (!empty($this->name)) {
|
||||
$profile->fullname = $this->name;
|
||||
}
|
||||
|
||||
if (empty($this->url)) {
|
||||
if (!empty($this->url)) {
|
||||
$profile->homepage = $this->url;
|
||||
}
|
||||
|
||||
|
@ -112,7 +112,7 @@ class ApiStatusesRetweetAction extends ApiAuthAction
|
||||
|
||||
$repeat = $this->original->repeat($this->user->id, $this->source);
|
||||
|
||||
common_broadcast_notice($repeat);
|
||||
|
||||
|
||||
$this->showNotice($repeat);
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ class ApiStatusesUpdateAction extends ApiAuthAction
|
||||
$upload->attachToNotice($this->notice);
|
||||
}
|
||||
|
||||
common_broadcast_notice($this->notice);
|
||||
|
||||
}
|
||||
|
||||
$this->showNotice();
|
||||
|
@ -201,7 +201,7 @@ class NewnoticeAction extends Action
|
||||
$upload->attachToNotice($notice);
|
||||
}
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
header('Content-Type: text/xml;charset=utf-8');
|
||||
|
@ -106,7 +106,7 @@ class RepeatAction extends Action
|
||||
{
|
||||
$repeat = $this->notice->repeat($this->user->id, 'web');
|
||||
|
||||
common_broadcast_notice($repeat);
|
||||
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
|
@ -120,11 +120,7 @@ class Inbox extends Memcached_DataObject
|
||||
$notice_id, $user_id));
|
||||
|
||||
if ($result) {
|
||||
$c = self::memcache();
|
||||
|
||||
if (!empty($c)) {
|
||||
$c->delete(self::cacheKey('inbox', 'user_id', $user_id));
|
||||
}
|
||||
self::blow('inbox:user_id:%d', $user_id);
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -458,4 +458,23 @@ class Memcached_DataObject extends DB_DataObject
|
||||
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
static function blow()
|
||||
{
|
||||
$c = self::memcache();
|
||||
|
||||
if (empty($c)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$args = func_get_args();
|
||||
|
||||
$format = array_shift($args);
|
||||
|
||||
$keyPart = vsprintf($format, $args);
|
||||
|
||||
$cacheKey = common_cache_key($keyPart);
|
||||
|
||||
return $c->delete($cacheKey);
|
||||
}
|
||||
}
|
||||
|
@ -94,10 +94,6 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
function delete()
|
||||
{
|
||||
$this->blowCaches(true);
|
||||
$this->blowFavesCache(true);
|
||||
$this->blowSubsCache(true);
|
||||
|
||||
// For auditing purposes, save a record that the notice
|
||||
// was deleted.
|
||||
|
||||
@ -109,31 +105,20 @@ class Notice extends Memcached_DataObject
|
||||
$deleted->created = $this->created;
|
||||
$deleted->deleted = common_sql_now();
|
||||
|
||||
$this->query('BEGIN');
|
||||
|
||||
$deleted->insert();
|
||||
|
||||
//Null any notices that are replies to this notice
|
||||
$this->query(sprintf("UPDATE notice set reply_to = null WHERE reply_to = %d", $this->id));
|
||||
// Clear related records
|
||||
|
||||
//Null any notices that are repeats of this notice
|
||||
//XXX: probably need to uncache these, too
|
||||
$this->clearReplies();
|
||||
$this->clearRepeats();
|
||||
$this->clearFaves();
|
||||
$this->clearTags();
|
||||
$this->clearGroupInboxes();
|
||||
|
||||
$this->query(sprintf("UPDATE notice set repeat_of = null WHERE repeat_of = %d", $this->id));
|
||||
// NOTE: we don't clear inboxes
|
||||
// NOTE: we don't clear queue items
|
||||
|
||||
$related = array('Reply',
|
||||
'Fave',
|
||||
'Notice_tag',
|
||||
'Group_inbox',
|
||||
'Queue_item');
|
||||
|
||||
foreach ($related as $cls) {
|
||||
$inst = new $cls();
|
||||
$inst->notice_id = $this->id;
|
||||
$inst->delete();
|
||||
}
|
||||
$result = parent::delete();
|
||||
$this->query('COMMIT');
|
||||
}
|
||||
|
||||
function saveTags()
|
||||
@ -155,6 +140,7 @@ class Notice extends Memcached_DataObject
|
||||
foreach(array_unique($hashtags) as $hashtag) {
|
||||
/* elide characters we don't want in the tag */
|
||||
$this->saveTag($hashtag);
|
||||
self::blow('profile:notice_ids_tagged:%d:%s', $this->profile_id, $tag->tag);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -172,6 +158,9 @@ class Notice extends Memcached_DataObject
|
||||
$last_error->message));
|
||||
return;
|
||||
}
|
||||
|
||||
// if it's saved, blow its cache
|
||||
$tag->blowCache(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -331,29 +320,45 @@ class Notice extends Memcached_DataObject
|
||||
}
|
||||
}
|
||||
|
||||
// XXX: do we need to change this for remote users?
|
||||
|
||||
$notice->saveTags();
|
||||
|
||||
$groups = $notice->saveGroups();
|
||||
|
||||
$recipients = $notice->saveReplies();
|
||||
|
||||
$notice->addToInboxes($groups, $recipients);
|
||||
|
||||
$notice->saveUrls();
|
||||
|
||||
Event::handle('EndNoticeSave', array($notice));
|
||||
}
|
||||
|
||||
# Clear the cache for subscribed users, so they'll update at next request
|
||||
# XXX: someone clever could prepend instead of clearing the cache
|
||||
$notice->blowOnInsert();
|
||||
|
||||
$notice->blowCaches();
|
||||
$qm = QueueManager::get();
|
||||
|
||||
$qm->enqueue($notice, 'distrib');
|
||||
|
||||
return $notice;
|
||||
}
|
||||
|
||||
function blowOnInsert()
|
||||
{
|
||||
self::blow('profile:notice_ids:%d', $this->profile_id);
|
||||
self::blow('public');
|
||||
|
||||
if ($this->conversation != $this->id) {
|
||||
self::blow('notice:conversation_ids:%d', $this->conversation);
|
||||
}
|
||||
|
||||
if (!empty($this->repeat_of)) {
|
||||
self::blow('notice:repeats:%d', $this->repeat_of);
|
||||
}
|
||||
|
||||
$original = Notice::staticGet('id', $this->repeat_of);
|
||||
|
||||
if (!empty($original)) {
|
||||
$originalUser = User::staticGet('id', $original->profile_id);
|
||||
if (!empty($originalUser)) {
|
||||
self::blow('user:repeats_of_me:%d', $originalUser->id);
|
||||
}
|
||||
}
|
||||
|
||||
$profile = Profile::staticGet($this->profile_id);
|
||||
$profile->blowNoticeCount();
|
||||
}
|
||||
|
||||
/** save all urls in the notice to the db
|
||||
*
|
||||
* follow redirects and save all available file information
|
||||
@ -456,227 +461,6 @@ class Notice extends Memcached_DataObject
|
||||
return $att;
|
||||
}
|
||||
|
||||
function blowCaches($blowLast=false)
|
||||
{
|
||||
$this->blowSubsCache($blowLast);
|
||||
$this->blowNoticeCache($blowLast);
|
||||
$this->blowRepliesCache($blowLast);
|
||||
$this->blowPublicCache($blowLast);
|
||||
$this->blowTagCache($blowLast);
|
||||
$this->blowGroupCache($blowLast);
|
||||
$this->blowConversationCache($blowLast);
|
||||
$this->blowRepeatCache();
|
||||
$profile = Profile::staticGet($this->profile_id);
|
||||
$profile->blowNoticeCount();
|
||||
}
|
||||
|
||||
function blowRepeatCache()
|
||||
{
|
||||
if (!empty($this->repeat_of)) {
|
||||
$cache = common_memcache();
|
||||
if (!empty($cache)) {
|
||||
// XXX: only blow if <100 in cache
|
||||
$ck = common_cache_key('notice:repeats:'.$this->repeat_of);
|
||||
$result = $cache->delete($ck);
|
||||
|
||||
$user = User::staticGet('id', $this->profile_id);
|
||||
|
||||
if (!empty($user)) {
|
||||
$uk = common_cache_key('user:repeated_by_me:'.$user->id);
|
||||
$cache->delete($uk);
|
||||
$user->free();
|
||||
unset($user);
|
||||
}
|
||||
|
||||
$original = Notice::staticGet('id', $this->repeat_of);
|
||||
|
||||
if (!empty($original)) {
|
||||
$originalUser = User::staticGet('id', $original->profile_id);
|
||||
if (!empty($originalUser)) {
|
||||
$ouk = common_cache_key('user:repeats_of_me:'.$originalUser->id);
|
||||
$cache->delete($ouk);
|
||||
$originalUser->free();
|
||||
unset($originalUser);
|
||||
}
|
||||
$original->free();
|
||||
unset($original);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function blowConversationCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$ck = common_cache_key('notice:conversation_ids:'.$this->conversation);
|
||||
$cache->delete($ck);
|
||||
if ($blowLast) {
|
||||
$cache->delete($ck.';last');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function blowGroupCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$group_inbox = new Group_inbox();
|
||||
$group_inbox->notice_id = $this->id;
|
||||
if ($group_inbox->find()) {
|
||||
while ($group_inbox->fetch()) {
|
||||
$cache->delete(common_cache_key('user_group:notice_ids:' . $group_inbox->group_id));
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('user_group:notice_ids:' . $group_inbox->group_id.';last'));
|
||||
}
|
||||
$member = new Group_member();
|
||||
$member->group_id = $group_inbox->group_id;
|
||||
if ($member->find()) {
|
||||
while ($member->fetch()) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id));
|
||||
}
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:' . $member->profile_id . ';last'));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:' . $member->profile_id . ';last'));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:' . $member->profile_id . ';last'));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:' . $member->profile_id . ';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$group_inbox->free();
|
||||
unset($group_inbox);
|
||||
}
|
||||
}
|
||||
|
||||
function blowTagCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$tag = new Notice_tag();
|
||||
$tag->notice_id = $this->id;
|
||||
if ($tag->find()) {
|
||||
while ($tag->fetch()) {
|
||||
$tag->blowCache($blowLast);
|
||||
$ck = 'profile:notice_ids_tagged:' . $this->profile_id . ':' . $tag->tag;
|
||||
|
||||
$cache->delete($ck);
|
||||
if ($blowLast) {
|
||||
$cache->delete($ck . ';last');
|
||||
}
|
||||
}
|
||||
}
|
||||
$tag->free();
|
||||
unset($tag);
|
||||
}
|
||||
}
|
||||
|
||||
function blowSubsCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$user = new User();
|
||||
|
||||
$UT = common_config('db','type')=='pgsql'?'"user"':'user';
|
||||
$user->query('SELECT id ' .
|
||||
|
||||
"FROM $UT JOIN subscription ON $UT.id = subscription.subscriber " .
|
||||
'WHERE subscription.subscribed = ' . $this->profile_id);
|
||||
|
||||
while ($user->fetch()) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:'.$user->id));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id));
|
||||
}
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user:'.$user->id.';last'));
|
||||
$cache->delete(common_cache_key('notice_inbox:by_user_own:'.$user->id.';last'));
|
||||
if (empty($this->repeat_of)) {
|
||||
$cache->delete(common_cache_key('user:friends_timeline:'.$user->id.';last'));
|
||||
$cache->delete(common_cache_key('user:friends_timeline_own:'.$user->id.';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$user->free();
|
||||
unset($user);
|
||||
}
|
||||
}
|
||||
|
||||
function blowNoticeCache($blowLast=false)
|
||||
{
|
||||
if ($this->is_local) {
|
||||
$cache = common_memcache();
|
||||
if (!empty($cache)) {
|
||||
$cache->delete(common_cache_key('profile:notice_ids:'.$this->profile_id));
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('profile:notice_ids:'.$this->profile_id.';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function blowRepliesCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$reply = new Reply();
|
||||
$reply->notice_id = $this->id;
|
||||
if ($reply->find()) {
|
||||
while ($reply->fetch()) {
|
||||
$cache->delete(common_cache_key('reply:stream:'.$reply->profile_id));
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('reply:stream:'.$reply->profile_id.';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$reply->free();
|
||||
unset($reply);
|
||||
}
|
||||
}
|
||||
|
||||
function blowPublicCache($blowLast=false)
|
||||
{
|
||||
if ($this->is_local == Notice::LOCAL_PUBLIC) {
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$cache->delete(common_cache_key('public'));
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('public').';last');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function blowFavesCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$fave = new Fave();
|
||||
$fave->notice_id = $this->id;
|
||||
if ($fave->find()) {
|
||||
while ($fave->fetch()) {
|
||||
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id));
|
||||
$cache->delete(common_cache_key('fave:by_user_own:'.$fave->user_id));
|
||||
if ($blowLast) {
|
||||
$cache->delete(common_cache_key('fave:ids_by_user:'.$fave->user_id.';last'));
|
||||
$cache->delete(common_cache_key('fave:by_user_own:'.$fave->user_id.';last'));
|
||||
}
|
||||
}
|
||||
}
|
||||
$fave->free();
|
||||
unset($fave);
|
||||
}
|
||||
}
|
||||
|
||||
function getStreamByIds($ids)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
@ -999,7 +783,14 @@ class Notice extends Memcached_DataObject
|
||||
$gi->notice_id = $this->id;
|
||||
$gi->created = $this->created;
|
||||
|
||||
return $gi->insert();
|
||||
$result = $gi->insert();
|
||||
|
||||
if (!result) {
|
||||
common_log_db_error($gi, 'INSERT', __FILE__);
|
||||
throw new ServerException(_('Problem saving group inbox.'));
|
||||
}
|
||||
|
||||
self::blow('user_group:notice_ids:%d', $gi->group_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -1094,7 +885,8 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
foreach ($recipientIds as $recipientId) {
|
||||
$user = User::staticGet('id', $recipientId);
|
||||
if ($user) {
|
||||
if (!empty($user)) {
|
||||
self::blow('reply:stream:%d', $reply->profile_id);
|
||||
mail_notify_attn($user, $this);
|
||||
}
|
||||
}
|
||||
@ -1553,4 +1345,104 @@ class Notice extends Memcached_DataObject
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
function clearReplies()
|
||||
{
|
||||
$replyNotice = new Notice();
|
||||
$replyNotice->reply_to = $this->id;
|
||||
|
||||
//Null any notices that are replies to this notice
|
||||
|
||||
if ($replyNotice->find()) {
|
||||
while ($replyNotice->fetch()) {
|
||||
$orig = clone($replyNotice);
|
||||
$replyNotice->reply_to = null;
|
||||
$replyNotice->update($orig);
|
||||
}
|
||||
}
|
||||
|
||||
// Reply records
|
||||
|
||||
$reply = new Reply();
|
||||
$reply->notice_id = $this->id;
|
||||
|
||||
if ($reply->find()) {
|
||||
while($reply->fetch()) {
|
||||
self::blow('reply:stream:%d', $reply->profile_id);
|
||||
$reply->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$reply->free();
|
||||
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function clearRepeats()
|
||||
{
|
||||
$repeatNotice = new Notice();
|
||||
$repeatNotice->repeat_of = $this->id;
|
||||
|
||||
//Null any notices that are repeats of this notice
|
||||
|
||||
if ($repeatNotice->find()) {
|
||||
while ($repeatNotice->fetch()) {
|
||||
$orig = clone($repeatNotice);
|
||||
$repeatNotice->repeat_of = null;
|
||||
$repeatNotice->update($orig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearFaves()
|
||||
{
|
||||
$fave = new Fave();
|
||||
$fave->notice_id = $this->id;
|
||||
|
||||
if ($fave->find()) {
|
||||
while ($fave->fetch()) {
|
||||
self::blow('fave:ids_by_user_own:%d', $fave->user_id);
|
||||
self::blow('fave:ids_by_user_own:%d;last', $fave->user_id);
|
||||
self::blow('fave:ids_by_user:%d', $fave->user_id);
|
||||
self::blow('fave:ids_by_user:%d;last', $fave->user_id);
|
||||
$fave->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$fave->free();
|
||||
}
|
||||
|
||||
function clearTags()
|
||||
{
|
||||
$tag = new Notice_tag();
|
||||
$tag->notice_id = $this->id;
|
||||
|
||||
if ($tag->find()) {
|
||||
while ($tag->fetch()) {
|
||||
self::blow('profile:notice_ids_tagged:%d:%s', $this->profile_id, common_keyize($tag->tag));
|
||||
self::blow('profile:notice_ids_tagged:%d:%s;last', $this->profile_id, common_keyize($tag->tag));
|
||||
self::blow('notice_tag:notice_ids:%s', common_keyize($tag->tag));
|
||||
self::blow('notice_tag:notice_ids:%s;last', common_keyize($tag->tag));
|
||||
$tag->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$tag->free();
|
||||
}
|
||||
|
||||
function clearGroupInboxes()
|
||||
{
|
||||
$gi = new Group_inbox();
|
||||
|
||||
$gi->notice_id = $this->id;
|
||||
|
||||
if ($gi->find()) {
|
||||
while ($gi->fetch()) {
|
||||
self::blow('user_group:notice_ids:%d', $gi->group_id);
|
||||
$gi->delete();
|
||||
}
|
||||
}
|
||||
|
||||
$gi->free();
|
||||
}
|
||||
}
|
||||
|
@ -86,13 +86,9 @@ class Notice_tag extends Memcached_DataObject
|
||||
|
||||
function blowCache($blowLast=false)
|
||||
{
|
||||
$cache = common_memcache();
|
||||
if ($cache) {
|
||||
$idkey = common_cache_key('notice_tag:notice_ids:' . common_keyize($this->tag));
|
||||
$cache->delete($idkey);
|
||||
if ($blowLast) {
|
||||
$cache->delete($idkey.';last');
|
||||
}
|
||||
self::blow('notice_tag:notice_ids:%s', common_keyize($this->tag));
|
||||
if ($blowLast) {
|
||||
self::blow('notice_tag:notice_ids:%s;last', common_keyize($this->tag));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ class Status_network extends DB_DataObject
|
||||
|
||||
static $cache = null;
|
||||
static $base = null;
|
||||
static $wildcard = null;
|
||||
|
||||
/**
|
||||
* @param string $dbhost
|
||||
@ -187,7 +188,12 @@ class Status_network extends DB_DataObject
|
||||
|
||||
$config['db']['database'] = "mysqli://$dbuser:$dbpass@$dbhost/$dbname";
|
||||
|
||||
$config['site']['name'] = $sn->sitename;
|
||||
$config['site']['name'] = $sn->sitename;
|
||||
$config['site']['nickname'] = $sn->nickname;
|
||||
|
||||
self::$wildcard = $wildcard;
|
||||
|
||||
$config['site']['wildcard'] =& self::$wildcard;
|
||||
|
||||
if (!empty($sn->hostname)) {
|
||||
$config['site']['server'] = $sn->hostname;
|
||||
@ -230,4 +236,13 @@ class Status_network extends DB_DataObject
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
function getServerName()
|
||||
{
|
||||
if (!empty($this->hostname)) {
|
||||
return $this->hostname;
|
||||
} else {
|
||||
return $this->nickname . '.' . self::$wildcard;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ class User extends Memcached_DataObject
|
||||
common_config('site', 'name'),
|
||||
$user->nickname),
|
||||
'system');
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
12
js/util.js
12
js/util.js
@ -495,7 +495,7 @@ var SN = { // StatusNet
|
||||
$('#'+SN.C.S.NoticeLocationId).val('');
|
||||
$('#'+SN.C.S.NoticeDataGeo).attr('checked', false);
|
||||
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, 'disabled');
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, 'disabled', { path: '/', expires: SN.U.GetFullYear(2029, 0, 1) });
|
||||
}
|
||||
|
||||
function getJSONgeocodeURL(geocodeURL, data) {
|
||||
@ -537,7 +537,8 @@ var SN = { // StatusNet
|
||||
NLNU: location.url,
|
||||
NDG: true
|
||||
};
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, JSON.stringify(cookieValue));
|
||||
|
||||
$.cookie(SN.C.S.NoticeDataGeoCookie, JSON.stringify(cookieValue), { path: '/', expires: SN.U.GetFullYear(2029, 0, 1) });
|
||||
});
|
||||
}
|
||||
|
||||
@ -658,6 +659,13 @@ var SN = { // StatusNet
|
||||
}
|
||||
return false;
|
||||
});
|
||||
},
|
||||
|
||||
GetFullYear: function(year, month, day) {
|
||||
var date = new Date();
|
||||
date.setFullYear(year, month, day);
|
||||
|
||||
return date;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -422,7 +422,7 @@ class RepeatCommand extends Command
|
||||
$repeat = $notice->repeat($this->user->id, $channel->source);
|
||||
|
||||
if ($repeat) {
|
||||
common_broadcast_notice($repeat);
|
||||
|
||||
$channel->output($this->user, sprintf(_('Notice from %s repeated'), $recipient->nickname));
|
||||
} else {
|
||||
$channel->error($this->user, _('Error repeating notice.'));
|
||||
@ -492,7 +492,7 @@ class ReplyCommand extends Command
|
||||
} else {
|
||||
$channel->error($this->user, _('Error saving notice.'));
|
||||
}
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
$default =
|
||||
array('site' =>
|
||||
array('name' => 'Just another StatusNet microblog',
|
||||
'nickname' => 'statusnet',
|
||||
'wildcard' => null,
|
||||
'server' => $_server,
|
||||
'theme' => 'default',
|
||||
'path' => $_path,
|
||||
|
84
lib/distribqueuehandler.php
Normal file
84
lib/distribqueuehandler.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/*
|
||||
* StatusNet - the 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/>.
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
||||
|
||||
/**
|
||||
* Base class for queue handlers.
|
||||
*
|
||||
* As extensions of the Daemon class, each queue handler has the ability
|
||||
* to launch itself in the background, at which point it'll pass control
|
||||
* to the configured QueueManager class to poll for updates.
|
||||
*
|
||||
* Subclasses must override at least the following methods:
|
||||
* - transport
|
||||
* - handle_notice
|
||||
*/
|
||||
|
||||
class DistribQueueHandler
|
||||
{
|
||||
/**
|
||||
* Return transport keyword which identifies items this queue handler
|
||||
* services; must be defined for all subclasses.
|
||||
*
|
||||
* Must be 8 characters or less to fit in the queue_item database.
|
||||
* ex "email", "jabber", "sms", "irc", ...
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
function transport()
|
||||
{
|
||||
return 'distrib';
|
||||
}
|
||||
|
||||
/**
|
||||
* Here's the meat of your queue handler -- you're handed a Notice
|
||||
* object, which you may do as you will with.
|
||||
*
|
||||
* If this function indicates failure, a warning will be logged
|
||||
* and the item is placed back in the queue to be re-run.
|
||||
*
|
||||
* @param Notice $notice
|
||||
* @return boolean true on success, false on failure
|
||||
*/
|
||||
function handle($notice)
|
||||
{
|
||||
// XXX: do we need to change this for remote users?
|
||||
|
||||
$notice->saveTags();
|
||||
|
||||
$groups = $notice->saveGroups();
|
||||
|
||||
$recipients = $notice->saveReplies();
|
||||
|
||||
$notice->addToInboxes($groups, $recipients);
|
||||
|
||||
$notice->saveUrls();
|
||||
|
||||
Event::handle('EndNoticeSave', array($notice));
|
||||
|
||||
// Enqueue for other handlers
|
||||
|
||||
common_enqueue_notice($notice);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ abstract class IoMaster
|
||||
$sn = new Status_network();
|
||||
$sn->find();
|
||||
while ($sn->fetch()) {
|
||||
$hosts[] = $sn->hostname;
|
||||
$hosts[] = $sn->getServerName();
|
||||
}
|
||||
return $hosts;
|
||||
}
|
||||
@ -102,7 +102,7 @@ abstract class IoMaster
|
||||
*/
|
||||
protected function instantiate($class)
|
||||
{
|
||||
if (isset($this->singletons[$class])) {
|
||||
if (is_string($class) && isset($this->singletons[$class])) {
|
||||
// Already instantiated a multi-site-capable handler.
|
||||
// Just let it know it should listen to this site too!
|
||||
$this->singletons[$class]->addSite(common_config('site', 'server'));
|
||||
@ -129,7 +129,11 @@ abstract class IoMaster
|
||||
|
||||
protected function getManager($class)
|
||||
{
|
||||
return call_user_func(array($class, 'get'));
|
||||
if(is_object($class)){
|
||||
return $class;
|
||||
} else {
|
||||
return call_user_func(array($class, 'get'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -347,7 +351,7 @@ abstract class IoMaster
|
||||
* for per-queue and per-site records.
|
||||
*
|
||||
* @param string $key counter name
|
||||
* @param array $owners list of owner keys like 'queue:jabber' or 'site:stat01'
|
||||
* @param array $owners list of owner keys like 'queue:xmpp' or 'site:stat01'
|
||||
*/
|
||||
public function stats($key, $owners=array())
|
||||
{
|
||||
|
@ -160,7 +160,7 @@ class MailHandler
|
||||
foreach($mediafiles as $mf){
|
||||
$mf->attachToNotice($notice);
|
||||
}
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
$this->log(LOG_INFO,
|
||||
'Added notice ' . $notice->id . ' from user ' . $user->nickname);
|
||||
return true;
|
||||
|
@ -362,7 +362,7 @@ class StatusNetOAuthDataStore extends OAuthDataStore
|
||||
array('is_local' => Notice::REMOTE_OMB,
|
||||
'uri' => $omb_notice->getIdentifierURI()));
|
||||
|
||||
common_broadcast_notice($notice, true);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +170,9 @@ abstract class QueueManager extends IoManager
|
||||
{
|
||||
if (isset($this->handlers[$queue])) {
|
||||
$class = $this->handlers[$queue];
|
||||
if (class_exists($class)) {
|
||||
if(is_object($class)) {
|
||||
return $class;
|
||||
} else if (class_exists($class)) {
|
||||
return new $class();
|
||||
} else {
|
||||
common_log(LOG_ERR, "Nonexistent handler class '$class' for queue '$queue'");
|
||||
@ -206,6 +208,7 @@ abstract class QueueManager extends IoManager
|
||||
$this->connect('plugin', 'PluginQueueHandler');
|
||||
$this->connect('omb', 'OmbQueueHandler');
|
||||
$this->connect('ping', 'PingQueueHandler');
|
||||
$this->connect('distrib', 'DistribQueueHandler');
|
||||
if (common_config('sms', 'enabled')) {
|
||||
$this->connect('sms', 'SmsQueueHandler');
|
||||
}
|
||||
@ -213,7 +216,7 @@ abstract class QueueManager extends IoManager
|
||||
// XMPP output handlers...
|
||||
$this->connect('jabber', 'JabberQueueHandler');
|
||||
$this->connect('public', 'PublicQueueHandler');
|
||||
|
||||
|
||||
// @fixme this should get an actual queue
|
||||
//$this->connect('confirm', 'XmppConfirmHandler');
|
||||
|
||||
@ -231,7 +234,7 @@ abstract class QueueManager extends IoManager
|
||||
* Only registered transports will be reliably picked up!
|
||||
*
|
||||
* @param string $transport
|
||||
* @param string $class
|
||||
* @param string $class class name or object instance
|
||||
* @param string $group
|
||||
*/
|
||||
public function connect($transport, $class, $group='queuedaemon')
|
||||
|
@ -294,7 +294,26 @@ class StompQueueManager extends QueueManager
|
||||
StatusNet::init($site);
|
||||
}
|
||||
|
||||
$item = $this->decode($frame->body);
|
||||
if (is_numeric($frame->body)) {
|
||||
$id = intval($frame->body);
|
||||
$info = "notice $id posted at {$frame->headers['created']} in queue $queue";
|
||||
|
||||
$notice = Notice::staticGet('id', $id);
|
||||
if (empty($notice)) {
|
||||
$this->_log(LOG_WARNING, "Skipping missing $info");
|
||||
$this->ack($frame);
|
||||
$this->commit();
|
||||
$this->begin();
|
||||
$this->stats('badnotice', $queue);
|
||||
return false;
|
||||
}
|
||||
|
||||
$item = $notice;
|
||||
} else {
|
||||
// @fixme should we serialize, or json, or what here?
|
||||
$info = "string posted at {$frame->headers['created']} in queue $queue";
|
||||
$item = $frame->body;
|
||||
}
|
||||
|
||||
$handler = $this->getHandler($queue);
|
||||
if (!$handler) {
|
||||
|
@ -980,7 +980,7 @@ function common_redirect($url, $code=307)
|
||||
|
||||
function common_broadcast_notice($notice, $remote=false)
|
||||
{
|
||||
return common_enqueue_notice($notice);
|
||||
// DO NOTHING!
|
||||
}
|
||||
|
||||
// Stick the notice on the queue
|
||||
|
@ -101,7 +101,7 @@ class XmppManager extends IoManager
|
||||
$this->conn->addEventHandler('reconnect', 'handle_reconnect', $this);
|
||||
|
||||
$this->conn->setReconnectTimeout(600);
|
||||
jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', -1);
|
||||
jabber_send_presence("Send me a message to post a notice", 'available', null, 'available', 100);
|
||||
|
||||
return !is_null($this->conn);
|
||||
}
|
||||
@ -233,7 +233,7 @@ class XmppManager extends IoManager
|
||||
common_log(LOG_NOTICE, 'XMPP reconnected');
|
||||
|
||||
$this->conn->processUntil('session_start');
|
||||
$this->conn->presence(null, 'available', null, 'available', -1);
|
||||
$this->conn->presence(null, 'available', null, 'available', 100);
|
||||
}
|
||||
|
||||
|
||||
|
@ -397,7 +397,7 @@ class FacebookAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ class ImapPlugin extends Plugin
|
||||
}
|
||||
}
|
||||
|
||||
function onStartIoManagerClasses(&$classes)
|
||||
function onStartQueueDaemonIoManagers(&$classes)
|
||||
{
|
||||
$classes[] = new ImapManager($this);
|
||||
}
|
||||
|
@ -414,7 +414,15 @@ class MobileProfilePlugin extends WAP20Plugin
|
||||
|
||||
return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
|
||||
}
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
{
|
||||
$versions[] = array('name' => 'MobileProfile',
|
||||
'version' => STATUSNET_VERSION,
|
||||
'author' => 'Sarven Capadisli',
|
||||
'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
|
||||
'rawdescription' =>
|
||||
_m('XHTML MobileProfile output for supporting user agents.'));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
|
@ -46,8 +46,9 @@ class PoweredByStatusNetPlugin extends Plugin
|
||||
function onEndAddressData($action)
|
||||
{
|
||||
$action->elementStart('span', 'poweredby');
|
||||
$action->text(_('powered by'));
|
||||
$action->element('a', array('href' => 'http://status.net/'), 'StatusNet');
|
||||
$action->raw(sprintf(_m('powered by %s'),
|
||||
sprintf('<a href="http://status.net/">%s</a>',
|
||||
_m('StatusNet'))));
|
||||
$action->elementEnd('span');
|
||||
|
||||
return true;
|
||||
|
32
plugins/PoweredByStatusNet/locale/PoweredByStatusNet.po
Normal file
32
plugins/PoweredByStatusNet/locale/PoweredByStatusNet.po
Normal file
@ -0,0 +1,32 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-01-22 15:03-0800\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=CHARSET\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: PoweredByStatusNetPlugin.php:49
|
||||
#, php-format
|
||||
msgid "powered by %s"
|
||||
msgstr ""
|
||||
|
||||
#: PoweredByStatusNetPlugin.php:51
|
||||
msgid "StatusNet"
|
||||
msgstr ""
|
||||
|
||||
#: PoweredByStatusNetPlugin.php:64
|
||||
msgid ""
|
||||
"Outputs powered by <a href=\"http://status.net/\">StatusNet</a> after site "
|
||||
"name."
|
||||
msgstr ""
|
@ -18,7 +18,8 @@ display:none;
|
||||
}
|
||||
|
||||
.realtime-popup #form_notice label[for=notice_data-attach],
|
||||
.realtime-popup #form_notice #notice_data-attach {
|
||||
.realtime-popup #form_notice #notice_data-attach,
|
||||
.realtime-popup #form_notice label[for=notice_data-geo] {
|
||||
top:0;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2009 Control Yourself, Inc.
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @copyright 2009-2010 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/
|
||||
*/
|
||||
@ -41,6 +42,7 @@ define('TWITTERBRIDGEPLUGIN_VERSION', '0.9');
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
* @link http://twitter.com/
|
||||
@ -72,6 +74,27 @@ class TwitterBridgePlugin extends Plugin
|
||||
$m->connect('twitter/authorization',
|
||||
array('action' => 'twitterauthorization'));
|
||||
$m->connect('settings/twitter', array('action' => 'twittersettings'));
|
||||
$m->connect('main/twitterlogin', array('action' => 'twitterlogin'));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a login tab for 'Sign in with Twitter'
|
||||
*
|
||||
* @param Action &action the current action
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function onEndLoginGroupNav(&$action)
|
||||
{
|
||||
|
||||
$action_name = $action->trimmed('action');
|
||||
|
||||
$action->menuItem(common_local_url('twitterlogin'),
|
||||
_('Twitter'),
|
||||
_('Login or register using Twitter'),
|
||||
'twitterlogin' === $action_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -108,6 +131,7 @@ class TwitterBridgePlugin extends Plugin
|
||||
switch ($cls) {
|
||||
case 'TwittersettingsAction':
|
||||
case 'TwitterauthorizationAction':
|
||||
case 'TwitterloginAction':
|
||||
include_once INSTALLDIR . '/plugins/TwitterBridge/' .
|
||||
strtolower(mb_substr($cls, 0, -6)) . '.php';
|
||||
return false;
|
||||
|
@ -19,10 +19,11 @@
|
||||
* 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 TwitterauthorizationAction
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copely <zach@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @copyright 2009-2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -41,15 +42,21 @@ require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
|
||||
* (Foreign_link) between the StatusNet user and Twitter user and stores the
|
||||
* access token and secret in the link.
|
||||
*
|
||||
* @category Twitter
|
||||
* @category Plugin
|
||||
* @package StatusNet
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @author Julien C <chaumond@gmail.com>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
*/
|
||||
class TwitterauthorizationAction extends Action
|
||||
{
|
||||
var $twuid = null;
|
||||
var $tw_fields = null;
|
||||
var $access_token = null;
|
||||
var $signin = null;
|
||||
|
||||
/**
|
||||
* Initialize class members. Looks for 'oauth_token' parameter.
|
||||
*
|
||||
@ -61,6 +68,7 @@ class TwitterauthorizationAction extends Action
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->signin = $this->boolean('signin');
|
||||
$this->oauth_token = $this->arg('oauth_token');
|
||||
|
||||
return true;
|
||||
@ -77,28 +85,61 @@ class TwitterauthorizationAction extends Action
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_m('Not logged in.'), 403);
|
||||
if (common_logged_in()) {
|
||||
$user = common_current_user();
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
|
||||
// If there's already a foreign link record, it means we already
|
||||
// have an access token, and this is unecessary. So go back.
|
||||
|
||||
if (isset($flink)) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE);
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
|
||||
// If there's already a foreign link record, it means we already
|
||||
// have an access token, and this is unecessary. So go back.
|
||||
// User was not logged in to StatusNet before
|
||||
|
||||
if (isset($flink)) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
$this->twuid = $this->trimmed('twuid');
|
||||
|
||||
// $this->oauth_token is only populated once Twitter authorizes our
|
||||
// request token. If it's empty we're at the beginning of the auth
|
||||
// process
|
||||
$this->tw_fields = array('screen_name' => $this->trimmed('tw_fields_screen_name'),
|
||||
'fullname' => $this->trimmed('tw_fields_fullname'));
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
$this->authorizeRequestToken();
|
||||
$this->access_token = new OAuthToken($this->trimmed('access_token_key'), $this->trimmed('access_token_secret'));
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->arg('create')) {
|
||||
if (!$this->boolean('license')) {
|
||||
$this->showForm(_('You can\'t register if you don\'t agree to the license.'),
|
||||
$this->trimmed('newname'));
|
||||
return;
|
||||
}
|
||||
$this->createNewUser();
|
||||
} else if ($this->arg('connect')) {
|
||||
$this->connectNewUser();
|
||||
} else {
|
||||
common_debug('Twitter Connect Plugin - ' .
|
||||
print_r($this->args, true));
|
||||
$this->showForm(_('Something weird happened.'),
|
||||
$this->trimmed('newname'));
|
||||
}
|
||||
} else {
|
||||
$this->saveAccessToken();
|
||||
// $this->oauth_token is only populated once Twitter authorizes our
|
||||
// request token. If it's empty we're at the beginning of the auth
|
||||
// process
|
||||
|
||||
if (empty($this->oauth_token)) {
|
||||
$this->authorizeRequestToken();
|
||||
} else {
|
||||
$this->saveAccessToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +164,7 @@ class TwitterauthorizationAction extends Action
|
||||
$_SESSION['twitter_request_token'] = $req_tok->key;
|
||||
$_SESSION['twitter_request_token_secret'] = $req_tok->secret;
|
||||
|
||||
$auth_link = $client->getAuthorizeLink($req_tok);
|
||||
$auth_link = $client->getAuthorizeLink($req_tok, $this->signin);
|
||||
|
||||
} catch (OAuthClientException $e) {
|
||||
$msg = sprintf('OAuth client cURL error - code: %1s, msg: %2s',
|
||||
@ -150,6 +191,8 @@ class TwitterauthorizationAction extends Action
|
||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
$twitter_user = null;
|
||||
|
||||
try {
|
||||
|
||||
$client = new TwitterOAuthClient($_SESSION['twitter_request_token'],
|
||||
@ -165,40 +208,54 @@ class TwitterauthorizationAction extends Action
|
||||
$twitter_user = $client->verifyCredentials();
|
||||
|
||||
} catch (OAuthClientException $e) {
|
||||
$msg = sprintf('OAuth client cURL error - code: %1$s, msg: %2$s',
|
||||
$msg = sprintf('OAuth client error - code: %1$s, msg: %2$s',
|
||||
$e->getCode(), $e->getMessage());
|
||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
// Save the access token and Twitter user info
|
||||
if (common_logged_in()) {
|
||||
|
||||
$this->saveForeignLink($atok, $twitter_user);
|
||||
// Save the access token and Twitter user info
|
||||
|
||||
$user = common_current_user();
|
||||
$this->saveForeignLink($user->id, $twitter_user->id, $atok);
|
||||
save_twitter_user($twitter_user->id, $twitter_user->name);
|
||||
|
||||
} else {
|
||||
|
||||
$this->twuid = $twitter_user->id;
|
||||
$this->tw_fields = array("screen_name" => $twitter_user->screen_name,
|
||||
"name" => $twitter_user->name);
|
||||
$this->access_token = $atok;
|
||||
$this->tryLogin();
|
||||
}
|
||||
|
||||
// Clean up the the mess we made in the session
|
||||
|
||||
unset($_SESSION['twitter_request_token']);
|
||||
unset($_SESSION['twitter_request_token_secret']);
|
||||
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
if (common_logged_in()) {
|
||||
common_redirect(common_local_url('twittersettings'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a Foreign_link between Twitter user and local user,
|
||||
* which includes the access token and secret.
|
||||
*
|
||||
* @param OAuthToken $access_token the access token to save
|
||||
* @param mixed $twitter_user twitter API user object
|
||||
* @param int $user_id StatusNet user ID
|
||||
* @param int $twuid Twitter user ID
|
||||
* @param OAuthToken $token the access token to save
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function saveForeignLink($access_token, $twitter_user)
|
||||
function saveForeignLink($user_id, $twuid, $access_token)
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$flink = new Foreign_link();
|
||||
|
||||
$flink->user_id = $user->id;
|
||||
$flink->foreign_id = $twitter_user->id;
|
||||
$flink->user_id = $user_id;
|
||||
$flink->foreign_id = $twuid;
|
||||
$flink->service = TWITTER_SERVICE;
|
||||
|
||||
$creds = TwitterOAuthClient::packToken($access_token);
|
||||
@ -214,10 +271,325 @@ class TwitterauthorizationAction extends Action
|
||||
|
||||
if (empty($flink_id)) {
|
||||
common_log_db_error($flink, 'INSERT', __FILE__);
|
||||
$this->serverError(_m('Couldn\'t link your Twitter account.'));
|
||||
$this->serverError(_('Couldn\'t link your Twitter account.'));
|
||||
}
|
||||
|
||||
save_twitter_user($twitter_user->id, $twitter_user->screen_name);
|
||||
return $flink_id;
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
if ($this->error) {
|
||||
$this->element('div', array('class' => 'error'), $this->error);
|
||||
} else {
|
||||
$this->element('div', 'instructions',
|
||||
sprintf(_('This is the first time you\'ve logged into %s so we must connect your Twitter account to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
|
||||
}
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Twitter Account Setup');
|
||||
}
|
||||
|
||||
function showForm($error=null, $username=null)
|
||||
{
|
||||
$this->error = $error;
|
||||
$this->username = $username;
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function showPage()
|
||||
{
|
||||
parent::showPage();
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if (!empty($this->message_text)) {
|
||||
$this->element('p', null, $this->message);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'form_settings_twitter_connect',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('twitterauthorization')));
|
||||
$this->elementStart('fieldset', array('id' => 'settings_twitter_connect_options'));
|
||||
$this->element('legend', null, _('Connection options'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->element('input', array('type' => 'checkbox',
|
||||
'id' => 'license',
|
||||
'class' => 'checkbox',
|
||||
'name' => 'license',
|
||||
'value' => 'true'));
|
||||
$this->elementStart('label', array('class' => 'checkbox', 'for' => 'license'));
|
||||
$this->text(_('My text and files are available under '));
|
||||
$this->element('a', array('href' => common_config('license', 'url')),
|
||||
common_config('license', 'title'));
|
||||
$this->text(_(' except this private data: password, email address, IM address, phone number.'));
|
||||
$this->elementEnd('label');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->hidden('access_token_key', $this->access_token->key);
|
||||
$this->hidden('access_token_secret', $this->access_token->secret);
|
||||
$this->hidden('twuid', $this->twuid);
|
||||
$this->hidden('tw_fields_screen_name', $this->tw_fields['screen_name']);
|
||||
$this->hidden('tw_fields_name', $this->tw_fields['name']);
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->element('legend', null,
|
||||
_('Create new account'));
|
||||
$this->element('p', null,
|
||||
_('Create a new user with this nickname.'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('newname', _('New nickname'),
|
||||
($this->username) ? $this->username : '',
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('create', _('Create'));
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null,
|
||||
_('Connect existing account'));
|
||||
$this->element('p', null,
|
||||
_('If you already have an account, login with your username and password to connect it to your Twitter account.'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Existing nickname'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('password', _('Password'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('connect', _('Connect'));
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
function message($msg)
|
||||
{
|
||||
$this->message_text = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function createNewUser()
|
||||
{
|
||||
if (common_config('site', 'closed')) {
|
||||
$this->clientError(_('Registration not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$invite = null;
|
||||
|
||||
if (common_config('site', 'inviteonly')) {
|
||||
$code = $_SESSION['invitecode'];
|
||||
if (empty($code)) {
|
||||
$this->clientError(_('Registration not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$invite = Invitation::staticGet($code);
|
||||
|
||||
if (empty($invite)) {
|
||||
$this->clientError(_('Not a valid invitation code.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$nickname = $this->trimmed('newname');
|
||||
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => NICKNAME_FMT))) {
|
||||
$this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!User::allowed_nickname($nickname)) {
|
||||
$this->showForm(_('Nickname not allowed.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (User::staticGet('nickname', $nickname)) {
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$fullname = trim($this->tw_fields['name']);
|
||||
|
||||
$args = array('nickname' => $nickname, 'fullname' => $fullname);
|
||||
|
||||
if (!empty($invite)) {
|
||||
$args['code'] = $invite->code;
|
||||
}
|
||||
|
||||
$user = User::register($args);
|
||||
|
||||
$result = $this->saveForeignLink($user->id,
|
||||
$this->twuid,
|
||||
$this->access_token);
|
||||
|
||||
save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
|
||||
|
||||
if (!$result) {
|
||||
$this->serverError(_('Error connecting user to Twitter.'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_set_user($user);
|
||||
common_real_login(true);
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Registered new user $user->id from Twitter user $this->twuid");
|
||||
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
|
||||
function connectNewUser()
|
||||
{
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$password = $this->trimmed('password');
|
||||
|
||||
if (!common_check_user($nickname, $password)) {
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = User::staticGet('nickname', $nickname);
|
||||
|
||||
if (!empty($user)) {
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Legit user to connect to Twitter: $nickname");
|
||||
}
|
||||
|
||||
$result = $this->saveForeignLink($user->id,
|
||||
$this->twuid,
|
||||
$this->access_token);
|
||||
|
||||
save_twitter_user($this->twuid, $this->tw_fields['screen_name']);
|
||||
|
||||
if (!$result) {
|
||||
$this->serverError(_('Error connecting user to Twitter.'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Connected Twitter user $this->twuid to local user $user->id");
|
||||
|
||||
common_set_user($user);
|
||||
common_real_login(true);
|
||||
|
||||
$this->goHome($user->nickname);
|
||||
}
|
||||
|
||||
function connectUser()
|
||||
{
|
||||
$user = common_current_user();
|
||||
|
||||
$result = $this->flinkUser($user->id, $this->twuid);
|
||||
|
||||
if (empty($result)) {
|
||||
$this->serverError(_('Error connecting user to Twitter.'));
|
||||
return;
|
||||
}
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Connected Twitter user $this->twuid to local user $user->id");
|
||||
|
||||
// Return to Twitter connection settings tab
|
||||
common_redirect(common_local_url('twittersettings'), 303);
|
||||
}
|
||||
|
||||
function tryLogin()
|
||||
{
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Trying login for Twitter user $this->twuid.");
|
||||
|
||||
$flink = Foreign_link::getByForeignID($this->twuid,
|
||||
TWITTER_SERVICE);
|
||||
|
||||
if (!empty($flink)) {
|
||||
$user = $flink->getUser();
|
||||
|
||||
if (!empty($user)) {
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"Logged in Twitter user $flink->foreign_id as user $user->id ($user->nickname)");
|
||||
|
||||
common_set_user($user);
|
||||
common_real_login(true);
|
||||
$this->goHome($user->nickname);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
common_debug('TwitterBridge Plugin - ' .
|
||||
"No flink found for twuid: $this->twuid - new user");
|
||||
|
||||
$this->showForm(null, $this->bestNewNickname());
|
||||
}
|
||||
}
|
||||
|
||||
function goHome($nickname)
|
||||
{
|
||||
$url = common_get_returnto();
|
||||
if ($url) {
|
||||
// We don't have to return to it again
|
||||
common_set_returnto(null);
|
||||
} else {
|
||||
$url = common_local_url('all',
|
||||
array('nickname' =>
|
||||
$nickname));
|
||||
}
|
||||
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
function bestNewNickname()
|
||||
{
|
||||
if (!empty($this->tw_fields['name'])) {
|
||||
$nickname = $this->nicknamize($this->tw_fields['name']);
|
||||
if ($this->isNewNickname($nickname)) {
|
||||
return $nickname;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Given a string, try to make it work as a nickname
|
||||
|
||||
function nicknamize($str)
|
||||
{
|
||||
$str = preg_replace('/\W/', '', $str);
|
||||
$str = str_replace(array('-', '_'), '', $str);
|
||||
return strtolower($str);
|
||||
}
|
||||
|
||||
function isNewNickname($str)
|
||||
{
|
||||
if (!Validate::string($str, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => NICKNAME_FMT))) {
|
||||
return false;
|
||||
}
|
||||
if (!User::allowed_nickname($str)) {
|
||||
return false;
|
||||
}
|
||||
if (User::staticGet('nickname', $str)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
97
plugins/TwitterBridge/twitterlogin.php
Normal file
97
plugins/TwitterBridge/twitterlogin.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* StatusNet, the distributed open-source microblogging tool
|
||||
*
|
||||
* 'Sign in with Twitter' login page
|
||||
*
|
||||
* 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 Login
|
||||
* @package StatusNet
|
||||
* @author Julien Chaumond <chaumond@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR . '/plugins/TwitterBridge/twitter.php';
|
||||
|
||||
/**
|
||||
* Page for logging in with Twitter
|
||||
*
|
||||
* @category Login
|
||||
* @package StatusNet
|
||||
* @author Julien Chaumond <chaumond@gmail.com>
|
||||
* @author Zach Copley <zach@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*
|
||||
* @see SettingsAction
|
||||
*/
|
||||
|
||||
class TwitterloginAction extends Action
|
||||
{
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if (common_is_real_login()) {
|
||||
$this->clientError(_('Already logged in.'));
|
||||
}
|
||||
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Twitter Login');
|
||||
}
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Login with your Twitter account');
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
$instr = $this->getInstructions();
|
||||
$output = common_markup_to_html($instr);
|
||||
$this->elementStart('div', 'instructions');
|
||||
$this->raw($output);
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('a', array('href' => common_local_url('twitterauthorization',
|
||||
null,
|
||||
array('signin' => true))));
|
||||
$this->element('img', array('src' => common_path('plugins/TwitterBridge/Sign-in-with-Twitter-lighter.png'),
|
||||
'alt' => 'Sign in with Twitter'));
|
||||
$this->elementEnd('a');
|
||||
}
|
||||
|
||||
function showLocalNav()
|
||||
{
|
||||
$nav = new LoginGroupNav($this);
|
||||
$nav->show();
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ class TwitterOAuthClient extends OAuthClient
|
||||
{
|
||||
public static $requestTokenURL = 'https://twitter.com/oauth/request_token';
|
||||
public static $authorizeURL = 'https://twitter.com/oauth/authorize';
|
||||
public static $signinUrl = 'https://twitter.com/oauth/authenticate';
|
||||
public static $accessTokenURL = 'https://twitter.com/oauth/access_token';
|
||||
|
||||
/**
|
||||
@ -97,9 +98,11 @@ class TwitterOAuthClient extends OAuthClient
|
||||
*
|
||||
* @return the link
|
||||
*/
|
||||
function getAuthorizeLink($request_token)
|
||||
function getAuthorizeLink($request_token, $signin = false)
|
||||
{
|
||||
return parent::getAuthorizeLink(self::$authorizeURL,
|
||||
$url = ($signin) ? self::$signinUrl : self::$authorizeURL;
|
||||
|
||||
return parent::getAuthorizeLink($url,
|
||||
$request_token,
|
||||
common_local_url('twitterauthorization'));
|
||||
}
|
||||
|
@ -121,8 +121,35 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
$this->elementEnd('p');
|
||||
$this->element('p', 'form_note',
|
||||
_m('Connected Twitter account'));
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->submit('remove', _m('Remove'));
|
||||
$this->elementStart('fieldset');
|
||||
|
||||
$this->element('legend', null, _m('Disconnect my account from Twitter'));
|
||||
|
||||
if (!$user->password) {
|
||||
|
||||
$this->elementStart('p', array('class' => 'form_guide'));
|
||||
$this->text(_m('Disconnecting your Twitter ' .
|
||||
'could make it impossible to log in! Please '));
|
||||
$this->element('a',
|
||||
array('href' => common_local_url('passwordsettings')),
|
||||
_m('set a password'));
|
||||
|
||||
$this->text(_m(' first.'));
|
||||
$this->elementEnd('p');
|
||||
} else {
|
||||
|
||||
$note = _m('Keep your %1$s account but disconnect from Twitter. ' .
|
||||
'You can use your %1$s password to log in.');
|
||||
|
||||
$site = common_config('site', 'name');
|
||||
|
||||
$this->element('p', 'instructions',
|
||||
sprintf($note, $site));
|
||||
|
||||
$this->submit('disconnect', _m('Disconnect'));
|
||||
}
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
@ -205,7 +232,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
if ($this->arg('save')) {
|
||||
$this->savePreferences();
|
||||
} else if ($this->arg('remove')) {
|
||||
} else if ($this->arg('disconnect')) {
|
||||
$this->removeTwitterAccount();
|
||||
} else {
|
||||
$this->showForm(_m('Unexpected form submission.'));
|
||||
@ -231,7 +258,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
return;
|
||||
}
|
||||
|
||||
$this->showForm(_m('Twitter account removed.'), true);
|
||||
$this->showForm(_m('Twitter account disconnected.'), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +86,7 @@ class User_flag_profile extends Memcached_DataObject
|
||||
|
||||
function keys()
|
||||
{
|
||||
return array('profile_id' => 'N', 'user_id' => 'N');
|
||||
return array('profile_id' => 'K', 'user_id' => 'K');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,6 +130,15 @@ class User_flag_profile extends Memcached_DataObject
|
||||
return !empty($ufp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new flag
|
||||
*
|
||||
* @param integer $user_id ID of user who's flagging
|
||||
* @param integer $profile_id ID of profile being flagged
|
||||
*
|
||||
* @return boolean success flag
|
||||
*/
|
||||
|
||||
static function create($user_id, $profile_id)
|
||||
{
|
||||
$ufp = new User_flag_profile();
|
||||
|
51
theme/README
51
theme/README
@ -2,37 +2,46 @@
|
||||
*
|
||||
* @package StatusNet
|
||||
* @author Sarven Capadisli <csarven@status.net>
|
||||
* @copyright 2009 StatusNet, Inc.
|
||||
* @copyright 2010 StatusNet, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
|
||||
Location of key paths and files under theme/:
|
||||
== Location of key paths and files ==
|
||||
<pre><nowiki>
|
||||
base/css/
|
||||
base/css/display.css #layout, typography rules
|
||||
base/images/ #common icons, illustrations
|
||||
base/images/icons/icons-01.png #main icons file (combined into a single file)
|
||||
|
||||
./base/css/
|
||||
./base/css/display.css
|
||||
./base/images/
|
||||
default/css/
|
||||
default/css/display.css #imports the base stylesheet for layout and adds background images and colour rules
|
||||
default/logo.png #default site logo for this theme
|
||||
default/mobilelogo.png #default logo for the mobile output
|
||||
default/default-avatar-mini.png #24x24 default avatar for minilists
|
||||
default/default-avatar-stream.png #48x48 default avatar for notice timelines
|
||||
default/default-avatar-profile.png #96x96 default avatar for the profile page
|
||||
</nowiki></pre>
|
||||
|
||||
./default/css/
|
||||
./default/css/display.css
|
||||
./default/images/
|
||||
|
||||
./base/display.css contains layout, typography rules:
|
||||
Only alter this file if you want to change the layout of the site. Please note that, any updates to this in future statusnet releases may not be compatible with your version.
|
||||
== How to create your own theme ==
|
||||
|
||||
./default/css/display.css contains only the background images and colour rules:
|
||||
This file is a good basis for creating your own theme.
|
||||
|
||||
Let's create a theme:
|
||||
You probably want to do one of the following:
|
||||
|
||||
1. To start off, copy over the default theme:
|
||||
cp -r default mytheme
|
||||
|
||||
2. Edit your mytheme stylesheet:
|
||||
nano mytheme/css/display.css
|
||||
* If you just want to change the text, link, background, content, sidebar colours, background image:
|
||||
** Do this from the Admin->Design settings (recommended!). You could also create a directory and a file structure like the default theme, search and replace with your own values. This is more work, but, you can do this if you plan to make additional *minimal* changes.
|
||||
|
||||
a) Search and replace your colours and background images, or
|
||||
b) Create your own layout either importing a separate stylesheet (e.g., change to @import url(base.css);) or simply place it before the rest of the rules.
|
||||
|
||||
4. Set /config.php to load 'mytheme':
|
||||
$config['site']['theme'] = 'mytheme';
|
||||
* If you want to change the background images and colours:
|
||||
# Create a directory and a file structure like the default theme.
|
||||
# Have your stylesheet import base/css/display.css and add your own styles below. It is okay to add *minimal* changes here.
|
||||
|
||||
|
||||
* If you want to create a different layout, typography, background images and colours:
|
||||
** Create your own theme directory (base or default) with stylesheets and images like.
|
||||
|
||||
|
||||
Finally, enable your theme by selecting it from the Admin->Design interface. You can set site's logo from here as well.
|
||||
|
||||
|
@ -1039,12 +1039,13 @@ overflow:visible;
|
||||
#showstream .notice div.entry-content {
|
||||
margin-left:0;
|
||||
}
|
||||
#shownotice .notice .entry-title,
|
||||
#shownotice .notice div.entry-content {
|
||||
margin-left:110px;
|
||||
}
|
||||
#shownotice .notice .entry-title {
|
||||
margin-left:110px;
|
||||
font-size:2.2em;
|
||||
min-height:123px;
|
||||
}
|
||||
#shownotice .notice div.entry-content {
|
||||
margin-left:0;
|
||||
}
|
||||
|
||||
.notice p.entry-content {
|
||||
|
Loading…
Reference in New Issue
Block a user