diff options
33 files changed, 736 insertions, 252 deletions
diff --git a/EVENTS.txt b/EVENTS.txt index ed461ee9f..5edf59245 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -88,9 +88,18 @@ StartShowLocalNavBlock: Showing the local nav menu EndShowLocalNavBlock: At the end of the local nav menu - $action: the current action -StartShowHTML: Chance to set document content type, charset, language, DOCTYPE and html element properties +StartShowHTML: Chance to set document headers (e.g., content type, charset, language), DOCTYPE and html element properties - $action: the current action EndShowHTML: Showing after the html element - $action: the current action +StartPublicGroupNav: Showing the public group nav menu +- $action: the current action + +EndPublicGroupNav: At the end of the public group nav menu +- $action: the current action + +RouterInitialized: After the router instance has been initialized +- $m: the Net_URL_Mapper that has just been set up + @@ -236,21 +236,28 @@ especially if you've previously installed PHP/MySQL packages. configure virtual hosts on your web server, you can try setting up "http://micro.example.net/" or the like. -3. You should also take this moment to make your avatar subdirectory - writeable by the Web server. An insecure way to do this is: +3. Make your target directory writeable by the Web server. - chmod a+w /var/www/mublog/avatar + chmod a+w /var/www/mublog/ On some systems, this will probably work: - chgrp www-data /var/www/mublog/avatar - chmod g+w /var/www/mublog/avatar + chgrp www-data /var/www/mublog/ + chmod g+w /var/www/mublog/ If your Web server runs as another user besides "www-data", try that user's default group instead. As a last resort, you can create - a new group like "avatar" and add the Web server's user to the group. + a new group like "mublog" and add the Web server's user to the group. -4. Create a database to hold your microblog data. Something like this +4. You should also take this moment to make your avatar subdirectory + writeable by the Web server. An insecure way to do this is: + + chmod a+w /var/www/mublog/avatar + + You can also make the avatar directory writeable by the Web server + group, as noted above. + +5. Create a database to hold your microblog data. Something like this should work: mysqladmin -u "username" --password="password" create laconica @@ -263,63 +270,55 @@ especially if you've previously installed PHP/MySQL packages. a tool like PHPAdmin to create a database. Check your hosting service's documentation for how to create a new MySQL database.) -5. Run the laconica.sql SQL script in the db subdirectory to create - the database tables in the database. A typical system would work - like this: - - mysql -u "username" --password="password" laconica < /var/www/mublog/db/laconica.sql - - You may want to test by logging into the database and checking that - the tables were created. Here's an example: - - SHOW TABLES; - 6. Create a new database account that Laconica will use to access the database. If you have shell access, this will probably work from the MySQL shell: - GRANT SELECT,INSERT,DELETE,UPDATE on laconica.* + GRANT ALL on laconica.* TO 'lacuser'@'localhost' IDENTIFIED BY 'lacpassword'; You should change 'lacuser' and 'lacpassword' to your preferred new - username and password. You may want to test logging in as this new - user and testing that you can SELECT from some of the tables in the - DB (use SHOW TABLES to see which ones are there). - -7. Copy the config.php.sample in the Laconica directory to config.php. - -8. Edit config.php to set the basic configuration for your system. - (See descriptions below for basic config options.) Note that there - are lots of options and if you try to do them all at once, you will - have a hard time making sure what's working and what's not. So, - stick with the basics at first. In particular, customizing the - 'site' and 'db' settings will almost definitely be needed. - -9. At this point, you should be able to navigate in a browser to your - microblog's main directory and see the "Public Timeline", which - will be empty. If not, magic has happened! You can now register a - new user, post some notices, edit your profile, etc. However, you - may want to wait to do that stuff if you think you can set up - "fancy URLs" (see below), since some URLs are stored in the database. + username and password. You may want to test logging in to MySQL as + this new user. + +7. In a browser, navigate to the Laconica install script; something like: + + http://yourserver.example.com/mublog/install.php + + Enter the database connection information and your site name. The + install program will configure your site and install the initial, + almost-empty database. + +8. You should now be able to navigate to your microblog's main directory + and see the "Public Timeline", which will be empty. If not, magic + has happened! You can now register a new user, post some notices, + edit your profile, etc. However, you may want to wait to do that stuff + if you think you can set up "fancy URLs" (see below), since some + URLs are stored in the database. Fancy URLs ---------- -By default, Laconica will have big long sloppy URLs that are hard for -people to remember or use. For example, a user's home profile might be +By default, Laconica will use URLs that include the main PHP program's +name in them. For example, a user's home profile might be found at: - http://example.org/mublog/index.php?action=showstream&nickname=fred + http://example.org/mublog/index.php/mublog/fred + +On certain systems that don't support this kind of syntax, they'll +look like this: + + http://example.org/mublog/index.php?p=mublog/fred It's possible to configure the software so it looks like this instead: http://example.org/mublog/fred These "fancy URLs" are more readable and memorable for users. To use -fancy URLs, you must either have Apache 2.2.x with .htaccess enabled -and mod_redirect enabled, -OR- know how to configure "url redirection" -in your server. +fancy URLs, you must either have Apache 2.x with .htaccess enabled and +mod_redirect enabled, -OR- know how to configure "url redirection" in +your server. 1. Copy the htaccess.sample file to .htaccess in your Laconica directory. Note: if you have control of your server's httpd.conf or @@ -344,10 +343,6 @@ like: If you changed your HTTP server configuration, you may need to restart the server first. -If you have problems with the .htaccess file on versions of Apache -earlier than 2.2.x, try changing the regular expressions in the -htaccess.sample file that use "\w" to just use ".". - Sphinx ------ @@ -557,7 +552,7 @@ Sample cron job: # Update Twitter friends subscriptions every half hour 0,30 * * * * /path/to/php /path/to/laconica/scripts/synctwitterfriends.php>&/dev/null -Built-in Facebook Application +Built-in Facebook Application ----------------------------- Laconica's Facebook application allows your users to automatically @@ -571,7 +566,7 @@ above). Quick setup instructions*: -Install the Facebook Developer application on Facebook: +Install the Facebook Developer application on Facebook: http://www.facebook.com/developers/ @@ -644,7 +639,7 @@ to these resources. Themes ------ -There are two themes shipped with this version of Laconica: "stoica", +There are two themes shipped with this version of Laconica: "identica", which is what the Identi.ca site uses, and "default", which is a good basis for other sites. diff --git a/actions/avatarsettings.php b/actions/avatarsettings.php index 6545d9489..c2bb35a39 100644 --- a/actions/avatarsettings.php +++ b/actions/avatarsettings.php @@ -324,11 +324,13 @@ class AvatarsettingsAction extends AccountSettingsAction return; } - // If image is not being cropped assume pos & dimensions of original. + $file_d = ($filedata['width'] > $filedata['height']) + ? $filedata['height'] : $filedata['width']; + $dest_x = $this->arg('avatar_crop_x') ? $this->arg('avatar_crop_x'):0; $dest_y = $this->arg('avatar_crop_y') ? $this->arg('avatar_crop_y'):0; - $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$filedata['width']; - $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$filedata['height']; + $dest_w = $this->arg('avatar_crop_w') ? $this->arg('avatar_crop_w'):$file_d; + $dest_h = $this->arg('avatar_crop_h') ? $this->arg('avatar_crop_h'):$file_d; $size = min($dest_w, $dest_h, MAX_ORIGINAL); $user = common_current_user(); diff --git a/actions/favorited.php b/actions/favorited.php index fd5ff413c..5082f4a4e 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -169,8 +169,14 @@ class FavoritedAction extends Action function showContent() { + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; + } + $qry = 'SELECT notice.*, '. - 'sum(exp(-(now() - fave.modified) / %s)) as weight ' . + $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . 'GROUP BY fave.notice_id ' . 'ORDER BY weight DESC'; diff --git a/actions/newnotice.php b/actions/newnotice.php index 9f44d2516..cbd04c58b 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -152,6 +152,11 @@ class NewnoticeAction extends Action } $replyto = $this->trimmed('inreplyto'); + #If an ID of 0 is wrongly passed here, it will cause a database error, + #so override it... + if ($replyto == 0) { + $replyto = 'false'; + } $notice = Notice::saveNew($user->id, $content, 'web', 1, ($replyto == 'false') ? null : $replyto); diff --git a/actions/twitapiaccount.php b/actions/twitapiaccount.php index c19cd370d..68a18cb57 100644 --- a/actions/twitapiaccount.php +++ b/actions/twitapiaccount.php @@ -23,22 +23,24 @@ require_once(INSTALLDIR.'/lib/twitterapi.php'); class TwitapiaccountAction extends TwitterapiAction { - function verify_credentials($args, $apidata) { - if ($apidata['content-type'] == 'xml') { - header('Content-Type: application/xml; charset=utf-8'); - print '<authorized>true</authorized>'; - } elseif ($apidata['content-type'] == 'json') { - header('Content-Type: application/json; charset=utf-8'); - print '{"authorized":true}'; - } else { + parent::handle($args); + + switch ($apidata['content-type']) { + case 'xml': + case 'json': + $action_obj = new TwitapiusersAction(); + $action_obj->prepare($args); + call_user_func(array($action_obj, 'show'), $args, $apidata); + break; + default: header('Content-Type: text/html; charset=utf-8'); print 'Authorized'; } } - function end_session($args, $apidata) + function end_session($args, $apidata) { parent::handle($args); $this->serverError(_('API method under construction.'), $code=501); diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php index 8f16e5613..2894b7486 100644 --- a/actions/twitapiusers.php +++ b/actions/twitapiusers.php @@ -25,25 +25,29 @@ class TwitapiusersAction extends TwitterapiAction { function show($args, $apidata) - { + { parent::handle($args); - if (!in_array($apidata['content-type'], array('xml', 'json'))) { + if (!in_array($apidata['content-type'], array('xml', 'json'))) { $this->clientError(_('API method not found!'), $code = 404); return; } - - $this->auth_user = $apidata['user']; + $user = null; $email = $this->arg('email'); + $user_id = $this->arg('user_id'); if ($email) { $user = User::staticGet('email', $email); + } elseif ($user_id) { + $user = $this->get_user($user_id); } elseif (isset($apidata['api_arg'])) { $user = $this->get_user($apidata['api_arg']); - } - - if (!$user) { + } elseif (isset($apidata['user'])) { + $user = $apidata['user']; + } + + if (!$user) { // XXX: Twitter returns a random(?) user instead of throwing and err! -- Zach $this->client_error(_('Not found.'), 404, $apidata['content-type']); return; @@ -74,9 +78,12 @@ class TwitapiusersAction extends TwitterapiAction // Other fields Twitter sends... $twitter_user['profile_background_color'] = ''; + $twitter_user['profile_background_image_url'] = ''; $twitter_user['profile_text_color'] = ''; $twitter_user['profile_link_color'] = ''; $twitter_user['profile_sidebar_fill_color'] = ''; + $twitter_user['profile_sidebar_border_color'] = ''; + $twitter_user['profile_background_tile'] = 'false'; $faves = DB_DataObject::factory('fave'); $faves->user_id = $user->id; @@ -94,18 +101,27 @@ class TwitapiusersAction extends TwitterapiAction $twitter_user['utc_offset'] = $t->format('Z'); $twitter_user['time_zone'] = $timezone; - if (isset($this->auth_user)) { + if (isset($apidata['user'])) { - if ($this->auth_user->isSubscribed($profile)) { + if ($apidata['user']->isSubscribed($profile)) { $twitter_user['following'] = 'true'; } else { $twitter_user['following'] = 'false'; } - - // Not implemented yet - $twitter_user['notifications'] = 'false'; - } - + + // Notifications on? + $sub = Subscription::pkeyGet(array('subscriber' => + $apidata['user']->id, 'subscribed' => $profile->id)); + + if ($sub) { + if ($sub->jabber || $sub->sms) { + $twitter_user['notifications'] = 'true'; + } else { + $twitter_user['notifications'] = 'false'; + } + } + } + if ($apidata['content-type'] == 'xml') { $this->init_document('xml'); $this->show_twitter_xml_user($twitter_user); @@ -114,7 +130,13 @@ class TwitapiusersAction extends TwitterapiAction $this->init_document('json'); $this->show_json_objects($twitter_user); $this->end_document('json'); - } + } else { + + // This is in case 'show' was called via /account/verify_credentials + // without a format (xml or json). + header('Content-Type: text/html; charset=utf-8'); + print 'Authorized'; + } } } diff --git a/classes/Notice.php b/classes/Notice.php index 8300667fa..907239b08 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -585,7 +585,7 @@ class Notice extends Memcached_DataObject $inbox = new Notice_inbox(); $UT = common_config('db','type')=='pgsql'?'"user"':'user'; $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' . - "SELECT $UT.id, " . $this->id . ', "' . $this->created . '" ' . + "SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " . "FROM $UT JOIN subscription ON $UT.id = subscription.subscriber " . 'WHERE subscription.subscribed = ' . $this->profile_id . ' ' . 'AND NOT EXISTS (SELECT user_id, notice_id ' . @@ -655,7 +655,7 @@ class Notice extends Memcached_DataObject $inbox = new Notice_inbox(); $UT = common_config('db','type')=='pgsql'?'"user"':'user'; $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' . - "SELECT $UT.id, " . $this->id . ', "' . $this->created . '", 2 ' . + "SELECT $UT.id, " . $this->id . ", '" . $this->created . "', 2 " . "FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " . 'WHERE group_member.group_id = ' . $group->id . ' ' . 'AND NOT EXISTS (SELECT user_id, notice_id ' . diff --git a/classes/Profile_tag.php b/classes/Profile_tag.php index cb60cbaec..0a1ad9cd6 100644 --- a/classes/Profile_tag.php +++ b/classes/Profile_tag.php @@ -4,7 +4,7 @@ */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Profile_tag extends Memcached_DataObject +class Profile_tag extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -23,45 +23,46 @@ class Profile_tag extends Memcached_DataObject ###END_AUTOCODE static function getTags($tagger, $tagged) { - + $tags = array(); # XXX: store this in memcached - + $profile_tag = new Profile_tag(); $profile_tag->tagger = $tagger; $profile_tag->tagged = $tagged; - + $profile_tag->find(); - + while ($profile_tag->fetch()) { $tags[] = $profile_tag->tag; } - + $profile_tag->free(); - + return $tags; } - + static function setTags($tagger, $tagged, $newtags) { - + + $newtags = array_unique($newtags); $oldtags = Profile_tag::getTags($tagger, $tagged); - + # Delete stuff that's old that not in new - + $to_delete = array_diff($oldtags, $newtags); - + # Insert stuff that's in new and not in old - + $to_insert = array_diff($newtags, $oldtags); - + $profile_tag = new Profile_tag(); - + $profile_tag->tagger = $tagger; $profile_tag->tagged = $tagged; - + $profile_tag->query('BEGIN'); - + foreach ($to_delete as $deltag) { $profile_tag->tag = $deltag; $result = $profile_tag->delete(); @@ -70,7 +71,7 @@ class Profile_tag extends Memcached_DataObject return false; } } - + foreach ($to_insert as $instag) { $profile_tag->tag = $instag; $result = $profile_tag->insert(); @@ -79,12 +80,12 @@ class Profile_tag extends Memcached_DataObject return false; } } - + $profile_tag->query('COMMIT'); - + return true; } - + # Return profiles with a given tag static function getTagged($tagger, $tag) { $profile = new Profile(); diff --git a/config.php.sample b/config.php.sample index 6e55eaffc..a6cada77a 100644 --- a/config.php.sample +++ b/config.php.sample @@ -34,6 +34,9 @@ $config['site']['path'] = 'laconica'; # If you want logging sent to a file instead of syslog #$config['site']['logfile'] = '/tmp/laconica.log'; +# Enables extra log information, for example full details of PEAR DB errors +#$config['site']['logdebug'] = true; + # This is a PEAR DB DSN, see http://pear.php.net/manual/en/package.database.db.intro-dsn.php # Set it to match your actual database diff --git a/db/foreign_services.sql b/db/foreign_services.sql index 512d42513..557ede024 100644 --- a/db/foreign_services.sql +++ b/db/foreign_services.sql @@ -1,8 +1,5 @@ insert into foreign_service (id, name, description, created) values - ('1','Twitter', 'Twitter Micro-blogging service', now()); -insert into foreign_service - (id, name, description, created) -values - ('2','Facebook', 'Facebook', now()); + ('1','Twitter', 'Twitter Micro-blogging service', now()), + ('2','Facebook', 'Facebook', now()); diff --git a/db/laconica.sql b/db/laconica.sql index dd93a727b..c2cd887de 100644 --- a/db/laconica.sql +++ b/db/laconica.sql @@ -171,7 +171,7 @@ create table token ( tok char(32) not null comment 'identifying value', secret char(32) not null comment 'secret value', type tinyint not null default 0 comment 'request or access', - state tinyint default 0 comment 'for requests; 0 = initial, 1 = authorized, 2 = used', + state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used', created datetime not null comment 'date this record was created', modified timestamp comment 'date this record was modified', @@ -344,7 +344,7 @@ create table notice_inbox ( user_id integer not null comment 'user receiving the message' references user (id), notice_id integer not null comment 'notice received' references notice (id), created datetime not null comment 'date the notice was created', - source tinyint default 1 comment 'reason it is in the inbox; 1=subscription', + source tinyint default 1 comment 'reason it is in the inbox, 1=subscription', constraint primary key (user_id, notice_id), index notice_inbox_notice_id_idx (notice_id) diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql index 9882d091a..4ef2330f4 100644 --- a/db/laconica_pg.sql +++ b/db/laconica_pg.sql @@ -8,7 +8,7 @@ create table profile ( homepage varchar(255) /* comment 'identifying URL' */,
bio varchar(140) /* comment 'descriptive biography' */,
location varchar(255) /* comment 'physical location' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
textsearch tsvector
@@ -23,7 +23,7 @@ create table avatar ( mediatype varchar(32) not null /* comment 'file type' */,
filename varchar(255) null /* comment 'local filename, if local' */,
url varchar(255) unique /* comment 'avatar location' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
primary key(profile_id, width, height)
@@ -34,7 +34,7 @@ create table sms_carrier ( id serial primary key /* comment 'primary key for SMS carrier' */,
name varchar(64) unique /* comment 'name of the carrier' */,
email_pattern varchar(255) not null /* comment 'sprintf pattern for making an email address from a phone number' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified ' */
);
@@ -50,6 +50,7 @@ create table "user" ( emailnotifyfav integer default 1 /* comment 'Notify by email of favorites' */,
emailnotifynudge integer default 1 /* comment 'Notify by email of nudges' */,
emailnotifymsg integer default 1 /* comment 'Notify by email of direct messages' */,
+ emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */,
emailmicroid integer default 1 /* comment 'whether to publish email microid' */,
language varchar(50) /* comment 'preferred language' */,
timezone varchar(50) /* comment 'timezone' */,
@@ -68,7 +69,7 @@ create table "user" ( autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -81,7 +82,7 @@ create table remote_profile ( uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
postnoticeurl varchar(255) /* comment 'URL we use for posting notices' */,
updateprofileurl varchar(255) /* comment 'URL we use for updates to this profile' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -92,7 +93,7 @@ create table subscription ( sms integer default 1 /* comment 'deliver sms messages' */,
token varchar(255) /* comment 'authorization token' */,
secret varchar(255) /* comment 'token secret' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
primary key (subscriber, subscribed)
@@ -108,7 +109,7 @@ create table notice ( content varchar(140) /* comment 'update content' */,
rendered text /* comment 'HTML version of the content' */,
url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
reply_to integer /* comment 'notice replied to (usually a guess)' */ references notice (id) ,
is_local integer default 0 /* comment 'notice was generated by a user' */,
@@ -123,7 +124,7 @@ create table notice_source ( code varchar(32) primary key not null /* comment 'source code' */,
name varchar(255) not null /* comment 'name of the source' */,
url varchar(255) not null /* comment 'url to link to' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -131,7 +132,7 @@ create table reply ( notice_id integer not null /* comment 'notice that is the reply' */ references notice (id) ,
profile_id integer not null /* comment 'profile replied to' */ references profile (id) ,
- modified timestamp not null default 'now' /* comment 'date this record was modified' */,
+ modified timestamp /* comment 'date this record was modified' */,
replied_id integer /* comment 'notice replied to (not used, see notice.reply_to)' */,
primary key (notice_id, profile_id)
@@ -145,7 +146,7 @@ create table fave ( notice_id integer not null /* comment 'notice that is the favorite' */ references notice (id),
user_id integer not null /* comment 'user who likes this notice' */ references "user" (id) ,
- modified timestamp not null /* comment 'date this record was modified' */,
+ modified timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was modified' */,
primary key (notice_id, user_id)
);
@@ -159,7 +160,7 @@ create table consumer ( consumer_key varchar(255) primary key /* comment 'unique identifier, root URL' */,
seed char(32) not null /* comment 'seed for new tokens by this consumer' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -170,7 +171,7 @@ create table token ( type integer not null default 0 /* comment 'request or access' */,
state integer default 0 /* comment 'for requests; 0 = initial, 1 = authorized, 2 = used' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
primary key (consumer_key, tok)
@@ -182,7 +183,7 @@ create table nonce ( nonce char(32) not null /* comment 'nonce' */,
ts timestamp not null /* comment 'timestamp sent' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
primary key (consumer_key, tok, nonce),
@@ -195,7 +196,7 @@ create table user_openid ( canonical varchar(255) primary key /* comment 'Canonical true URL' */,
display varchar(255) not null unique /* comment 'URL for viewing, may be different from canonical' */,
user_id integer not null /* comment 'user owning this URL' */ references "user" (id) ,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -241,7 +242,7 @@ create table queue_item ( notice_id integer not null /* comment 'notice queued' */ references notice (id) ,
transport varchar(8) not null /* comment 'queue for what? "email", "jabber", "sms", "irc", ...' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
claimed timestamp /* comment 'date this item was claimed' */,
primary key (notice_id, transport)
@@ -253,7 +254,7 @@ create index queue_item_created_idx on queue_item using btree(created); create table notice_tag (
tag varchar( 64 ) not null /* comment 'hash tag associated with this notice' */,
notice_id integer not null /* comment 'notice tagged' */ references notice (id) ,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
primary key (tag, notice_id)
);
@@ -265,7 +266,7 @@ create table foreign_service ( id int not null primary key /* comment 'numeric key for service' */,
name varchar(32) not null unique /* comment 'name of the service' */,
description varchar(255) /* comment 'description' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -274,7 +275,7 @@ create table foreign_user ( service int not null /* comment 'foreign key to service' */ references foreign_service(id) ,
uri varchar(255) not null unique /* comment 'identifying URI' */,
nickname varchar(255) /* comment 'nickname on foreign service' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
primary key (id, service)
@@ -288,8 +289,8 @@ create table foreign_link ( noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
- created timestamp not null /* comment 'date this record was created' */,
- modified timestamp not null /* comment 'date this record was modified' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
primary key (user_id,foreign_id,service)
);
@@ -299,7 +300,7 @@ create table foreign_subscription ( service int not null /* comment 'service where relationship happens' */ references foreign_service(id) ,
subscriber int not null /* comment 'subscriber on foreign service' */ ,
subscribed int not null /* comment 'subscribed user' */ ,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
primary key (service, subscriber, subscribed)
);
@@ -311,7 +312,7 @@ create table invitation ( user_id int not null /* comment 'who sent the invitation' */ references "user" (id),
address varchar(255) not null /* comment 'invitation sent to' */,
address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms") '*/,
- created timestamp not null /* comment 'date this record was created' */
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */
);
create index invitation_address_idx on invitation using btree(address,address_type);
@@ -326,7 +327,7 @@ create table message ( content varchar(140) /* comment 'message content' */,
rendered text /* comment 'HTML version of the content' */,
url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
@@ -339,7 +340,7 @@ create table notice_inbox ( user_id integer not null /* comment 'user receiving the message' */ references "user" (id),
notice_id integer not null /* comment 'notice received' */ references notice (id),
- created timestamp not null /* comment 'date the notice was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
source integer default 1 /* comment 'reason it is in the inbox; 1=subscription' */,
primary key (user_id, notice_id)
@@ -382,7 +383,7 @@ create table user_group ( stream_logo varchar(255) /* comment 'stream-sized logo' */,
mini_logo varchar(255) /* comment 'mini logo' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */
);
@@ -394,7 +395,7 @@ create table group_member ( profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id),
is_admin integer default 0 /* comment 'is this user an admin?' */,
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
primary key (group_id, profile_id)
@@ -405,7 +406,7 @@ create table related_group ( group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id) ,
related_group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
- created timestamp not null /* comment 'date this record was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
primary key (group_id, related_group_id)
@@ -414,7 +415,7 @@ create table related_group ( create table group_inbox (
group_id integer not null /* comment 'group receiving the message' references user_group (id) */,
notice_id integer not null /* comment 'notice received' references notice (id) */,
- created timestamp not null /* comment 'date the notice was created' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
primary key (group_id, notice_id)
);
diff --git a/db/notice_source.sql b/db/notice_source.sql new file mode 100644 index 000000000..ea04862e0 --- /dev/null +++ b/db/notice_source.sql @@ -0,0 +1,46 @@ +INSERT INTO notice_source + (code, name, url, created) +VALUES + ('Do','Gnome Do','http://do.davebsd.com/wiki/index.php?title=Microblog_Plugin', now()), + ('Facebook','Facebook','http://apps.facebook.com/identica/', now()), + ('Gwibber','Gwibber','http://launchpad.net/gwibber', now()), + ('HelloTxt','HelloTxt','http://hellotxt.com/', now()), + ('IdentiFox','IdentiFox','http://www.bitbucket.org/uncryptic/identifox/', now()), + ('LaTwit','LaTwit','http://latwit.mac65.com/', now()), + ('Nambu','Nambu','http://www.nambu.com/', now()), + ('Pikchur','Pikchur','http://www.pikchur.com/', now()), + ('Ping.fm','Ping.fm','http://ping.fm/', now()), + ('Twidge','Twidge','http://software.complete.org/twidge', now()), + ('Updating.Me','Updating.Me','http://updating.me/', now()), + ('betwittered','BeTwittered','http://www.32hours.com/betwitteredinfo/', now()), + ('bti','bti','http://gregkh.github.com/bti/', now()), + ('deskbar','Deskbar-Applet','http://www.gnome.org/projects/deskbar-applet/', now()), + ('identicatools','Laconica Tools','http://bitbucketlabs.net/laconica-tools/', now()), + ('identichat','identichat','http://identichat.prosody.im/', now()), + ('identitwitch','IdentiTwitch','http://richfish.org/identitwitch/', now()), + ('mbpidgin','mbpidgin','http://code.google.com/p/microblog-purple/', now()), + ('moconica','Moconica','http://moconica.com/', now()), + ('pocketwit','PockeTwit','http://code.google.com/p/pocketwit/', now()), + ('posty','Posty','http://spreadingfunkyness.com/posty/', now()), + ('royalewithcheese','Royale With Cheese','http://p.hellyeah.org/', now()), + ('rssdent','rssdent','http://github.com/zcopley/rssdent/tree/master', now()), + ('rygh.no','rygh.no','http://rygh.no/', now()), + ('ryghsms','ryghsms','http://sms.rygh.no/', now()), + ('smob','SMOB','http://smob.sioc-project.org/', now()), + ('spaz','Spaz','http://funkatron.com/spaz', now()), + ('tarpipe','tarpipe','http://tarpipe.com/', now()), + ('tjunar','Tjunar','http://nederflash.nl/boek/titels/tjunar-air', now()), + ('tr.im','tr.im','http://tr.im/', now()), + ('tweenky','Tweenky','http://beta.tweenky.com/', now()), + ('twhirl','Twhirl','http://www.twhirl.org/', now()), + ('twibble','twibble','http://www.twibble.de/', now()), + ('twidge','Twidge','http://software.complete.org/twidge', now()), + ('twidroid','twidroid','http://www.twidroid.com/', now()), + ('twittelator','Twittelator','http://www.stone.com/iPhone/Twittelator/', now()), + ('twitterfeed','twitterfeed','http://twitterfeed.com/', now()), + ('twitterphoto','TwitterPhoto','http://richfish.org/twitterphoto/', now()), + ('twitterpm','Net::Twitter','http://search.cpan.org/dist/Net-Twitter/', now()), + ('twittertools','Twitter Tools','http://wordpress.org/extend/plugins/twitter-tools/', now()), + ('twitux','Twitux','http://live.gnome.org/DanielMorales/Twitux', now()), + ('twitvim','TwitVim','http://vim.sourceforge.net/scripts/script.php?script_id=2204', now()), + ('urfastr','urfastr','http://urfastr.net/', now()); @@ -43,7 +43,11 @@ function handleError($error) return; } - common_log(LOG_ERR, "PEAR error: " . $error->getMessage()); + $logmsg = "PEAR error: " . $error->getMessage(); + if(common_config('site', 'logdebug')) { + $logmsg .= " : ". $error->getDebugInfo(); + } + common_log(LOG_ERR, $logmsg); $msg = sprintf(_('The database for %s isn\'t responding correctly, '. 'so the site won\'t work properly. '. 'The site admins probably know about the problem, '. @@ -61,6 +65,14 @@ function main() { global $user, $action; + if (!_have_config()) { + $msg = sprintf(_("No configuration file found. Try running ". + "the installation program first.")); + $sac = new ServerErrorAction($msg); + $sac->showPage(); + return; + } + // For database errors PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError'); diff --git a/install.php b/install.php new file mode 100644 index 000000000..0240349bb --- /dev/null +++ b/install.php @@ -0,0 +1,255 @@ +<? +define('INSTALLDIR', dirname(__FILE__)); + +function main() +{ + if (!checkPrereqs()) + { + return; + } + + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + handlePost(); + } else { + showForm(); + } +} + +function checkPrereqs() +{ + if (file_exists(INSTALLDIR.'/config.php')) { + ?><p class="error">Config file "config.php" already exists.</p> + <? + return false; + } + + if (version_compare(PHP_VERSION, '5.0.0', '<')) { + ?><p class="error">Require PHP version 5 or greater.</p><? + return false; + } + + $reqs = array('gd', 'mysql', 'curl', + 'xmlwriter', 'mbstring', + 'gettext'); + + foreach ($reqs as $req) { + if (!checkExtension($req)) { + ?><p class="error">Cannot load required extension "<?= $req ?>".</p><? + return false; + } + } + + if (!is_writable(INSTALLDIR)) { + ?><p class="error">Cannot write config file to "<?= INSTALLDIR ?>".</p> + <p>On your server, try this command:</p> + <blockquote>chmod a+w <?= INSTALLDIR ?></blockquote> + <? + return false; + } + + if (!is_writable(INSTALLDIR.'/avatar/')) { + ?><p class="error">Cannot write avatar directory "<?= INSTALLDIR ?>/avatar/".</p> + <p>On your server, try this command:</p> + <blockquote>chmod a+w <?= INSTALLDIR ?>/avatar/</blockquote> + <? + return false; + } + + return true; +} + +function checkExtension($name) +{ + if (!extension_loaded($name)) { + if (!dl($name.'.so')) { + return false; + } + } + return true; +} + +function showForm() +{ +?> +<p>Enter your database connection information below to initialize the database.</p> +<form method='post' action='install.php'> + <fieldset> + <ul class='form_data'> + <li> + <label for='sitename'>Site name</label> + <input type='text' id='sitename' name='sitename' /> + <p>The name of your site</p> + </li> + <li> + <li> + <label for='host'>Hostname</label> + <input type='text' id='host' name='host' /> + <p>Database hostname</p> + </li> + <li> + <label for='host'>Database</label> + <input type='text' id='database' name='database' /> + <p>Database name</p> + </li> + <li> + <label for='username'>Username</label> + <input type='text' id='username' name='username' /> + <p>Database username</p> + </li> + <li> + <label for='password'>Password</label> + <input type='password' id='password' name='password' /> + <p>Database password</p> + </li> + </ul> + <input type='submit' name='submit' value='Submit'> + </fieldset> +</form> +<? +} + +function updateStatus($status, $error=false) +{ +?> + <li> +<? + print $status; +?> + </li> +<? +} + +function handlePost() +{ +?> + <ul> +<? + $host = $_POST['host']; + $database = $_POST['database']; + $username = $_POST['username']; + $password = $_POST['password']; + $sitename = $_POST['sitename']; + + if (empty($host)) { + updateStatus("No hostname specified.", true); + showForm(); + return; + } + + if (empty($database)) { + updateStatus("No database specified.", true); + showForm(); + return; + } + + if (empty($username)) { + updateStatus("No username specified.", true); + showForm(); + return; + } + + if (empty($password)) { + updateStatus("No password specified.", true); + showForm(); + return; + } + + if (empty($sitename)) { + updateStatus("No sitename specified.", true); + showForm(); + return; + } + + updateStatus("Starting installation..."); + updateStatus("Checking database..."); + $conn = mysql_connect($host, $username, $password); + if (!$conn) { + updateStatus("Can't connect to server '$host' as '$username'.", true); + showForm(); + return; + } + updateStatus("Changing to database..."); + $res = mysql_select_db($database, $conn); + if (!$res) { + updateStatus("Can't change to database.", true); + showForm(); + return; + } + updateStatus("Running database script..."); + $res = runDbScript(INSTALLDIR.'/db/laconica.sql', $conn); + if ($res === false) { + updateStatus("Can't run database script.", true); + showForm(); + return; + } + foreach (array('sms_carrier' => 'SMS carrier', + 'notice_source' => 'notice source', + 'foreign_services' => 'foreign service') + as $scr => $name) { + updateStatus(sprintf("Adding %s data to database...", $name)); + $res = runDbScript(INSTALLDIR.'/db/'.$scr.'.sql', $conn); + if ($res === false) { + updateStatus(sprintf("Can't run %d script.", $name), true); + showForm(); + return; + } + } + updateStatus("Writing config file..."); + $sqlUrl = "mysqli://$username:$password@$host/$database"; + $res = writeConf($sitename, $sqlUrl); + if (!$res) { + updateStatus("Can't write config file.", true); + showForm(); + return; + } + updateStatus("Done!"); +?> + </ul> +<? +} + +function writeConf($sitename, $sqlUrl) +{ + $res = file_put_contents(INSTALLDIR.'/config.php', + "<?\n". + "\$config['site']['name'] = \"$sitename\";\n\n". + "\$config['db']['database'] = \"$sqlUrl\";\n\n"); + return $res; +} + +function runDbScript($filename, $conn) +{ + $sql = trim(file_get_contents($filename)); + $stmts = explode(';', $sql); + foreach ($stmts as $stmt) { + $stmt = trim($stmt); + if (!mb_strlen($stmt)) { + continue; + } + $res = mysql_query($stmt, $conn); + if ($res === false) { + return $res; + } + } + return true; +} + +?> +<html> +<head> + <title>Install Laconica</title> + <link rel="stylesheet" type="text/css" href="theme/base/css/display.css?version=0.7.1" media="screen, projection, tv"/> + <link rel="stylesheet" type="text/css" href="theme/base/css/modal.css?version=0.7.1" media="screen, projection, tv"/> + <link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.7.1" media="screen, projection, tv"/> +</head> +<body> + <div id="wrap"> + <div id="core"> + <div id="content"> + <h1>Install Laconica</h1> +<? main() ?> + </div> + </div> + </div> +</body> +</html>
\ No newline at end of file diff --git a/js/jcrop/jquery.Jcrop.go.js b/js/jcrop/jquery.Jcrop.go.js index b2737407b..a0399d540 100644 --- a/js/jcrop/jquery.Jcrop.go.js +++ b/js/jcrop/jquery.Jcrop.go.js @@ -37,10 +37,3 @@ $('#avatar_crop_w').val(c.w); $('#avatar_crop_h').val(c.h); }; - - function checkCoords() { - if (parseInt($('#avatar_crop_w').val())) return true; - alert('Please select a crop region then press submit.'); - return false; - }; - diff --git a/lib/action.php b/lib/action.php index 9c71a153d..812df635e 100644 --- a/lib/action.php +++ b/lib/action.php @@ -976,17 +976,17 @@ class Action extends HTMLOutputter // lawsuit } if ($have_before) { $pargs = array('page' => $page-1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; $this->elementStart('li', array('class' => 'nav_prev')); - $this->element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'prev'), + $this->element('a', array('href' => common_local_url($action, $args, $pargs), + 'rel' => 'prev'), _('After')); $this->elementEnd('li'); } if ($have_after) { $pargs = array('page' => $page+1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; $this->elementStart('li', array('class' => 'nav_next')); - $this->element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'next'), + $this->element('a', array('href' => common_local_url($action, $args, $pargs), + 'rel' => 'next'), _('Before')); $this->elementEnd('li'); } diff --git a/lib/clienterroraction.php b/lib/clienterroraction.php index 5019dc06d..0c48414d5 100644 --- a/lib/clienterroraction.php +++ b/lib/clienterroraction.php @@ -49,7 +49,7 @@ class ClientErrorAction extends ErrorAction function __construct($message='Error', $code=400) { parent::__construct($message, $code); - + $this->status = array(400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', @@ -72,7 +72,7 @@ class ClientErrorAction extends ErrorAction } // XXX: Should these error actions even be invokable via URI? - + function handle($args) { parent::handle($args); @@ -84,11 +84,16 @@ class ClientErrorAction extends ErrorAction } $this->message = $this->trimmed('message'); - + if (!$this->message) { - $this->message = "Client Error $this->code"; - } + $this->message = "Client Error $this->code"; + } $this->showPage(); } + + function title() + { + return $this->status[$this->code]; + } } diff --git a/lib/common.php b/lib/common.php index 4fc749ca0..f215192f4 100644 --- a/lib/common.php +++ b/lib/common.php @@ -73,6 +73,7 @@ $config = 'theme' => 'default', 'path' => $_path, 'logfile' => null, + 'logdebug' => false, 'fancy' => false, 'locale_path' => INSTALLDIR.'/locale', 'language' => 'en_US', @@ -178,12 +179,31 @@ if (strlen($_path) > 0) { $_config_files[] = INSTALLDIR.'/config.php'; +$_have_a_config = false; + foreach ($_config_files as $_config_file) { if (file_exists($_config_file)) { include_once($_config_file); + $_have_a_config = true; } } +function _have_config() +{ + global $_have_a_config; + return $_have_a_config; +} + +// XXX: Throw a conniption if database not installed + +// Fixup for laconica.ini + +$_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1); + +if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'])) { + $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini'; +} + // XXX: how many of these could be auto-loaded on use? require_once('Validate.php'); diff --git a/lib/groupsbymemberssection.php b/lib/groupsbymemberssection.php index 4fa07a244..5f26c6626 100644 --- a/lib/groupsbymemberssection.php +++ b/lib/groupsbymemberssection.php @@ -45,7 +45,7 @@ class GroupsByMembersSection extends GroupSection { function getGroups() { - $qry = 'SELECT user_group.*, count(*) as value ' . + $qry = 'SELECT user_group.id, count(*) as value ' . 'FROM user_group JOIN group_member '. 'ON user_group.id = group_member.group_id ' . 'GROUP BY user_group.id ' . diff --git a/lib/groupsbypostssection.php b/lib/groupsbypostssection.php index a5e33a93d..1a60ddb4f 100644 --- a/lib/groupsbypostssection.php +++ b/lib/groupsbypostssection.php @@ -45,7 +45,7 @@ class GroupsByPostsSection extends GroupSection { function getGroups() { - $qry = 'SELECT user_group.*, count(*) as value ' . + $qry = 'SELECT user_group.id, count(*) as value ' . 'FROM user_group JOIN group_inbox '. 'ON user_group.id = group_inbox.group_id ' . 'GROUP BY user_group.id ' . diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php index f05be85cb..5d68af28b 100644 --- a/lib/grouptagcloudsection.php +++ b/lib/grouptagcloudsection.php @@ -58,8 +58,14 @@ class GroupTagCloudSection extends TagCloudSection function getTags() { + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; + } + $qry = 'SELECT notice_tag.tag, '. - 'sum(exp(-(now() - notice_tag.created)/%s)) as weight ' . + $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'JOIN group_inbox on group_inbox.notice_id = notice.id ' . diff --git a/lib/personaltagcloudsection.php b/lib/personaltagcloudsection.php index 0882822db..978153a84 100644 --- a/lib/personaltagcloudsection.php +++ b/lib/personaltagcloudsection.php @@ -58,8 +58,14 @@ class PersonalTagCloudSection extends TagCloudSection function getTags() { - $qry = 'SELECT notice_tag.tag, '. - 'sum(exp(-(now() - notice_tag.created)/%s)) as weight ' . + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; + } + + $qry = 'SELECT notice_tag.tag, '. + $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'WHERE notice.profile_id = %d ' . diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index c7c7f0215..f7fb93554 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -48,10 +48,16 @@ class PopularNoticeSection extends NoticeSection { function getNotices() { - $qry = 'SELECT notice.*, '. - 'sum(exp(-(now() - fave.modified) / %s)) as weight ' . + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; + } + + $qry = 'SELECT notice.id, '. + $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . - 'GROUP BY fave.notice_id ' . + 'GROUP BY notice.id ' . 'ORDER BY weight DESC'; $offset = 0; diff --git a/lib/publicgroupnav.php b/lib/publicgroupnav.php index d72475e20..485d25e20 100644 --- a/lib/publicgroupnav.php +++ b/lib/publicgroupnav.php @@ -39,6 +39,7 @@ require_once INSTALLDIR.'/lib/widget.php'; * @category Output * @package Laconica * @author Evan Prodromou <evan@controlyourself.ca> + * @author Sarven Capadisli <csarven@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/ * @@ -73,23 +74,26 @@ class PublicGroupNav extends Widget $this->action->elementStart('ul', array('class' => 'nav')); - $this->out->menuItem(common_local_url('public'), _('Public'), - _('Public timeline'), $action_name == 'public', 'nav_timeline_public'); + if (Event::handle('StartPublicGroupNav', array($this))) { + $this->out->menuItem(common_local_url('public'), _('Public'), + _('Public timeline'), $action_name == 'public', 'nav_timeline_public'); - $this->out->menuItem(common_local_url('groups'), _('Groups'), - _('User groups'), $action_name == 'groups', 'nav_groups'); + $this->out->menuItem(common_local_url('groups'), _('Groups'), + _('User groups'), $action_name == 'groups', 'nav_groups'); - $this->out->menuItem(common_local_url('publictagcloud'), _('Recent tags'), - _('Recent tags'), $action_name == 'publictagcloud', 'nav_recent-tags'); + $this->out->menuItem(common_local_url('publictagcloud'), _('Recent tags'), + _('Recent tags'), $action_name == 'publictagcloud', 'nav_recent-tags'); - if (count(common_config('nickname', 'featured')) > 0) { - $this->out->menuItem(common_local_url('featured'), _('Featured'), - _('Featured users'), $action_name == 'featured', 'nav_featured'); - } + if (count(common_config('nickname', 'featured')) > 0) { + $this->out->menuItem(common_local_url('featured'), _('Featured'), + _('Featured users'), $action_name == 'featured', 'nav_featured'); + } - $this->out->menuItem(common_local_url('favorited'), _('Popular'), - _("Popular notices"), $action_name == 'favorited', 'nav_timeline_favorited'); + $this->out->menuItem(common_local_url('favorited'), _('Popular'), + _("Popular notices"), $action_name == 'favorited', 'nav_timeline_favorited'); + Event::handle('EndPublicGroupNav', array($this)); + } $this->action->elementEnd('ul'); } } diff --git a/lib/router.php b/lib/router.php index 4b70c0150..da57f8417 100644 --- a/lib/router.php +++ b/lib/router.php @@ -228,14 +228,15 @@ class Router // users - $m->connect('api/users/show/:argument', + $m->connect('api/users/:method/:argument', array('action' => 'api', - 'apiaction' => 'users')); + 'apiaction' => 'users'), + array('method' => 'show(\.(xml|json))?')); $m->connect('api/users/:method', array('action' => 'api', 'apiaction' => 'users'), - array('method' => 'show(\.(xml|json|atom|rss))?')); + array('method' => 'show(\.(xml|json))?')); // direct messages @@ -304,11 +305,11 @@ class Router } // account - + $m->connect('api/account/:method', array('action' => 'api', 'apiaction' => 'account')); - + // favorites $m->connect('api/favorites/:method/:argument', @@ -393,6 +394,8 @@ class Router array('action' => 'showstream'), array('nickname' => '[a-zA-Z0-9]{1,64}')); + Event::handle('RouterInitialized', array($m)); + return $m; } diff --git a/lib/servererroraction.php b/lib/servererroraction.php index 80a3fdd7b..595dcf147 100644 --- a/lib/servererroraction.php +++ b/lib/servererroraction.php @@ -42,7 +42,7 @@ require_once INSTALLDIR.'/lib/error.php'; * says that 500 errors should be treated similarly to 400 errors, and * it's easier to give an HTML response. Maybe we can customize these * to display some funny animal cartoons. If not, we can probably role - * these classes up into a single class. + * these classes up into a single class. * * See: http://tools.ietf.org/html/rfc2616#section-10 * @@ -57,19 +57,19 @@ class ServerErrorAction extends ErrorAction function __construct($message='Error', $code=500) { parent::__construct($message, $code); - + $this->status = array(500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported'); - + $this->default = 500; } // XXX: Should these error actions even be invokable via URI? - + function handle($args) { parent::handle($args); @@ -81,12 +81,16 @@ class ServerErrorAction extends ErrorAction } $this->message = $this->trimmed('message'); - + if (!$this->message) { - $this->message = "Server Error $this->code"; - } + $this->message = "Server Error $this->code"; + } $this->showPage(); } - + + function title() + { + return $this->status[$this->code]; + } } diff --git a/lib/twitterapi.php b/lib/twitterapi.php index a4d183fcd..74f265cbb 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -60,20 +60,34 @@ class TwitterapiAction extends Action function twitter_status_array($notice, $include_user=true) { - $profile = $notice->getProfile(); $twitter_status = array(); $twitter_status['text'] = $notice->content; $twitter_status['truncated'] = 'false'; # Not possible on Laconica $twitter_status['created_at'] = $this->date_twitter($notice->created); - $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? intval($notice->reply_to) : null; + $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? + intval($notice->reply_to) : null; $twitter_status['source'] = $this->source_link($notice->source); $twitter_status['id'] = intval($notice->id); - $twitter_status['in_reply_to_user_id'] = ($notice->reply_to) ? $this->replier_by_reply(intval($notice->reply_to)) : null; + + $replier_profile = null; + + if ($notice->reply_to) { + $reply = Notice::staticGet(intval($notice->reply_to)); + if ($reply) { + $replier_profile = $reply->getProfile(); + } + } + + $twitter_status['in_reply_to_user_id'] = + ($replier_profile) ? intval($replier_profile->id) : null; + $twitter_status['in_reply_to_screen_name'] = + ($replier_profile) ? $replier_profile->nickname : null; if (isset($this->auth_user)) { - $twitter_status['favorited'] = ($this->auth_user->hasFave($notice)) ? 'true' : 'false'; + $twitter_status['favorited'] = + ($this->auth_user->hasFave($notice)) ? 'true' : 'false'; } else { $twitter_status['favorited'] = 'false'; } @@ -137,7 +151,6 @@ class TwitterapiAction extends Action function twitter_dmsg_array($message) { - $twitter_dm = array(); $from_profile = $message->getFrom(); @@ -386,23 +399,7 @@ class TwitterapiAction extends Action $t = strtotime($dt); return date("D M d G:i:s O Y", $t); } - - function replier_by_reply($reply_id) - { - $notice = Notice::staticGet($reply_id); - if ($notice) { - $profile = $notice->getProfile(); - if ($profile) { - return intval($profile->id); - } else { - common_debug('Can\'t find a profile for notice: ' . $notice->id, __FILE__); - } - } else { - common_debug("Can't get notice: $reply_id", __FILE__); - } - return null; - } - + // XXX: Candidate for a general utility method somewhere? function count_subscriptions($profile) { diff --git a/lib/util.php b/lib/util.php index 18e4f310c..f9a787d47 100644 --- a/lib/util.php +++ b/lib/util.php @@ -81,7 +81,7 @@ function common_language() // If there is a user logged in and they've set a language preference // then return that one... - if (common_logged_in()) { + if (_have_config() && common_logged_in()) { $user = common_current_user(); $user_language = $user->language; if ($user_language) @@ -315,6 +315,10 @@ function common_current_user() { global $_cur; + if (!_have_config()) { + return null; + } + if ($_cur === false) { if (isset($_REQUEST[session_name()]) || (isset($_SESSION['userid']) && $_SESSION['userid'])) { diff --git a/scripts/SearchMonkey-Om3.0.txt b/scripts/SearchMonkey-Om3.0.txt new file mode 100644 index 000000000..45b782d0b --- /dev/null +++ b/scripts/SearchMonkey-Om3.0.txt @@ -0,0 +1 @@ +BE9KrPPSJAPljm0ykS59yJQmWBFY9RPVJFhZsiF_5Wcf_tkGwf4FP2Ncjs7qGfHFCb2pv.eDr5y0zhKrF4s3ugs89DbLaA.hrbRJwglsNym5TDwDycrGw3TvjfCVmHBx4VzOZ2QzUyXBIs0T30paT6PYQfARKBdMkieKbbQ1tfl.f.ul35_kcpoXZt_lTDWFDaia2RM41uDLHJyVbCcRkqfHCLabgNeOq_MGFXGA6DjnKQx7TNyQe.2N6IyVd1quVapHn6jUOsWNkahehPMHtO72yvPpugS0UHCKBqcd.UCcbIhmtzLnKoBQAH2AJqUrmfg1XRwqFvTo6y9Z5XmDQK2hRnv97InV5he1AMIqNUotAcIrYjq5Tn42whYsznnMYhMY44UqZGoJI_ZwsSvnH6Je.AhKU3hBW9Tsmggpxgnhx_o2vhyNw2QAgPJng0FKxaevCmPnFtLntwluhxLbiTo2IiIotP4VjIVKs76hHzAsmXYuvS01OU.XB43Gmcw5yP9OUIoh5fEA1ANxOb.ba8aVxu2FdvedbOECgO6gvr.kYilrdxwwnVbHwVP6esrOiYE32dRs0_tWdgfvJfyloLjj_M5stZLEBcVfoUSQHsxX6jW5jrs4BTEHhKrxlOzdBt8f8T2E6eA9x2h7B8zK4eRtC2NBrcj1jzYCVWUT7IdbN05NZBjGYvxtmX1KRW91QwdFXgytfOINFkDk0scNCGGt4OYDzKLJ7sRBy0iKhHNfTC3noUhWf1372uXQ_yiWDWB7cTfxF9meAU3TWrTS7DjGTkwLvCVUJ43QyCxBQd1jWU6sp_VvytDeHx7cqrkNsa3JRN9dht3POqq_mVL0c5MX_XRpV8O.tPSGmfUPUrR5qnV8Z739D6PGWkOQzfzTTv6vGkf4jj1xyDEfUqr767_yL7gHeI2VlbdD2ammzwEhRK9f8ME8FbrZTTgX1OD0.v1cFULt1lew.rtCOtKf4F2MBbi90edst.TpOoUh_TvFkgKf0zgteNo2JjzrmCO.uviLCM2weGksARL70mdU6W9N932YWr6E8HbUc02S8ifSnbMpiUTHwNzMErsg7BSyRVJngGLDreBkBEIjXkNoApJR7kMPMaYVwtvjU.8wLmyFLZ.PHqqcrADTr7R50hL3UKj1mLsL19gQL3cP9J7_zJJM4Q1GDj2dPWBLhJMosUVhW8XBFPhW0aEdmgqhpsAJ_qv52xfjBeEPyPmKHu1p.1G2QEmOqFm_swbVAPHnra5zd8x4OOlHGFeL3qPLW9_LXN46chs6cOpUdYaWRzT2YuOUHHE8RDV9Mev22p7WjrbgC8hY3wK55Cpw_fCekaHcJX2jU3FPl09httjI1i5yGU04yD5MpOQF5EadbSlfjDEg8H.GoOFZcyKKDnqj_8SYdrXWq4aTqAnWgvBPh.bznvmevDgEpH.9gtzLcao4Dzmk.K0PnRgvkzyaN5IGk60TiD4Fk0u3f4bqKaPCOIKCTajbNGIasyND0J5ROtAa_IlXljCpzeEYPhSASSFV6fWmlqHFiGa2cKlLNr157MAUVQg52dJRRyid1YDcHK8ZuMc4BX8QA0olb2CDbUHKxxwv0zbIsgUTL8gvKIAPwBfF0cPfV9v6Phs1rPFXnysxdnunXnr6r6ZCN00rZeA7XbH68f.UjW0.ERGvB72kMnB8fBhfEgD22Y0ZFkwxI00UVAm5yiwkjYx86EdCpkMLBVDR1kWictX04pFLzxZK8iRflPBy74Nx2SFO19qJFnQmKEV2IN2wlrH6z14902LEI2Vuh_dVxNphr1k5mJ9x2VNGmvol.vvHmaLCufHIrOMRkAFMxeP37Mnzyk6NpxAQbdV0KwC.YTfoK9Y5knYAherlh7x8NqELX6XqutF2Lm11dikoK8Yu8u3Rkhoaef00PISV0LOb0E.D1LRjFFGzUCt5Ezcq68Tt0rFNEF1gm5Xl9Rygln_67F0KMgacpKTJ2PBIqcteyRZoRohFBRUTLkKn784KacSBsWFkogD5n7blv943wWeZFvUcKsFyYZny1WLvGEQX01kbjyaDCLDxiEQWSvlDuD.2wOra0JO5.Bo2PpPK5tbNexZDVx3k1yb48ev2UC4J4IlD6oK1KYe46Y.7NX9kDYCcdRiQOVnLJ4PSbPhDW0hcE2SNtxmFdpAf2xQOiekXY35lkuNxvebVhKuoFWxUgQmFEfreJQsC5qf_dunxGquD6u3SXnLbTg8aNWZqtR74dr3s7C5kwBK6eBGwJfkAx8Z2JKwLr5QHdISfa0wLl7aIejz5Mg_tfeATLIwW8SiIQdJiZ992Bx1k_50XQVeHOdyEc8J1Tjnkrji_ZY9PFn3AZc94wXD8erpANuJIbDIdLUp1idqF_TDtmqSK2qQgz26IkewcZnSIQnm98qxkHf9DAIbE6_GUP0ZeWqLQrn0CdhejhOPsKsovcDI7zBHMQABquMeBh9YC1.QCO9br6YmYEAV30n5IsZgl5PRiRDjkhXv8VaE.fnRNndSy7BX6kmxSmDWQfY0FvbUBWBQm7tfU3Mrk2Ojm4ALIYUZnJxl.5xj6VvD.2ZX3ug_1zo7mAiAYG_F939DMccfgCVFUcdtbF9Q9YFeC2bVMfgX5gA75nBCu5R8KopeWfTjdqZBtJoT6HxFmCSLQqIdjrxD7X2RapCI0QoDsp9xyzRZJ5NF5ygVBJqtNn2lAwFENasqFvGRSb35B.sjTQoHW5WBoBjFy5tNF1vWYJENfKRjWn5Pr0FvFdQfBKqeiWrLtStAnGrd49frviyK5VtYa.eSuRyX32SGb7.Pxo0Hf0bhER4uvPBktf3ec5UjL_xRI3eQ__F7tRiGu2tRYIUYcUkhLKAGYoDx2_gdMOXcow5W3KwtuVNtZ4UMRmuB3ccyBUzDTRWNLFISq56JXU46_v7ANub44kTLDfGuJExu.0NaOuW6isndAIYslJlcCs6NJ6j_6Ag55G.UhQFfzDKVOEt.L
\ No newline at end of file diff --git a/scripts/SearchMonkey-yQP.0.txt b/scripts/SearchMonkey-yQP.0.txt new file mode 100644 index 000000000..e42a04e16 --- /dev/null +++ b/scripts/SearchMonkey-yQP.0.txt @@ -0,0 +1 @@ +bzN6aQzSJBM8jb6JDpNRvtfEMpxOC6r2ffo5VJf0ah_Q3kXs8gwvDzGy0KGHkwDDijfnJAwhb.BIcFihUZVWe.vAy2xZZN8XUMxHwc16HwCsgDyOC9sH5WzOV0dvJcVZ.9ipAgI7RuXsAvZdJv90N89iOh1WmD6QwWyzyvnu.FjQDrQH1DlGwFs3ZNzY5lsd5uYhtJ3puBXrzSmGcR68_7OEw4QzAV9SyPSHSskXF56cpH8pUey8WiQieM4X_uuKsMjQfWEUdqNb6teXDplvPDRqHwP5rC6X1_oHBiocfgWiBfUfKOXE1g5J.JtqXYIBee8ROyx3sVIc7V2I0eotZCCiCJ1k74ru2OGC9UhX__ZESGrp9b0JZGZFO6w97IL1Y3BTgVXNox8L3FcFjl11s7YcYBhc_3e3WbJA4pZzczPzd0ouZiCjUcBCZXNu6fnM6XerBbsVj584ZbPdjQ6A5TcrED8dTcFdgfMWlMu7bHsE7e0QIJYmc2g5NWeur2ovAOPVxhELrvnJ6X6Z.06vAmwdJcl4hyYRVqA.9QynHlH2dezXS5y0eKXFUzg.tHNqZboEGutLL316mZQYvwZwATZFc8iO3EuiNV3MWbiCrLX.n3nbXp82A4v7Bv.PVJoeOTmiPmq8vuxts8nUEPf7gA3j6.DmlDvfZQNx9.WNmNFps0B08hzDMvKX98.ft9.GJlftPCYCk2qHRtWm3tjB2R9O6mF6XYvOLUK7aQ4rz5oCxHwmrF.n56G07MS5GS1pjV3ByUO88PI1i_rPbim_Up0jIO5q7PqXudyFE.nG0Dc8yaExZk7PryBfSHk2yMQVXcBjy3XQBVmrIwPwKs.YUFC1qLSThfA8UNckik2xuDZKvf29xpGvHlMbH67UV5HhY5CTeqlgvapRThmfrexqaBTTPPqR.Sy3Pvr9vHX.0UC6kNCTlxW3CExrx9EipRKUvRVClNLEG6M9hm5MQkdfgmd2Dmj5DmjcrZkWOqnNfLn_mtYdoD3nK4zCk.NZwXTFlx5FVr5bOzyncalNdb77qLEH9E9R8d2KUA4Axljx29kycILhZCvy3Qz22Vz_M72lVFKQAFnGlERRS7NLu2rB00e.MNeH9aB01uj.y9UHpfjTAwOJSFEBf7yKRCkVzqFpGAQo7txlC3NRgSyI3kQtW0WeWiNzghBv8c_5iXWkXqFyRfVZUCw2qqow3BF6SDtkhXAr8d.JrprGdG67U66ZD3JB10OLmmAaDiiCr81eVOkrsz3ONdigZOlP7RrYtodAORnheCZ10SAYbaru0sKmsJx4sB41QKn79dieWs5oihI5Rr3jUzPjfYgav5jeEfUYz5qHTtmps4vVJjt9s4zueRiT8AYzg.Xv.wdC1dvBr_kpGxwrkMEZJ0QfZkH.TDWBSWyxeG9gtuKd1gy9CGQTXlLvonJWHwK9gwWZwRKIanV4gnMfWz4pvhGixzEaiRU6g9giKYHpVKe.w0cwPfSDIhbBYqrlvuxkSTXfuFNyTpHM0Mgc6PMNnH6GooeLVK3IO2M8dRdDbL7EHykIJWe85pm5BxSqFTcWXn1nGuVWQV.F.J1XYJj1KheT725MVRlrE3sH.MgY6m4hKCUXT7mIgJ6xsfAQ8dWn7V1fCpqoIYub55iw_dg8yfZ7Yfgwj9bqN81lvTWQzBMLKYpG6pOh37JsTikpXa9kTSJfbJm0_GYZv_Bu10D1WqiO0UCvJXrlqkl5F610fkXkhwRXvmIQL2Mv_R71zSKqMr1g5RmnNifUv43jpXoOWmOKscg59pv8eOyb2JG26BtyVS2XOTDw6pHpHKuksqRKt62i1z83uv_ve5rO0zIKeMnWGlvXKHn8ld3fqGyJvqZ7wqYpnV_LTE3p73XCLEeniClXyk5Q_Icu1PgakYh3GIz8RVBjbjgrZIsvvkEp0Kgeo6oFY0wnboIwDlaUVHIue1nPkuAIsVk9i_IJWeqoRV0eO0wUGWgQ5.HT9RzcKdFVe2kl84RKuQkvoibiCfGlfTXpOfLOZtwsfl2TuNgZtP5oG1Wfsgi6g2a1N8B2WHYN8kZuG8pMnc4NQDIoO8BDnz89lDt7Y9JCslIM3O2Y25EGsylNKamKPJZr.ZSvvTVJG5sxftLxvF8vc8h5_pJD9Akj.84CjqQyfsnzFqc_.EqBaRVSy35wHHrdWTBsvjcobtSed8wXs.5En6HdubdATcgthozHWMEMsUdA29XkenPic2cR.8bQ5VdGZ2_YkJIXrxgt_XoEFFB8tgy061cghyL2fc2fHMQm4KBEc1vjkZjwRo9adWbg9dzAl782AwKC.C72bw--
\ No newline at end of file diff --git a/theme/base/css/mobile.css b/theme/base/css/mobile.css index 3d0455a67..eee98317c 100644 --- a/theme/base/css/mobile.css +++ b/theme/base/css/mobile.css @@ -2,14 +2,21 @@ * * @package Laconica * @author Meitar Moscovitz <meitar@maymay.net> + * @author Sarven Capadisli <csarven@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/ */ -/* Go linear. */ +body { +font-size:2.5em; +} + +#wrap { +width:95%; +} + #header, #header address, -#site_nav_global_primary, #anon_notice, #site_nav_local_views .nav, #form_notice, @@ -24,49 +31,120 @@ .notice .notice-options a, .pagination, .pagination .nav, -.aside .section { float: none; } +.aside .section { +float:none; +} .notice-options .notice_reply, .notice-options .notice_delete, .notice-options .form_favor, -.notice-options .form_disfavor { position: static; } +.notice-options .form_disfavor { +position:static; +} #form_notice, #anon_notice, -#content_inner, -#footer { width: auto; } - -/* And liquid. */ -#wrap { width: 95%; } - -/* Make things bigger on smaller screens. */ -body { font-size: 2em; } -.notices { font-size: 1.5em; } - -#site_nav_global_primary, #site_nav_global_secondary { text-align: center; } - -.notice div.entry-content { margin-left: 0; } -address { margin: 0; } - -#anon_notice, #footer { clear: left; font-size: .5em; } - -#form_notice textarea { width: 80%; height: 5em; } -#form_notice .form_note { right: 20%; top: 6em; } -#form_notice .form_actions input.submit { width: auto; } - -#content { padding: 18px 0; width: 100%; } -#content h1, #page_notice, #content_inner { padding: 0 18px; } -.notices .entry-title, .notices div.entry-content { width: 90%; } -.notice .author .photo { height: 4.5em; width: 4.5em; } /* about double physical size; TODO: do this scaling better */ -.notice-options { position: absolute; top: 0; right: 0; padding-left: 7%; width: 3%; } -.notice-options .notice_delete a { float: left; } /* Works, but feels like it shouldn't. */ -/* TODO: Make the icons of the notice options bigger. Probably with mobile-specific images. */ -.pagination .nav { overflow: auto; } - -#aside_primary { margin: 10px 0 0 0; border: none; padding: 0; width: 100%; } -#popular_notices { float: none; width: auto; } -/* Columns for supplemental info. */ -.aside .section { clear: none; padding: 9px; width: 45%; } -#top_groups_by_post { float: left; } -#featured_users { float: right; } -#export_data { display: none; } +#footer, +#form_notice .form_actions input.submit { +width:auto; +} + +.form_settings label { +width:25%; +} +.form_settings .form_data p.form_guide { +margin-left:26%; +} + +#site_nav_global_primary { +width:75%; +} + +.entity_profile { +width:65%; +} +.entity_actions { +margin-left:0; +} + +#form_notice, +#anon_notice { +clear:both; +} + +#content, +#aside_primary { +width:96%; +padding-left:2%; +padding-right:2%; +} + +#site_notice { +position:static; +float:right; +clear:right; +width:75%; +margin-right:0; +margin-bottom:11px; +} + +.notices { +font-size:1.5em; +} + +#form_notice textarea { +width:80%; +height:5em; +} +#form_notice .form_note { +right:20%; +top:6em; +} + + +.vcard .photo, +.section .vcard .photo { +margin-right:18px; +} +.notice, +.profile { +margin-bottom:18px; +} + +.notices .entry-title, +.notices div.entry-content { +width:90%; +} +.notice div.entry-content { +margin-left:0; +} + +.notice .author .photo { +height:4.5em; +width:4.5em; +} +.notice-options { +position:absolute; +top:0; +right:0; +padding-left:7%; +width:3%; +} + +.notice-options .notice_delete a { +float:left; +} +.pagination .nav { +overflow:auto; +} + +#export_data { +display:none; +} + +#site_nav_local_views li { +margin-right:4px; +} +#site_nav_local_views a { +padding:18px 11px; +} |