forked from GNUsocial/gnu-social
Merge branch '0.8.x' of git://gitorious.org/laconica/dev into dev/0.8.x
This commit is contained in:
commit
003c63e587
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,8 +1,10 @@
|
||||
avatar/*
|
||||
files/*
|
||||
_darcs/*
|
||||
logs/*
|
||||
config.php
|
||||
.htaccess
|
||||
httpd.conf
|
||||
*.tmproj
|
||||
dataobject.ini
|
||||
*~
|
||||
@ -10,3 +12,7 @@ dataobject.ini
|
||||
*.orig
|
||||
*.rej
|
||||
.#*
|
||||
*.swp
|
||||
.buildpath
|
||||
.project
|
||||
.settings
|
||||
|
35
EVENTS.txt
35
EVENTS.txt
@ -82,3 +82,38 @@ StartNoticeSave: before inserting a notice (good place for content filters)
|
||||
EndNoticeSave: after inserting a notice and related code
|
||||
- $notice: notice that was saved (with ID and URI)
|
||||
|
||||
StartShowLocalNavBlock: Showing the local nav menu
|
||||
- $action: the current action
|
||||
|
||||
EndShowLocalNavBlock: At the end of the local nav menu
|
||||
- $action: the current action
|
||||
|
||||
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
|
||||
|
||||
StartSubGroupNav: Showing the subscriptions group nav menu
|
||||
- $action: the current action
|
||||
|
||||
EndSubGroupNav: At the end of the subscriptions 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
|
||||
|
||||
StartLogout: Before logging out
|
||||
- $action: the logout action
|
||||
|
||||
EndLogout: After logging out
|
||||
- $action: the logout action
|
||||
|
||||
ArgsInitialized: After the argument array has been initialized
|
||||
- $args: associative array of arguments, can be modified
|
||||
|
278
README
278
README
@ -2,8 +2,8 @@
|
||||
README
|
||||
------
|
||||
|
||||
Laconica 0.7.1 ("West of the Fields")
|
||||
6 February 2009
|
||||
Laconica 0.7.3 ("You Are The Everything")
|
||||
7 April 2009
|
||||
|
||||
This is the README file for Laconica, the Open Source microblogging
|
||||
platform. It includes installation instructions, descriptions of
|
||||
@ -71,54 +71,29 @@ for additional terms.
|
||||
New this version
|
||||
================
|
||||
|
||||
This is a minor bug-fix release since version 0.7.0, released Jan 29
|
||||
2009. Notable changes this version:
|
||||
This is a minor bug-fix and feature release since version 0.7.2.1,
|
||||
released Mar 11 2009. Notable changes this version:
|
||||
|
||||
- Vast improvement in auto-linking to URLs.
|
||||
- Link to group search from user's group page
|
||||
- Improved interface in Facebook application
|
||||
- Fix bad redirects in delete notice
|
||||
- Updated PostgreSQL database creation script
|
||||
- Show filesize in avatar/logo upload
|
||||
- Vastly improved avatar/logo upload
|
||||
- Allow re-authentication with OpenID
|
||||
- Correctly link hashtabs inside parens and brackets
|
||||
- Group and avatar image transparency works
|
||||
- Better handling of commands through the Web and Ajax channels
|
||||
- Fix links for profile page feeds
|
||||
- Fixed destroy method in API
|
||||
- Fix endpoint of Connect menu when XMPP disabled
|
||||
- Show number of group members
|
||||
- Enable configuration files in /etc/laconica/
|
||||
|
||||
Changes in version 0.7.0:
|
||||
|
||||
- Support for groups. Users can join groups and send themed notices
|
||||
to those groups. All other members of the group receive the notices.
|
||||
- Laconica-specific extensions to the Twitter API.
|
||||
- A Facebook application.
|
||||
- A massive UI redesign. The HTML generated by Laconica has changed
|
||||
significantly, to make theming easier and to give a more open look
|
||||
by default. Also, sidebar.
|
||||
- Massive code hygiene changes to move towards compliance with the PEAR
|
||||
coding standards and to support the new UI redesign.
|
||||
- Began the breakup of util.php -- moved about 30% of code to a views
|
||||
hierarchy.
|
||||
- UI elements for statistical information (like top posters or most
|
||||
popular groups) added in a sidebar.
|
||||
- include Javascript badge by Kent Brewster.
|
||||
- Updated online documentation.
|
||||
- Cropping of user avatars using Jcrop.
|
||||
- fix for Twitter bridge to not send "Expect:" headers.
|
||||
- add 'dm' as a synonym for 'd' in commands.
|
||||
- Upgrade upstream version of jQuery to 1.3.
|
||||
- Upgrade upstream version of PHP-OpenID to 2.1.2.
|
||||
- Move OpenMicroBlogging specification to its own repository.
|
||||
- Make tag-based RSS streams work.
|
||||
- Additional locales: Bulgarian, Catalan, Greek, Hebrew, simplified
|
||||
Chinese, Telugu, Taiwanese Chinese, Vietnamese,
|
||||
- PostgreSQL updates.
|
||||
- Nasty bug in Twitter bridge that wouldn't verify with Twitter
|
||||
- A plugin to allow a templating language for customization
|
||||
- A plugin for Piwik Analytics engine
|
||||
- A bookmarklet for posting a notice about a Web page you're reading
|
||||
- A welcome notice ('welcomebot') and default subscription for new users
|
||||
- Support for SSL for some or all pages on the site
|
||||
- Better handling of empty notice lists on many pages
|
||||
- Major improvements to the Twitter friend-sync offline processing
|
||||
- subscribers, subscriptions, groups are listed on the Personal page.
|
||||
- "Invite" link restored to main menu
|
||||
- Better memory handling in FOAF output
|
||||
- Fix for SUP support (FriendFeed)
|
||||
- Correct and intelligent redirect HTTP status codes
|
||||
- Fix DB collations for search and sort
|
||||
- Better H1s and Titles using user full names
|
||||
- Fixes to make the linkback plugin operational
|
||||
- Better indication that a notice is being published by Ajax (spinner)
|
||||
- Better and unified Atom output
|
||||
- Hiding "register" and "join now" messages when site is closed
|
||||
- ping, twitter and facebook queuehandlers working better
|
||||
- Updated RPM spec
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
@ -222,9 +197,9 @@ especially if you've previously installed PHP/MySQL packages.
|
||||
1. Unpack the tarball you downloaded on your Web server. Usually a
|
||||
command like this will work:
|
||||
|
||||
tar zxf laconica-0.7.1.tar.gz
|
||||
tar zxf laconica-0.7.3.tar.gz
|
||||
|
||||
...which will make a laconica-0.7.1 subdirectory in your current
|
||||
...which will make a laconica-0.7.3 subdirectory in your current
|
||||
directory. (If you don't have shell access on your Web server, you
|
||||
may have to unpack the tarball on your local computer and FTP the
|
||||
files to the server.)
|
||||
@ -232,7 +207,7 @@ especially if you've previously installed PHP/MySQL packages.
|
||||
2. Move the tarball to a directory of your choosing in your Web root
|
||||
directory. Usually something like this will work:
|
||||
|
||||
mv laconica-0.7.1 /var/www/mublog
|
||||
mv laconica-0.7.3 /var/www/mublog
|
||||
|
||||
This will make your Laconica instance available in the mublog path of
|
||||
your server, like "http://example.net/mublog". "microblog" or
|
||||
@ -240,21 +215,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
|
||||
3. Make your target directory writeable by the Web server.
|
||||
|
||||
chmod a+w /var/www/mublog/
|
||||
|
||||
On some systems, this will probably work:
|
||||
|
||||
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 "mublog" and add the Web server's user to the group.
|
||||
|
||||
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
|
||||
|
||||
On some systems, this will probably work:
|
||||
You can also make the avatar directory writeable by the Web server
|
||||
group, as noted above.
|
||||
|
||||
chgrp www-data /var/www/mublog/avatar
|
||||
chmod g+w /var/www/mublog/avatar
|
||||
|
||||
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.
|
||||
|
||||
4. Create a database to hold your microblog data. Something like this
|
||||
5. Create a database to hold your microblog data. Something like this
|
||||
should work:
|
||||
|
||||
mysqladmin -u "username" --password="password" create laconica
|
||||
@ -267,63 +249,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).
|
||||
username and password. You may want to test logging in to MySQL as
|
||||
this new user.
|
||||
|
||||
7. Copy the config.php.sample in the Laconica directory to config.php.
|
||||
7. In a browser, navigate to the Laconica install script; something like:
|
||||
|
||||
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.
|
||||
http://yourserver.example.com/mublog/install.php
|
||||
|
||||
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.
|
||||
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
|
||||
@ -348,10 +322,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
|
||||
------
|
||||
|
||||
@ -511,7 +481,7 @@ server is probably a good idea for high-volume sites.
|
||||
needs as a parameter the install path; if you run it from the
|
||||
Laconica dir, "." should suffice.
|
||||
|
||||
This will run six (for now) queue handlers:
|
||||
This will run eight (for now) queue handlers:
|
||||
|
||||
* xmppdaemon.php - listens for new XMPP messages from users and stores
|
||||
them as notices in the database.
|
||||
@ -525,6 +495,10 @@ This will run six (for now) queue handlers:
|
||||
of registered users.
|
||||
* xmppconfirmhandler.php - sends confirmation messages to registered
|
||||
users.
|
||||
* twitterqueuehandler.php - sends queued notices to Twitter for user
|
||||
who have opted to set up Twitter bridging.
|
||||
* facebookqueuehandler.php - sends queued notices to Facebook for users
|
||||
of the built-in Facebook application.
|
||||
|
||||
Note that these queue daemons are pretty raw, and need your care. In
|
||||
particular, they leak memory, and you may want to restart them on a
|
||||
@ -557,6 +531,53 @@ 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
|
||||
-----------------------------
|
||||
|
||||
Laconica's Facebook application allows your users to automatically
|
||||
update their Facebook statuses with their latest notices, invite
|
||||
their friends to use the app (and thus your site), view their notice
|
||||
timelines, and post notices -- all from within Facebook. The application
|
||||
is built into Laconica and runs on your host. For automatic Facebook
|
||||
status updating to work you will need to enable queuing and run the
|
||||
facebookqueuehandler.php daemon (see the "Queues and daemons" section
|
||||
above).
|
||||
|
||||
Quick setup instructions*:
|
||||
|
||||
Install the Facebook Developer application on Facebook:
|
||||
|
||||
http://www.facebook.com/developers/
|
||||
|
||||
Use it to create a new application and generate an API key and secret.
|
||||
Uncomment the Facebook app section of your config.php and copy in the
|
||||
key and secret, e.g.:
|
||||
|
||||
# Config section for the built-in Facebook application
|
||||
$config['facebook']['apikey'] = 'APIKEY';
|
||||
$config['facebook']['secret'] = 'SECRET';
|
||||
|
||||
In Facebook's application editor, specify the following URLs for your app:
|
||||
|
||||
- Callback URL: http://example.net/mublog/facebook/
|
||||
- Post-Remove URL: http://example.net/mublog/facebook/remove
|
||||
- Post-Add Redirect URL: http://apps.facebook.com/yourapp/
|
||||
- Canvas URL: http://apps.facebook.com/yourapp/
|
||||
|
||||
(Replace 'example.net' with your host's URL, 'mublog' with the path
|
||||
to your Laconica installation, and 'yourapp' with the name of the
|
||||
Facebook application you created.)
|
||||
|
||||
Additionally, Choose "Web" for Application type in the Advanced tab.
|
||||
In the "Canvas setting" section, choose the "FBML" for Render Method,
|
||||
"Smart Size" for IFrame size, and "Full width (760px)" for Canvas Width.
|
||||
Everything else can be left with default values.
|
||||
|
||||
*For more detailed instructions please see the installation guide on the
|
||||
Laconica wiki:
|
||||
|
||||
http://laconi.ca/trac/wiki/FacebookApplication
|
||||
|
||||
Sitemaps
|
||||
--------
|
||||
|
||||
@ -597,7 +618,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.
|
||||
|
||||
@ -676,7 +697,7 @@ Upgrading
|
||||
If you've been using Laconica 0.6, 0.5 or lower, or if you've been
|
||||
tracking the "git" version of the software, you will probably want
|
||||
to upgrade and keep your existing data. There is no automated upgrade
|
||||
procedure in Laconica 0.7.1. Try these step-by-step instructions; read
|
||||
procedure in Laconica 0.7.3. Try these step-by-step instructions; read
|
||||
to the end first before trying them.
|
||||
|
||||
0. Download Laconica and set up all the prerequisites as if you were
|
||||
@ -703,16 +724,19 @@ to the end first before trying them.
|
||||
directory to your new directory.
|
||||
9. Copy htaccess.sample to .htaccess in the new directory. Change the
|
||||
RewriteBase to use the correct path.
|
||||
10. Rebuild the database. Go to your Laconica directory and run the
|
||||
rebuilddb.sh script like this:
|
||||
10. Rebuild the database. For MySQL, go to your Laconica directory and
|
||||
run the rebuilddb.sh script like this:
|
||||
|
||||
./scripts/rebuilddb.sh rootuser rootpassword database db/laconica.sql
|
||||
|
||||
Here, rootuser and rootpassword are the username and password for a
|
||||
user who can drop and create databases as well as tables; typically
|
||||
that's _not_ the user Laconica runs as.
|
||||
11. Use mysql client to log into your database and make sure that the
|
||||
notice, user, profile, subscription etc. tables are non-empty.
|
||||
For PostgreSQL databases there is an equivalent, rebuilddb_psql.sh,
|
||||
which operates slightly differently. Read the documentation in that
|
||||
script before running it.
|
||||
11. Use mysql or psql client to log into your database and make sure that
|
||||
the notice, user, profile, subscription etc. tables are non-empty.
|
||||
12. Turn back on the Web server, and check that things still work.
|
||||
13. Turn back on XMPP bots and email maildaemon. Note that the XMPP
|
||||
bots have changed since version 0.5; see above for details.
|
||||
@ -793,7 +817,7 @@ This section is a catch-all for site-wide variables.
|
||||
|
||||
name: the name of your site, like 'YourCompany Microblog'.
|
||||
server: the server part of your site's URLs, like 'example.net'.
|
||||
path: The path part of your site's URLs, like 'mublog' or '/'
|
||||
path: The path part of your site's URLs, like 'mublog' or ''
|
||||
(installed in root).
|
||||
fancy: whether or not your site uses fancy URLs (see Fancy URLs
|
||||
section above). Default is false.
|
||||
@ -837,6 +861,20 @@ notice: A plain string that will appear on every page. A good place
|
||||
to put introductory information about your service, or info about
|
||||
upgrades and outages, or other community info. Any HTML will
|
||||
be escaped.
|
||||
dupelimit: Time in which it's not OK for the same person to post the
|
||||
same notice; default = 60 seconds.
|
||||
logo: URL of an image file to use as the logo for the site. Overrides
|
||||
the logo in the theme, if any.
|
||||
ssl: Whether to use SSL and https:// URLs for some or all pages.
|
||||
Possible values are 'always' (use it for all pages), 'never'
|
||||
(don't use it for any pages), or 'sometimes' (use it for
|
||||
sensitive pages that include passwords like login and registration,
|
||||
but not for regular pages). Default to 'never'.
|
||||
sslserver: use an alternate server name for SSL URLs, like
|
||||
'secure.example.org'. You should be careful to set cookie
|
||||
parameters correctly so that both the SSL server and the
|
||||
"normal" server can access the session cookie and
|
||||
preferably other cookies as well.
|
||||
|
||||
db
|
||||
--
|
||||
@ -1081,6 +1119,23 @@ banned: an array of usernames and/or profile IDs of 'banned' profiles.
|
||||
not be accepted at all. (Compare with blacklisted users above,
|
||||
whose posts just won't show up in the public stream.)
|
||||
|
||||
newuser
|
||||
-------
|
||||
|
||||
Options with new users.
|
||||
|
||||
default: nickname of a user account to automatically subscribe new
|
||||
users to. Typically this would be system account for e.g.
|
||||
service updates or announcements. Users are able to unsub
|
||||
if they want. Default is null; no auto subscribe.
|
||||
welcome: nickname of a user account that sends welcome messages to new
|
||||
users. Can be the same as 'default' account, although on
|
||||
busy servers it may be a good idea to keep that one just for
|
||||
'urgent' messages. Default is null; no message.
|
||||
|
||||
If either of these special user accounts are specified, the users should
|
||||
be created before the configuration is updated.
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
@ -1093,7 +1148,7 @@ repository (see below), and you get a compilation error ("unexpected
|
||||
T_STRING") in the browser, check to see that you don't have any
|
||||
conflicts in your code.
|
||||
|
||||
If you upgraded to Laconica 0.7.1 without reading the "Notice inboxes"
|
||||
If you upgraded to Laconica 0.7.3 without reading the "Notice inboxes"
|
||||
section above, and all your users' 'Personal' tabs are empty, read the
|
||||
"Notice inboxes" section above.
|
||||
|
||||
@ -1179,6 +1234,11 @@ if anyone's been overlooked in error.
|
||||
* Ken Sheppardson (Trac server, man-about-town)
|
||||
* Tiago 'gouki' Faria (i18n managerx)
|
||||
* Sean Murphy
|
||||
* Leslie Michael Orchard
|
||||
* Eric Helgeson
|
||||
* Ken Sedgwick
|
||||
* Brian Hendrickson
|
||||
* Tobias Diekershoff
|
||||
|
||||
Thanks also to the developers of our upstream library code and to the
|
||||
thousands of people who have tried out Identi.ca, installed Laconi.ca,
|
||||
|
@ -59,7 +59,7 @@ class AccesstokenAction extends Action
|
||||
try {
|
||||
common_debug('getting request from env variables', __FILE__);
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('accesstoken'));
|
||||
common_debug('getting a server', __FILE__);
|
||||
$server = omb_oauth_server();
|
||||
common_debug('fetching the access token', __FILE__);
|
||||
|
@ -23,31 +23,13 @@ require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
|
||||
class AllAction extends Action
|
||||
class AllAction extends ProfileAction
|
||||
{
|
||||
var $user = null;
|
||||
var $page = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = common_canonical_nickname($this->arg('nickname'));
|
||||
$this->user = User::staticGet('nickname', $nickname);
|
||||
$this->page = $this->trimmed('page');
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
@ -77,22 +59,54 @@ class AllAction extends Action
|
||||
sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::RSS2,
|
||||
common_local_url('api', array('apiaction' => 'statuses',
|
||||
'method' => 'friends',
|
||||
'method' => 'friends_timeline',
|
||||
'argument' => $this->user->nickname.'.rss')),
|
||||
sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)),
|
||||
new Feed(Feed::ATOM,
|
||||
common_local_url('api', array('apiaction' => 'statuses',
|
||||
'method' => 'friends',
|
||||
'method' => 'friends_timeline',
|
||||
'argument' => $this->user->nickname.'.atom')),
|
||||
sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'all', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function showLocalNav()
|
||||
{
|
||||
$nav = new PersonalGroupNav($this);
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('This is the timeline for %s and friends but no one has posted anything yet.'), $this->user->nickname) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message .= _('Try subscribing to more people, [join a group](%%action.groups%%) or post something yourself.');
|
||||
} else {
|
||||
$message .= sprintf(_('You can try to [nudge %s](../%s) from his profile or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
@ -101,6 +115,10 @@ class AllAction extends Action
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'all', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
@ -54,6 +54,8 @@ class AllrssAction extends Rss10Action
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*/
|
||||
function prepare($args)
|
||||
@ -81,6 +83,7 @@ class AllrssAction extends Rss10Action
|
||||
{
|
||||
$user = $this->user;
|
||||
$notice = $user->noticesWithFriends(0, $limit);
|
||||
$notices = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
@ -104,7 +107,8 @@ class AllrssAction extends Rss10Action
|
||||
'link' => common_local_url('all',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'description' => sprintf(_('Feed for friends of %s'), $user->nickname));
|
||||
'description' => sprintf(_('Feed for friends of %s'),
|
||||
$user->nickname));
|
||||
return $c;
|
||||
}
|
||||
|
||||
@ -123,10 +127,5 @@ class AllrssAction extends Rss10Action
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
return $avatar ? $avatar->url : null;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,18 +127,21 @@ class ApiAction extends Action
|
||||
'laconica/wadl');
|
||||
|
||||
static $bareauth = array('statuses/user_timeline',
|
||||
'statuses/friends_timeline',
|
||||
'statuses/friends',
|
||||
'statuses/replies',
|
||||
'statuses/mentions',
|
||||
'statuses/followers',
|
||||
'favorites/favorites');
|
||||
|
||||
# If the site is "private", all API methods need authentication
|
||||
|
||||
if (common_config('site', 'private')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$fullname = "$this->api_action/$this->api_method";
|
||||
|
||||
// If the site is "private", all API methods except laconica/config
|
||||
// need authentication
|
||||
if (common_config('site', 'private')) {
|
||||
return $fullname != 'laconica/config' || false;
|
||||
}
|
||||
|
||||
if (in_array($fullname, $bareauth)) {
|
||||
# bareauth: only needs auth if without an argument
|
||||
if ($this->api_arg) {
|
||||
@ -178,11 +181,11 @@ class ApiAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
# NOTE: before handle(), can't use $this->arg
|
||||
$apiaction = $_REQUEST['apiaction'];
|
||||
$method = $_REQUEST['method'];
|
||||
$apiaction = $args['apiaction'];
|
||||
$method = $args['method'];
|
||||
|
||||
list($cmdtext, $fmt) = explode('.', $method);
|
||||
|
||||
static $write_methods = array(
|
||||
@ -205,5 +208,4 @@ class ApiAction extends Action
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
209
actions/attachment.php
Normal file
209
actions/attachment.php
Normal file
@ -0,0 +1,209 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show notice attachments
|
||||
*
|
||||
* 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 Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||
|
||||
/**
|
||||
* Show notice attachments
|
||||
*
|
||||
* @category Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class AttachmentAction extends Action
|
||||
{
|
||||
/**
|
||||
* Attachment object to show
|
||||
*/
|
||||
|
||||
var $attachment = null;
|
||||
|
||||
/**
|
||||
* Load attributes based on database arguments
|
||||
*
|
||||
* Loads all the DB stuff
|
||||
*
|
||||
* @param array $args $_REQUEST array
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->arg('attachment');
|
||||
|
||||
$this->attachment = File::staticGet($id);
|
||||
|
||||
if (!$this->attachment) {
|
||||
$this->clientError(_('No such attachment.'), 404);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this action read-only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
function title()
|
||||
{
|
||||
$a = new Attachment($this->attachment);
|
||||
return $a->title();
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-modified date for page
|
||||
*
|
||||
* When was the content of this page last modified? Based on notice,
|
||||
* profile, avatar.
|
||||
*
|
||||
* @return int last-modified date as unix timestamp
|
||||
*/
|
||||
/*
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->notice->created),
|
||||
strtotime($this->profile->modified),
|
||||
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An entity tag for this page
|
||||
*
|
||||
* Shows the ETag for the page, based on the notice ID and timestamps
|
||||
* for the notice, profile, and avatar. It's weak, since we change
|
||||
* the date text "one hour ago", etc.
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
/*
|
||||
function etag()
|
||||
{
|
||||
$avtime = ($this->avatar) ?
|
||||
strtotime($this->avatar->modified) : 0;
|
||||
|
||||
return 'W/"' . implode(':', array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created),
|
||||
strtotime($this->profile->modified),
|
||||
$avtime)) . '"';
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Handle input
|
||||
*
|
||||
* Only handles get, so just show the page.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show local navigation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showLocalNavBlock()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the content area of the page
|
||||
*
|
||||
* Shows a single notice list item.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$this->elementStart('ul', array('class' => 'attachments'));
|
||||
$ali = new Attachment($this->attachment, $this);
|
||||
$cnt = $ali->show();
|
||||
$this->elementEnd('ul');
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show page notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showPageNoticeBlock()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Show aside: this attachments appears in what notices
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showSections() {
|
||||
$ns = new AttachmentNoticeSection($this);
|
||||
$ns->show();
|
||||
$atcs = new AttachmentTagCloudSection($this);
|
||||
$atcs->show();
|
||||
}
|
||||
}
|
||||
|
141
actions/attachment_ajax.php
Normal file
141
actions/attachment_ajax.php
Normal file
@ -0,0 +1,141 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show notice attachments
|
||||
*
|
||||
* 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 Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/actions/attachment.php';
|
||||
|
||||
/**
|
||||
* Show notice attachments
|
||||
*
|
||||
* @category Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class Attachment_ajaxAction extends AttachmentAction
|
||||
{
|
||||
/**
|
||||
* Load attributes based on database arguments
|
||||
*
|
||||
* Loads all the DB stuff
|
||||
*
|
||||
* @param array $args $_REQUEST array
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
if (!$this->attachment) {
|
||||
$this->clientError(_('No such attachment.'), 404);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show page, a template method.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showPage()
|
||||
{
|
||||
if (Event::handle('StartShowBody', array($this))) {
|
||||
$this->showCore();
|
||||
Event::handle('EndShowBody', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show core.
|
||||
*
|
||||
* Shows local navigation, content block and aside.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showCore()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'core'));
|
||||
if (Event::handle('StartShowContentBlock', array($this))) {
|
||||
$this->showContentBlock();
|
||||
Event::handle('EndShowContentBlock', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Last-modified date for page
|
||||
*
|
||||
* When was the content of this page last modified? Based on notice,
|
||||
* profile, avatar.
|
||||
*
|
||||
* @return int last-modified date as unix timestamp
|
||||
*/
|
||||
/*
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->notice->created),
|
||||
strtotime($this->profile->modified),
|
||||
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* An entity tag for this page
|
||||
*
|
||||
* Shows the ETag for the page, based on the notice ID and timestamps
|
||||
* for the notice, profile, and avatar. It's weak, since we change
|
||||
* the date text "one hour ago", etc.
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
/*
|
||||
function etag()
|
||||
{
|
||||
$avtime = ($this->avatar) ?
|
||||
strtotime($this->avatar->modified) : 0;
|
||||
|
||||
return 'W/"' . implode(':', array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created),
|
||||
strtotime($this->profile->modified),
|
||||
$avtime)) . '"';
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
292
actions/attachments.php
Normal file
292
actions/attachments.php
Normal file
@ -0,0 +1,292 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show notice attachments
|
||||
*
|
||||
* 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 Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
require_once INSTALLDIR.'/lib/attachmentlist.php';
|
||||
|
||||
/**
|
||||
* Show notice attachments
|
||||
*
|
||||
* @category Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class AttachmentsAction extends Action
|
||||
{
|
||||
/**
|
||||
* Notice object to show
|
||||
*/
|
||||
|
||||
var $notice = null;
|
||||
|
||||
/**
|
||||
* Profile of the notice object
|
||||
*/
|
||||
|
||||
var $profile = null;
|
||||
|
||||
/**
|
||||
* Avatar of the profile of the notice object
|
||||
*/
|
||||
|
||||
var $avatar = null;
|
||||
|
||||
/**
|
||||
* Is this action read-only?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-modified date for page
|
||||
*
|
||||
* When was the content of this page last modified? Based on notice,
|
||||
* profile, avatar.
|
||||
*
|
||||
* @return int last-modified date as unix timestamp
|
||||
*/
|
||||
|
||||
function lastModified()
|
||||
{
|
||||
return max(strtotime($this->notice->created),
|
||||
strtotime($this->profile->modified),
|
||||
($this->avatar) ? strtotime($this->avatar->modified) : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* An entity tag for this page
|
||||
*
|
||||
* Shows the ETag for the page, based on the notice ID and timestamps
|
||||
* for the notice, profile, and avatar. It's weak, since we change
|
||||
* the date text "one hour ago", etc.
|
||||
*
|
||||
* @return string etag
|
||||
*/
|
||||
|
||||
function etag()
|
||||
{
|
||||
$avtime = ($this->avatar) ?
|
||||
strtotime($this->avatar->modified) : 0;
|
||||
|
||||
return 'W/"' . implode(':', array($this->arg('action'),
|
||||
common_language(),
|
||||
$this->notice->id,
|
||||
strtotime($this->notice->created),
|
||||
strtotime($this->profile->modified),
|
||||
$avtime)) . '"';
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return sprintf(_('%1$s\'s status on %2$s'),
|
||||
$this->profile->nickname,
|
||||
common_exact_date($this->notice->created));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load attributes based on database arguments
|
||||
*
|
||||
* Loads all the DB stuff
|
||||
*
|
||||
* @param array $args $_REQUEST array
|
||||
*
|
||||
* @return success flag
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$id = $this->arg('notice');
|
||||
|
||||
$this->notice = Notice::staticGet($id);
|
||||
|
||||
if (!$this->notice) {
|
||||
$this->clientError(_('No such notice.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// STOP if there are no attachments
|
||||
// maybe even redirect if there's a single one
|
||||
// RYM FIXME TODO
|
||||
$this->clientError(_('No such attachment.'), 404);
|
||||
return false;
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
$this->profile = $this->notice->getProfile();
|
||||
|
||||
if (!$this->profile) {
|
||||
$this->serverError(_('Notice has no profile'), 500);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->avatar = $this->profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Handle input
|
||||
*
|
||||
* Only handles get, so just show the page.
|
||||
*
|
||||
* @param array $args $_REQUEST data (unused)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($this->notice->is_local == 0) {
|
||||
if (!empty($this->notice->url)) {
|
||||
common_redirect($this->notice->url, 301);
|
||||
} else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
|
||||
common_redirect($this->notice->uri, 301);
|
||||
}
|
||||
} else {
|
||||
$f2p = new File_to_post;
|
||||
$f2p->post_id = $this->notice->id;
|
||||
$file = new File;
|
||||
$file->joinAdd($f2p);
|
||||
$file->selectAdd();
|
||||
$file->selectAdd('file.id as id');
|
||||
$count = $file->find(true);
|
||||
if (!$count) return;
|
||||
if (1 === $count) {
|
||||
common_redirect(common_local_url('attachment', array('attachment' => $file->id)), 301);
|
||||
} else {
|
||||
$this->showPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show local navigation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showLocalNavBlock()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the content area of the page
|
||||
*
|
||||
* Shows a single notice list item.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$al = new AttachmentList($this->notice, $this);
|
||||
$cnt = $al->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show page notice
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showPageNoticeBlock()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show aside
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showAside() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra <head> content
|
||||
*
|
||||
* We show the microid(s) for the author, if any.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
$user = User::staticGet($this->profile->id);
|
||||
|
||||
if (!$user) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->emailmicroid && $user->email && $this->notice->uri) {
|
||||
$id = new Microid('mailto:'. $user->email,
|
||||
$this->notice->uri);
|
||||
$this->element('meta', array('name' => 'microid',
|
||||
'content' => $id->toString()));
|
||||
}
|
||||
|
||||
if ($user->jabbermicroid && $user->jabber && $this->notice->uri) {
|
||||
$id = new Microid('xmpp:', $user->jabber,
|
||||
$this->notice->uri);
|
||||
$this->element('meta', array('name' => 'microid',
|
||||
'content' => $id->toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
115
actions/attachments_ajax.php
Normal file
115
actions/attachments_ajax.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Show notice attachments
|
||||
*
|
||||
* 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 Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//require_once INSTALLDIR.'/lib/personalgroupnav.php';
|
||||
//require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
require_once INSTALLDIR.'/actions/attachments.php';
|
||||
|
||||
/**
|
||||
* Show notice attachments
|
||||
*
|
||||
* @category Personal
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class Attachments_ajaxAction extends AttachmentsAction
|
||||
{
|
||||
function showContent()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the content area of the page
|
||||
*
|
||||
* Shows a single notice list item.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContentBlock()
|
||||
{
|
||||
$al = new AttachmentList($this->notice, $this);
|
||||
$cnt = $al->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra <head> content
|
||||
*
|
||||
* We show the microid(s) for the author, if any.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show page, a template method.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showPage()
|
||||
{
|
||||
if (Event::handle('StartShowBody', array($this))) {
|
||||
$this->showCore();
|
||||
Event::handle('EndShowBody', array($this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show core.
|
||||
*
|
||||
* Shows local navigation, content block and aside.
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
function showCore()
|
||||
{
|
||||
$this->elementStart('div', array('id' => 'core'));
|
||||
if (Event::handle('StartShowContentBlock', array($this))) {
|
||||
$this->showContentBlock();
|
||||
Event::handle('EndShowContentBlock', array($this));
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -98,7 +98,7 @@ class AvatarbynicknameAction extends Action
|
||||
common_redirect($url, 302);
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -324,13 +324,14 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
return;
|
||||
}
|
||||
|
||||
// If image is not being cropped assume pos & dimentions 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'];
|
||||
$size = min($dest_w, $dest_h);
|
||||
$size = ($size > MAX_ORIGINAL) ? MAX_ORIGINAL:$size;
|
||||
$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();
|
||||
$profile = $user->getProfile();
|
||||
@ -343,6 +344,7 @@ class AvatarsettingsAction extends AccountSettingsAction
|
||||
unset($_SESSION['FILEDATA']);
|
||||
$this->mode = 'upload';
|
||||
$this->showForm(_('Avatar updated.'), true);
|
||||
common_broadcast_profile($profile);
|
||||
} else {
|
||||
$this->showForm(_('Failed updating avatar.'));
|
||||
}
|
||||
|
@ -93,7 +93,8 @@ class BlockAction extends Action
|
||||
if ($this->arg('no')) {
|
||||
$cur = common_current_user();
|
||||
$other = Profile::staticGet('id', $this->arg('blockto'));
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $other->nickname)));
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $other->nickname)),
|
||||
303);
|
||||
} elseif ($this->arg('yes')) {
|
||||
$this->blockProfile();
|
||||
} elseif ($this->arg('blockto')) {
|
||||
@ -102,7 +103,6 @@ class BlockAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function showContent() {
|
||||
$this->areYouSureForm();
|
||||
}
|
||||
@ -178,10 +178,11 @@ class BlockAction extends Action
|
||||
}
|
||||
|
||||
if ($action) {
|
||||
common_redirect(common_local_url($action, $args));
|
||||
common_redirect(common_local_url($action, $args), 303);
|
||||
} else {
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $cur->nickname)));
|
||||
array('nickname' => $cur->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
107
actions/conversation.php
Normal file
107
actions/conversation.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Display a conversation in the browser
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*
|
||||
* Laconica - a distributed open-source microblogging tool
|
||||
* Copyright (C) 2008, Controlez-Vous, 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('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once(INSTALLDIR.'/lib/noticelist.php');
|
||||
|
||||
/**
|
||||
* Conversation tree in the browser
|
||||
*
|
||||
* @category Action
|
||||
* @package Laconica
|
||||
* @author Evan Prodromou <evan@controlyourself.ca>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
class ConversationAction extends Action
|
||||
{
|
||||
var $id = null;
|
||||
var $page = null;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if id not passed in
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->id = $this->trimmed('id');
|
||||
if (empty($this->id)) {
|
||||
return false;
|
||||
}
|
||||
$this->page = $this->trimmed('page');
|
||||
if (empty($this->page)) {
|
||||
$this->page = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
return _("Conversation");
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
// FIXME this needs to be a tree, not a list
|
||||
|
||||
$qry = 'SELECT * FROM notice WHERE conversation = %s ';
|
||||
|
||||
$offset = ($this->page-1)*NOTICES_PER_PAGE;
|
||||
$limit = NOTICES_PER_PAGE + 1;
|
||||
|
||||
$txt = sprintf($qry, $this->id);
|
||||
|
||||
$notices = Notice::getStream($txt,
|
||||
'notice:conversation:'.$this->id,
|
||||
$offset, $limit);
|
||||
|
||||
$nl = new NoticeList($notices, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'conversation', array('id' => $this->id));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -141,6 +141,6 @@ class DeletenoticeAction extends DeleteAction
|
||||
$url = common_local_url('public');
|
||||
}
|
||||
|
||||
common_redirect($url);
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
||||
|
262
actions/designsettings.php
Normal file
262
actions/designsettings.php
Normal file
@ -0,0 +1,262 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Change user password
|
||||
*
|
||||
* 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 Settings
|
||||
* @package Laconica
|
||||
* @author Sarven Capadisli <csarven@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/accountsettingsaction.php';
|
||||
|
||||
|
||||
|
||||
class DesignsettingsAction extends AccountSettingsAction
|
||||
{
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
* @return string Title of the page
|
||||
*/
|
||||
|
||||
function title()
|
||||
{
|
||||
return _('Profile design');
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructions for use
|
||||
*
|
||||
* @return instructions for use
|
||||
*/
|
||||
|
||||
function getInstructions()
|
||||
{
|
||||
return _('Customize the way your profile looks with a background image and a colour palette of your choice.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Content area of the page
|
||||
*
|
||||
* Shows a form for changing the password
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$user = common_current_user();
|
||||
$this->elementStart('form', array('method' => 'POST',
|
||||
'id' => 'form_settings_design',
|
||||
'class' => 'form_settings',
|
||||
'action' =>
|
||||
common_local_url('designsettings')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_design_background-image'));
|
||||
$this->element('legend', null, _('Change background image'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->element('label', array('for' => 'design_ background-image_file'),
|
||||
_('Upload file'));
|
||||
$this->element('input', array('name' => 'design_background-image_file',
|
||||
'type' => 'file',
|
||||
'id' => 'design_background-image_file'));
|
||||
$this->element('p', 'form_guide', _('You can upload your personal background image. The maximum file size is 2Mb.'));
|
||||
$this->element('input', array('name' => 'MAX_FILE_SIZE',
|
||||
'type' => 'hidden',
|
||||
'id' => 'MAX_FILE_SIZE',
|
||||
'value' => ImageFile::maxFileSizeInt()));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->elementStart('fieldset', array('id' => 'settings_design_color'));
|
||||
$this->element('legend', null, _('Change colours'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
|
||||
//This is a JSON object in the DB field. Here for testing. Remove later.
|
||||
$userSwatch = '{"body":{"background-color":"#F0F2F5"},
|
||||
"#content":{"background-color":"#FFFFFF"},
|
||||
"#aside_primary":{"background-color":"#CEE1E9"},
|
||||
"html body":{"color":"#000000"},
|
||||
"a":{"color":"#002E6E"}}';
|
||||
|
||||
//Default theme swatch -- Where should this be stored?
|
||||
$defaultSwatch = array('body' => array('background-color' => '#F0F2F5'),
|
||||
'#content' => array('background-color' => '#FFFFFF'),
|
||||
'#aside_primary' => array('background-color' => '#CEE1E9'),
|
||||
'html body' => array('color' => '#000000'),
|
||||
'a' => array('color' => '#002E6E'));
|
||||
|
||||
$userSwatch = ($userSwatch) ? json_decode($userSwatch, true) : $defaultSwatch;
|
||||
|
||||
$s = 0;
|
||||
$labelSwatch = array('Background',
|
||||
'Content',
|
||||
'Sidebar',
|
||||
'Text',
|
||||
'Links');
|
||||
foreach($userSwatch as $propertyvalue => $value) {
|
||||
$foo = array_values($value);
|
||||
$this->elementStart('li');
|
||||
$this->element('label', array('for' => 'swatch-'.$s), _($labelSwatch[$s]));
|
||||
$this->element('input', array('name' => 'swatch-'.$s, //prefer swatch[$s] ?
|
||||
'type' => 'text',
|
||||
'id' => 'swatch-'.$s,
|
||||
'class' => 'swatch',
|
||||
'maxlength' => '7',
|
||||
'size' => '7',
|
||||
'value' => $foo[0]));
|
||||
$this->elementEnd('li');
|
||||
$s++;
|
||||
}
|
||||
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('fieldset');
|
||||
|
||||
$this->submit('save', _('Save'));
|
||||
$this->element('input', array('type' => 'reset',
|
||||
'value' => 'Reset',
|
||||
'class' => 'form_action-secondary'));
|
||||
|
||||
/*TODO: Check submitted form values:
|
||||
json_encode(form values)
|
||||
if submitted Swatch == DefaultSwatch, don't store in DB.
|
||||
else store in BD
|
||||
*/
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a post
|
||||
*
|
||||
* Validate input and save changes. Reload the form with a success
|
||||
* or error message.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
/*
|
||||
// CSRF protection
|
||||
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
assert(!is_null($user)); // should already be checked
|
||||
|
||||
// FIXME: scrub input
|
||||
|
||||
$newpassword = $this->arg('newpassword');
|
||||
$confirm = $this->arg('confirm');
|
||||
|
||||
# Some validation
|
||||
|
||||
if (strlen($newpassword) < 6) {
|
||||
$this->showForm(_('Password must be 6 or more characters.'));
|
||||
return;
|
||||
} else if (0 != strcmp($newpassword, $confirm)) {
|
||||
$this->showForm(_('Passwords don\'t match.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->password) {
|
||||
$oldpassword = $this->arg('oldpassword');
|
||||
|
||||
if (!common_check_user($user->nickname, $oldpassword)) {
|
||||
$this->showForm(_('Incorrect old password'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$original = clone($user);
|
||||
|
||||
$user->password = common_munge_password($newpassword, $user->id);
|
||||
|
||||
$val = $user->validate();
|
||||
if ($val !== true) {
|
||||
$this->showForm(_('Error saving user; invalid.'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$user->update($original)) {
|
||||
$this->serverError(_('Can\'t save new password.'));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->showForm(_('Password saved.'), true);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the Farbtastic stylesheet
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showStylesheets()
|
||||
{
|
||||
parent::showStylesheets();
|
||||
$farbtasticStyle =
|
||||
common_path('theme/base/css/farbtastic.css?version='.LACONICA_VERSION);
|
||||
|
||||
$this->element('link', array('rel' => 'stylesheet',
|
||||
'type' => 'text/css',
|
||||
'href' => $farbtasticStyle,
|
||||
'media' => 'screen, projection, tv'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Farbtastic scripts
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showScripts()
|
||||
{
|
||||
parent::showScripts();
|
||||
|
||||
$farbtasticPack = common_path('js/farbtastic/farbtastic.js');
|
||||
$farbtasticGo = common_path('js/farbtastic/farbtastic.go.js');
|
||||
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticPack));
|
||||
$this->element('script', array('type' => 'text/javascript',
|
||||
'src' => $farbtasticGo));
|
||||
}
|
||||
}
|
@ -100,7 +100,8 @@ class DisfavorAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('showfavorites',
|
||||
array('nickname' => $user->nickname)));
|
||||
array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ class DocAction extends Action
|
||||
return ucfirst($this->title);
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -166,7 +166,6 @@ class EditgroupAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$nickname = common_canonical_nickname($this->trimmed('nickname'));
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
@ -221,7 +220,7 @@ class EditgroupAction extends Action
|
||||
if ($this->group->nickname != $orig->nickname) {
|
||||
common_redirect(common_local_url('editgroup',
|
||||
array('nickname' => $nickname)),
|
||||
307);
|
||||
303);
|
||||
} else {
|
||||
$this->showForm(_('Options saved.'));
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ class FavorAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('showfavorites',
|
||||
array('nickname' => $user->nickname)));
|
||||
array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ class FavoritedAction extends Action
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -145,6 +145,22 @@ class FavoritedAction extends Action
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showEmptyList()
|
||||
{
|
||||
$message = _('Favorite notices appear on this page but no one has favorited one yet.') . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$message .= _('Be the first to add a notice to your favorites by clicking the fave button next to any notice you like.');
|
||||
}
|
||||
else {
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to add a notice to your favorites!');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Local navigation
|
||||
*
|
||||
@ -169,10 +185,16 @@ 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 ' .
|
||||
'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source ' .
|
||||
'ORDER BY weight DESC';
|
||||
|
||||
$offset = ($this->page - 1) * NOTICES_PER_PAGE;
|
||||
@ -192,7 +214,22 @@ class FavoritedAction extends Action
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
if ($cnt == 0) {
|
||||
$this->showEmptyList();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'favorited');
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'favorited');
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ class FavoritesrssAction extends Rss10Action
|
||||
$c = array('url' => common_local_url('favoritesrss',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
'title' => sprintf(_("%s favorite notices"), $user->nickname),
|
||||
'title' => sprintf(_("%s's favorite notices"), $user->nickname),
|
||||
'link' => common_local_url('showfavorites',
|
||||
array('nickname' =>
|
||||
$user->nickname)),
|
||||
|
@ -50,7 +50,7 @@ class FeaturedAction extends Action
|
||||
{
|
||||
var $page = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -107,6 +107,7 @@ class FeaturedAction extends Action
|
||||
|
||||
$featured_nicks = common_config('nickname', 'featured');
|
||||
|
||||
|
||||
if (count($featured_nicks) > 0) {
|
||||
|
||||
$quoted = array();
|
||||
@ -118,7 +119,7 @@ class FeaturedAction extends Action
|
||||
$user = new User;
|
||||
$user->whereAdd(sprintf('nickname IN (%s)', implode(',', $quoted)));
|
||||
$user->limit(($this->page - 1) * PROFILES_PER_PAGE, PROFILES_PER_PAGE + 1);
|
||||
$user->orderBy('user.nickname ASC');
|
||||
$user->orderBy(common_database_tablename('user') .'.nickname ASC');
|
||||
|
||||
$user->find();
|
||||
|
||||
|
@ -139,7 +139,7 @@ class FinishaddopenidAction extends Action
|
||||
|
||||
oid_set_last($display);
|
||||
|
||||
common_redirect(common_local_url('openidsettings'));
|
||||
common_redirect(common_local_url('openidsettings'), 303);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,8 @@ class FinishopenidloginAction extends Action
|
||||
if ($this->error) {
|
||||
$this->element('div', array('class' => 'error'), $this->error);
|
||||
} else {
|
||||
global $config;
|
||||
$this->element('div', 'instructions',
|
||||
sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), $config['site']['name']));
|
||||
sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID 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')));
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,7 +82,7 @@ class FinishopenidloginAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
if ($this->message_text) {
|
||||
if (!empty($this->message_text)) {
|
||||
$this->element('p', null, $this->message);
|
||||
return;
|
||||
}
|
||||
@ -192,11 +191,28 @@ class FinishopenidloginAction extends Action
|
||||
{
|
||||
# FIXME: save invite code before redirect, and check here
|
||||
|
||||
if (common_config('site', 'closed') || common_config('site', 'inviteonly')) {
|
||||
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,
|
||||
@ -232,7 +248,8 @@ class FinishopenidloginAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
if ($sreg['country']) {
|
||||
$location = '';
|
||||
if (!empty($sreg['country'])) {
|
||||
if ($sreg['postcode']) {
|
||||
# XXX: use postcode to get city and region
|
||||
# XXX: also, store postcode somewhere -- it's valuable!
|
||||
@ -242,21 +259,31 @@ class FinishopenidloginAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
if ($sreg['fullname'] && mb_strlen($sreg['fullname']) <= 255) {
|
||||
if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
|
||||
$fullname = $sreg['fullname'];
|
||||
} else {
|
||||
$fullname = '';
|
||||
}
|
||||
|
||||
if ($sreg['email'] && Validate::email($sreg['email'], true)) {
|
||||
if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) {
|
||||
$email = $sreg['email'];
|
||||
} else {
|
||||
$email = '';
|
||||
}
|
||||
|
||||
# XXX: add language
|
||||
# XXX: add timezone
|
||||
|
||||
$user = User::register(array('nickname' => $nickname,
|
||||
$args = array('nickname' => $nickname,
|
||||
'email' => $email,
|
||||
'fullname' => $fullname,
|
||||
'location' => $location));
|
||||
'location' => $location);
|
||||
|
||||
if (!empty($invite)) {
|
||||
$args['code'] = $invite->code;
|
||||
}
|
||||
|
||||
$user = User::register($args);
|
||||
|
||||
$result = oid_link_user($user->id, $canonical, $display);
|
||||
|
||||
@ -267,7 +294,8 @@ class FinishopenidloginAction extends Action
|
||||
common_rememberme($user);
|
||||
}
|
||||
unset($_SESSION['openid_rememberme']);
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)));
|
||||
common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
|
||||
303);
|
||||
}
|
||||
|
||||
function connectUser()
|
||||
@ -320,7 +348,7 @@ class FinishopenidloginAction extends Action
|
||||
array('nickname' =>
|
||||
$nickname));
|
||||
}
|
||||
common_redirect($url);
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
function bestNewNickname($display, $sreg)
|
||||
@ -328,7 +356,7 @@ class FinishopenidloginAction extends Action
|
||||
|
||||
# Try the passed-in nickname
|
||||
|
||||
if ($sreg['nickname']) {
|
||||
if (!empty($sreg['nickname'])) {
|
||||
$nickname = $this->nicknamize($sreg['nickname']);
|
||||
if ($this->isNewNickname($nickname)) {
|
||||
return $nickname;
|
||||
@ -337,7 +365,7 @@ class FinishopenidloginAction extends Action
|
||||
|
||||
# Try the full name
|
||||
|
||||
if ($sreg['fullname']) {
|
||||
if (!empty($sreg['fullname'])) {
|
||||
$fullname = $this->nicknamize($sreg['fullname']);
|
||||
if ($this->isNewNickname($fullname)) {
|
||||
return $fullname;
|
||||
|
@ -44,7 +44,7 @@ class FinishremotesubscribeAction extends Action
|
||||
common_debug('stored request: '.print_r($omb,true), __FILE__);
|
||||
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('finishuserauthorization'));
|
||||
|
||||
$token = $req->get_parameter('oauth_token');
|
||||
|
||||
@ -136,16 +136,16 @@ class FinishremotesubscribeAction extends Action
|
||||
$profile->nickname = $nickname;
|
||||
$profile->profileurl = $profile_url;
|
||||
|
||||
if ($fullname) {
|
||||
if (!is_null($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if ($homepage) {
|
||||
if (!is_null($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if ($bio) {
|
||||
if (!is_null($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if ($location) {
|
||||
if (!is_null($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
@ -230,7 +230,8 @@ class FinishremotesubscribeAction extends Action
|
||||
# show up close to the top of the page
|
||||
|
||||
common_redirect(common_local_url('subscribers', array('nickname' =>
|
||||
$user->nickname)));
|
||||
$user->nickname)),
|
||||
303);
|
||||
}
|
||||
|
||||
function add_avatar($profile, $url)
|
||||
@ -283,7 +284,7 @@ class FinishremotesubscribeAction extends Action
|
||||
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
|
||||
$result = $fetcher->post($req->get_normalized_http_url(),
|
||||
$req->to_postdata(),
|
||||
array('User-Agent' => 'Laconica/' . LACONICA_VERSION));
|
||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||
|
||||
common_debug('got result: "'.print_r($result,true).'"', __FILE__);
|
||||
|
||||
|
@ -25,7 +25,7 @@ define('BOTH', 0);
|
||||
|
||||
class FoafAction extends Action
|
||||
{
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -33,7 +33,24 @@ class FoafAction extends Action
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->nickname = $this->trimmed('nickname');
|
||||
|
||||
$nickname_arg = $this->arg('nickname');
|
||||
|
||||
if (empty($nickname_arg)) {
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->nickname = common_canonical_nickname($nickname_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
if ($nickname_arg != $this->nickname) {
|
||||
common_redirect(common_local_url('foaf',
|
||||
array('nickname' => $this->nickname)),
|
||||
301);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->user = User::staticGet('nickname', $this->nickname);
|
||||
|
||||
@ -122,20 +139,30 @@ class FoafAction extends Action
|
||||
|
||||
if ($sub->find()) {
|
||||
while ($sub->fetch()) {
|
||||
if ($sub->token) {
|
||||
if (!empty($sub->token)) {
|
||||
$other = Remote_profile::staticGet('id', $sub->subscribed);
|
||||
} else {
|
||||
$other = User::staticGet('id', $sub->subscribed);
|
||||
}
|
||||
if (!$other) {
|
||||
if (empty($other)) {
|
||||
common_debug('Got a bad subscription: '.print_r($sub,true));
|
||||
continue;
|
||||
}
|
||||
$this->element('knows', array('rdf:resource' => $other->uri));
|
||||
$person[$other->uri] = array(LISTENEE, $other);
|
||||
$person[$other->uri] = array(LISTENEE,
|
||||
$other->id,
|
||||
$other->nickname,
|
||||
(empty($sub->token)) ? 'User' : 'Remote_profile');
|
||||
$other->free();
|
||||
$other = null;
|
||||
unset($other);
|
||||
}
|
||||
}
|
||||
|
||||
$sub->free();
|
||||
$sub = null;
|
||||
unset($sub);
|
||||
|
||||
// Get people who subscribe to user
|
||||
|
||||
$sub = new Subscription();
|
||||
@ -156,24 +183,35 @@ class FoafAction extends Action
|
||||
if (array_key_exists($other->uri, $person)) {
|
||||
$person[$other->uri][0] = BOTH;
|
||||
} else {
|
||||
$person[$other->uri] = array(LISTENER, $other);
|
||||
}
|
||||
$person[$other->uri] = array(LISTENER,
|
||||
$other->id,
|
||||
$other->nickname,
|
||||
(empty($sub->token)) ? 'User' : 'Remote_profile');
|
||||
}
|
||||
$other->free();
|
||||
$other = null;
|
||||
unset($other);
|
||||
}
|
||||
}
|
||||
|
||||
$sub->free();
|
||||
$sub = null;
|
||||
unset($sub);
|
||||
|
||||
$this->elementEnd('Person');
|
||||
|
||||
foreach ($person as $uri => $p) {
|
||||
$foaf_url = null;
|
||||
if ($p[1] instanceof User) {
|
||||
$foaf_url = common_local_url('foaf', array('nickname' => $p[1]->nickname));
|
||||
list($type, $id, $nickname, $cls) = $p;
|
||||
if ($cls == 'User') {
|
||||
$foaf_url = common_local_url('foaf', array('nickname' => $nickname));
|
||||
}
|
||||
$this->profile = Profile::staticGet($p[1]->id);
|
||||
$profile = Profile::staticGet($id);
|
||||
$this->elementStart('Person', array('rdf:about' => $uri));
|
||||
if ($p[0] == LISTENER || $p[0] == BOTH) {
|
||||
if ($type == LISTENER || $type == BOTH) {
|
||||
$this->element('knows', array('rdf:resource' => $this->user->uri));
|
||||
}
|
||||
$this->showMicrobloggingAccount($this->profile, ($p[1] instanceof User) ?
|
||||
$this->showMicrobloggingAccount($profile, ($cls == 'User') ?
|
||||
common_root_url() : null);
|
||||
if ($foaf_url) {
|
||||
$this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url));
|
||||
@ -182,6 +220,9 @@ class FoafAction extends Action
|
||||
if ($foaf_url) {
|
||||
$this->showPpd($foaf_url, $uri);
|
||||
}
|
||||
$profile->free();
|
||||
$profile = null;
|
||||
unset($profile);
|
||||
}
|
||||
|
||||
$this->elementEnd('rdf:RDF');
|
||||
|
@ -59,7 +59,7 @@ class GroupbyidAction extends Action
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class GrouplogoAction extends Action
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
common_redirect(common_local_url('editgroup', $args), 301);
|
||||
common_redirect(common_local_url('grouplogo', $args), 301);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ class GroupmembersAction extends Action
|
||||
{
|
||||
var $page = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -137,4 +137,15 @@ class GroupmembersAction extends Action
|
||||
$this->page, 'groupmembers',
|
||||
array('nickname' => $this->group->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'groupmembers', array('nickname' => $this->group->nickname));
|
||||
}
|
||||
}
|
@ -34,7 +34,7 @@ if (!defined('LACONICA')) {
|
||||
|
||||
require_once INSTALLDIR.'/lib/rssaction.php';
|
||||
|
||||
define('MEMBERS_PER_SECTION', 81);
|
||||
define('MEMBERS_PER_SECTION', 27);
|
||||
|
||||
/**
|
||||
* Group RSS feed
|
||||
@ -57,7 +57,7 @@ class groupRssAction extends Rss10Action
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -141,13 +141,4 @@ class groupRssAction extends Rss10Action
|
||||
{
|
||||
return $this->group->homepage_logo;
|
||||
}
|
||||
|
||||
# override parent to add X-SUP-ID URL
|
||||
|
||||
function initRss($limit=0)
|
||||
{
|
||||
$url = common_local_url('sup', null, $this->group->id);
|
||||
header('X-SUP-ID: '.$url);
|
||||
parent::initRss($limit);
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ class GroupsAction extends Action
|
||||
var $page = null;
|
||||
var $profile = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -129,4 +129,15 @@ class GroupsAction extends Action
|
||||
$gbm = new GroupsByMembersSection($this);
|
||||
$gbm->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'groups', array('nickname' => $this->group->nickname));
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,4 @@
|
||||
<?php
|
||||
|
||||
|
||||
// define('GROUPS_PER_PAGE', 20);
|
||||
|
||||
|
||||
/**
|
||||
* Group search action class.
|
||||
*
|
||||
@ -77,12 +72,23 @@ class GroupsearchAction extends SearchAction
|
||||
$terms = preg_split('/[\s,]+/', $q);
|
||||
$results = new GroupSearchResults($user_group, $terms, $this);
|
||||
$results->show();
|
||||
} else {
|
||||
$this->element('p', 'error', _('No results'));
|
||||
}
|
||||
$user_group->free();
|
||||
$this->pagination($page > 1, $cnt > GROUPS_PER_PAGE,
|
||||
$page, 'groupsearch', array('q' => $q));
|
||||
} else {
|
||||
$this->element('p', 'error', _('No results.'));
|
||||
$this->searchSuggestions($q);
|
||||
if (common_logged_in()) {
|
||||
$message = _('If you can\'t find the group you\'re looking for, you can [create it](%%action.newgroup%%) yourself.');
|
||||
}
|
||||
else {
|
||||
$message = _('Why not [register an account](%%action.register%%) and [create the group](%%action.newgroup%%) yourself!');
|
||||
}
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
$user_group->free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,10 +109,5 @@ class GroupSearchResults extends GroupList
|
||||
{
|
||||
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,17 @@ class InboxAction extends MailboxAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'inbox', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the messages for this user and this page
|
||||
*
|
||||
|
@ -27,7 +27,7 @@ class InviteAction extends Action
|
||||
var $subbed = null;
|
||||
var $sent = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ class JoingroupAction extends Action
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
common_redirect(common_local_url('editgroup', $args), 301);
|
||||
common_redirect(common_local_url('joingroup', $args), 301);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -143,7 +143,8 @@ class JoingroupAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('groupmembers', array('nickname' =>
|
||||
$this->group->nickname)));
|
||||
$this->group->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
@ -73,7 +73,7 @@ class LeavegroupAction extends Action
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
common_redirect(common_local_url('editgroup', $args), 301);
|
||||
common_redirect(common_local_url('leavegroup', $args), 301);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -96,12 +96,6 @@ class LeavegroupAction extends Action
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($cur->isAdmin($this->group)) {
|
||||
$this->clientError(_('You may not leave a group while you are its administrator.'), 403);
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -153,7 +147,8 @@ class LeavegroupAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('groupmembers', array('nickname' =>
|
||||
$this->group->nickname)));
|
||||
$this->group->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ class LoginAction extends Action
|
||||
* @return boolean false
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -108,13 +108,15 @@ class LoginAction extends Action
|
||||
$nickname = common_canonical_nickname($this->trimmed('nickname'));
|
||||
$password = $this->arg('password');
|
||||
|
||||
if (!common_check_user($nickname, $password)) {
|
||||
$user = common_check_user($nickname, $password);
|
||||
|
||||
if (!$user) {
|
||||
$this->showForm(_('Incorrect username or password.'));
|
||||
return;
|
||||
}
|
||||
|
||||
// success!
|
||||
if (!common_set_user($nickname)) {
|
||||
if (!common_set_user($user)) {
|
||||
$this->serverError(_('Error setting user.'));
|
||||
return;
|
||||
}
|
||||
@ -136,7 +138,7 @@ class LoginAction extends Action
|
||||
$nickname));
|
||||
}
|
||||
|
||||
common_redirect($url);
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ class LogoutAction extends Action
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -70,10 +70,20 @@ class LogoutAction extends Action
|
||||
if (!common_logged_in()) {
|
||||
$this->clientError(_('Not logged in.'));
|
||||
} else {
|
||||
if (Event::handle('StartLogout', array($this))) {
|
||||
$this->logout();
|
||||
}
|
||||
Event::handle('EndLogout', array($this));
|
||||
|
||||
common_redirect(common_local_url('public'), 303);
|
||||
}
|
||||
}
|
||||
|
||||
function logout()
|
||||
{
|
||||
common_set_user(null);
|
||||
common_real_login(false); // not logged in
|
||||
common_forgetme(); // don't log back in!
|
||||
common_redirect(common_local_url('public'));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ class MicrosummaryAction extends Action
|
||||
print $user->nickname . ': ' . $notice->content;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -193,7 +193,7 @@ class NewgroupAction extends Action
|
||||
|
||||
$group->query('COMMIT');
|
||||
|
||||
common_redirect($group->homeUrl(), 307);
|
||||
common_redirect($group->homeUrl(), 303);
|
||||
}
|
||||
|
||||
function nicknameExists($nickname)
|
||||
|
@ -172,15 +172,54 @@ class NewmessageAction extends Action
|
||||
|
||||
$this->notify($user, $this->other, $message);
|
||||
|
||||
$url = common_local_url('outbox', array('nickname' => $user->nickname));
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
$this->startHTML('text/xml;charset=utf-8');
|
||||
$this->elementStart('head');
|
||||
$this->element('title', null, _('Message sent'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$this->element('p', array('id' => 'command_result'),
|
||||
sprintf(_('Direct message to %s sent'),
|
||||
$this->other->nickname));
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
$url = common_local_url('outbox',
|
||||
array('nickname' => $user->nickname));
|
||||
common_redirect($url, 303);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an Ajax-y error message
|
||||
*
|
||||
* Goes back to the browser, where it's shown in a popup.
|
||||
*
|
||||
* @param string $msg Message to show
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function ajaxErrorMsg($msg)
|
||||
{
|
||||
$this->startHTML('text/xml;charset=utf-8', true);
|
||||
$this->elementStart('head');
|
||||
$this->element('title', null, _('Ajax Error'));
|
||||
$this->elementEnd('head');
|
||||
$this->elementStart('body');
|
||||
$this->element('p', array('id' => 'error'), $msg);
|
||||
$this->elementEnd('body');
|
||||
$this->elementEnd('html');
|
||||
}
|
||||
|
||||
function showForm($msg = null)
|
||||
{
|
||||
$this->msg = $msg;
|
||||
if ($msg && $this->boolean('ajax')) {
|
||||
$this->ajaxErrorMsg($msg);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->msg = $msg;
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
|
@ -152,8 +152,14 @@ 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,
|
||||
// $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||
$notice = Notice::saveNew($user->id, $content_shortened, 'web', 1,
|
||||
($replyto == 'false') ? null : $replyto);
|
||||
|
||||
if (is_string($notice)) {
|
||||
@ -161,6 +167,8 @@ class NewnoticeAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$this->saveUrls($notice);
|
||||
|
||||
common_broadcast_notice($notice);
|
||||
|
||||
if ($this->boolean('ajax')) {
|
||||
@ -186,6 +194,24 @@ class NewnoticeAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
/** save all urls in the notice to the db
|
||||
*
|
||||
* follow redirects and save all available file information
|
||||
* (mimetype, date, size, oembed, etc.)
|
||||
*
|
||||
* @param class $notice Notice to pull URLs from
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function saveUrls($notice) {
|
||||
common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id);
|
||||
}
|
||||
|
||||
function saveUrl($data) {
|
||||
list($url, $notice_id) = $data;
|
||||
$zzz = File::processNew($url, $notice_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show an Ajax-y error message
|
||||
*
|
||||
@ -253,7 +279,7 @@ class NewnoticeAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
$notice_form = new NoticeForm($this, $content);
|
||||
$notice_form = new NoticeForm($this, '', $content);
|
||||
$notice_form->show();
|
||||
}
|
||||
|
||||
|
@ -103,7 +103,7 @@ class NoticesearchAction extends SearchAction
|
||||
function showResults($q, $page)
|
||||
{
|
||||
$notice = new Notice();
|
||||
$q = strtolower($q);
|
||||
|
||||
$search_engine = $notice->getSearchEngine('identica_notices');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
// Ask for an extra to see if there's more.
|
||||
@ -113,123 +113,64 @@ class NoticesearchAction extends SearchAction
|
||||
} else {
|
||||
$cnt = $notice->find();
|
||||
}
|
||||
if ($cnt > 0) {
|
||||
$terms = preg_split('/[\s,]+/', $q);
|
||||
$this->elementStart('ul', array('class' => 'notices'));
|
||||
for ($i = 0; $i < min($cnt, NOTICES_PER_PAGE); $i++) {
|
||||
if ($notice->fetch()) {
|
||||
$this->showNotice($notice, $terms);
|
||||
} else {
|
||||
// shouldn't happen!
|
||||
break;
|
||||
if ($cnt === 0) {
|
||||
$this->element('p', 'error', _('No results.'));
|
||||
|
||||
$this->searchSuggestions($q);
|
||||
if (common_logged_in()) {
|
||||
$message = sprintf(_('Be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
|
||||
}
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
} else {
|
||||
$this->element('p', 'error', _('No results'));
|
||||
else {
|
||||
$message = sprintf(_('Why not [register an account](%%%%action.register%%%%) and be the first to [post on this topic](%%%%action.newnotice%%%%?status_textarea=%s)!'), urlencode($q));
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
return;
|
||||
}
|
||||
$terms = preg_split('/[\s,]+/', $q);
|
||||
$nl = new SearchNoticeList($notice, $this, $terms);
|
||||
$cnt = $nl->show();
|
||||
$this->pagination($page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$page, 'noticesearch', array('q' => $q));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice
|
||||
*
|
||||
* @param class $notice notice
|
||||
* @param array $terms terms to highlight
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @todo refactor and combine with StreamAction::showNotice()
|
||||
*/
|
||||
function showNotice($notice, $terms)
|
||||
{
|
||||
$profile = $notice->getProfile();
|
||||
if (!$profile) {
|
||||
common_log_db_error($notice, 'SELECT', __FILE__);
|
||||
$this->serverError(_('Notice without matching profile'));
|
||||
return;
|
||||
}
|
||||
// XXX: RDFa
|
||||
$this->elementStart('li', array('class' => 'hentry notice',
|
||||
'id' => 'notice-' . $notice->id));
|
||||
|
||||
$this->elementStart('div', 'entry-title');
|
||||
$this->elementStart('span', 'vcard author');
|
||||
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
||||
$this->elementStart('a', array('href' => $profile->profileurl,
|
||||
'class' => 'url'));
|
||||
$this->element('img', array('src' => ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE),
|
||||
'class' => 'avatar photo',
|
||||
'width' => AVATAR_STREAM_SIZE,
|
||||
'height' => AVATAR_STREAM_SIZE,
|
||||
'alt' =>
|
||||
($profile->fullname) ? $profile->fullname :
|
||||
$profile->nickname));
|
||||
$this->element('span', 'nickname fn', $profile->nickname);
|
||||
$this->elementEnd('a');
|
||||
$this->elementEnd('span');
|
||||
class SearchNoticeList extends NoticeList {
|
||||
function __construct($notice, $out=null, $terms)
|
||||
{
|
||||
parent::__construct($notice, $out);
|
||||
$this->terms = $terms;
|
||||
}
|
||||
|
||||
function newListItem($notice)
|
||||
{
|
||||
return new SearchNoticeListItem($notice, $this->out, $this->terms);
|
||||
}
|
||||
}
|
||||
|
||||
class SearchNoticeListItem extends NoticeListItem {
|
||||
function __construct($notice, $out=null, $terms)
|
||||
{
|
||||
parent::__construct($notice, $out);
|
||||
$this->terms = $terms;
|
||||
}
|
||||
|
||||
function showContent()
|
||||
{
|
||||
// FIXME: URL, image, video, audio
|
||||
$this->elementStart('p', array('class' => 'entry-content'));
|
||||
if ($notice->rendered) {
|
||||
$this->raw($this->highlight($notice->rendered, $terms));
|
||||
$this->out->elementStart('p', array('class' => 'entry-content'));
|
||||
if ($this->notice->rendered) {
|
||||
$this->out->raw($this->highlight($this->notice->rendered, $this->terms));
|
||||
} else {
|
||||
// XXX: may be some uncooked notices in the DB,
|
||||
// we cook them right now. This should probably disappear in future
|
||||
// versions (>> 0.4.x)
|
||||
$this->raw($this->highlight(common_render_content($notice->content, $notice), $terms));
|
||||
$this->out->raw($this->highlight(common_render_content($this->notice->content, $this->notice), $this->terms));
|
||||
}
|
||||
$this->elementEnd('p');
|
||||
$this->elementEnd('div');
|
||||
$this->out->elementEnd('p');
|
||||
|
||||
$noticeurl = common_local_url('shownotice', array('notice' => $notice->id));
|
||||
$this->elementStart('div', 'entry-content');
|
||||
$this->elementStart('dl', 'timestamp');
|
||||
$this->element('dt', null, _('Published'));
|
||||
$this->elementStart('dd', null);
|
||||
$this->elementStart('a', array('rel' => 'bookmark',
|
||||
'href' => $noticeurl));
|
||||
$dt = common_date_iso8601($notice->created);
|
||||
$this->element('abbr', array('class' => 'published',
|
||||
'title' => $dt),
|
||||
common_date_string($notice->created));
|
||||
$this->elementEnd('a');
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
if ($notice->reply_to) {
|
||||
$replyurl = common_local_url('shownotice',
|
||||
array('notice' => $this->notice->reply_to));
|
||||
$this->elementStart('dl', 'response');
|
||||
$this->element('dt', null, _('To'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $replyurl,
|
||||
'rel' => 'in-reply-to'),
|
||||
_('in reply to'));
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'notice-options');
|
||||
|
||||
$reply_url = common_local_url('newnotice',
|
||||
array('replyto' => $profile->nickname));
|
||||
|
||||
$this->elementStart('dl', 'notice_reply');
|
||||
$this->element('dt', null, _('Reply to this notice'));
|
||||
$this->elementStart('dd');
|
||||
$this->elementStart('a', array('href' => $reply_url,
|
||||
'title' => _('Reply to this notice')));
|
||||
$this->text(_('Reply'));
|
||||
$this->element('span', 'notice_id', $notice->id);
|
||||
$this->elementEnd('a');
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -242,21 +183,18 @@ class NoticesearchAction extends SearchAction
|
||||
*/
|
||||
function highlight($text, $terms)
|
||||
{
|
||||
/* Highligh serach terms */
|
||||
$pattern = '/('.implode('|', array_map('htmlspecialchars', $terms)).')/i';
|
||||
/* Highligh search terms */
|
||||
$options = implode('|', array_map('preg_quote', array_map('htmlspecialchars', $terms),
|
||||
array_fill(0, sizeof($terms), '/')));
|
||||
$pattern = "/($options)/i";
|
||||
$result = preg_replace($pattern, '<strong>\\1</strong>', $text);
|
||||
|
||||
/* Remove highlighting from inside links, loop incase multiple highlights in links */
|
||||
$pattern = '/(href="[^"]*)<strong>('.implode('|', array_map('htmlspecialchars', $terms)).')<\/strong>([^"]*")/iU';
|
||||
$pattern = '/(href="[^"]*)<strong>('.$options.')<\/strong>([^"]*")/iU';
|
||||
do {
|
||||
$result = preg_replace($pattern, '\\1\\2\\3', $result, -1, $count);
|
||||
} while ($count);
|
||||
return $result;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,6 @@ class NoticesearchrssAction extends Rss10Action
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
# lcase it for comparison
|
||||
$q = strtolower($q);
|
||||
|
||||
$search_engine = $notice->getSearchEngine('identica_notices');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
|
||||
@ -82,10 +79,9 @@ class NoticesearchrssAction extends Rss10Action
|
||||
|
||||
function getChannel()
|
||||
{
|
||||
global $config;
|
||||
$q = $this->trimmed('q');
|
||||
$c = array('url' => common_local_url('noticesearchrss', array('q' => $q)),
|
||||
'title' => $config['site']['name'] . sprintf(_(' Search Stream for "%s"'), $q),
|
||||
'title' => common_config('site', 'name') . sprintf(_(' Search Stream for "%s"'), $q),
|
||||
'link' => common_local_url('noticesearch', array('q' => $q)),
|
||||
'description' => sprintf(_('All updates matching search term "%s"'), $q));
|
||||
return $c;
|
||||
@ -96,7 +92,7 @@ class NoticesearchrssAction extends Rss10Action
|
||||
return null;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -100,7 +100,8 @@ class NudgeAction extends Action
|
||||
} else {
|
||||
// display a confirmation to the user
|
||||
common_redirect(common_local_url('showstream',
|
||||
array('nickname' => $other->nickname)));
|
||||
array('nickname' => $other->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,7 +124,7 @@ class NudgeAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ class OpensearchAction extends Action
|
||||
$this->endXML();
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -62,6 +62,17 @@ class OutboxAction extends MailboxAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'outbox', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve the messages for this user and this page
|
||||
*
|
||||
|
@ -60,16 +60,10 @@ class PeoplesearchAction extends SearchAction
|
||||
|
||||
function showResults($q, $page)
|
||||
{
|
||||
|
||||
$profile = new Profile();
|
||||
|
||||
# lcase it for comparison
|
||||
$q = strtolower($q);
|
||||
|
||||
$search_engine = $profile->getSearchEngine('identica_people');
|
||||
|
||||
$search_engine->set_sort_mode('chron');
|
||||
# Ask for an extra to see if there's more.
|
||||
// Ask for an extra to see if there's more.
|
||||
$search_engine->limit((($page-1)*PROFILES_PER_PAGE), PROFILES_PER_PAGE + 1);
|
||||
if (false === $search_engine->query($q)) {
|
||||
$cnt = 0;
|
||||
@ -81,38 +75,15 @@ class PeoplesearchAction extends SearchAction
|
||||
$terms = preg_split('/[\s,]+/', $q);
|
||||
$results = new PeopleSearchResults($profile, $terms, $this);
|
||||
$results->show();
|
||||
} else {
|
||||
$this->element('p', 'error', _('No results'));
|
||||
}
|
||||
|
||||
$profile->free();
|
||||
|
||||
$this->pagination($page > 1, $cnt > PROFILES_PER_PAGE,
|
||||
$page, 'peoplesearch', array('q' => $q));
|
||||
}
|
||||
}
|
||||
|
||||
class PeopleSearchResults extends ProfileList
|
||||
{
|
||||
var $terms = null;
|
||||
var $pattern = null;
|
||||
|
||||
function __construct($profile, $terms, $action)
|
||||
{
|
||||
parent::__construct($profile, $terms, $action);
|
||||
$this->terms = array_map('preg_quote',
|
||||
array_map('htmlspecialchars', $terms));
|
||||
$this->pattern = '/('.implode('|',$terms).')/i';
|
||||
}
|
||||
|
||||
function highlight($text)
|
||||
{
|
||||
return preg_replace($this->pattern, '<strong>\\1</strong>', htmlspecialchars($text));
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
{
|
||||
return true;
|
||||
|
||||
} else {
|
||||
$this->element('p', 'error', _('No results.'));
|
||||
$this->searchSuggestions($q);
|
||||
$profile->free();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,7 +119,7 @@ class PeopletagAction extends Action
|
||||
'FROM profile JOIN profile_tag ' .
|
||||
'ON profile.id = profile_tag.tagger ' .
|
||||
'WHERE profile_tag.tagger = profile_tag.tagged ' .
|
||||
'AND tag = "%s" ' .
|
||||
"AND tag = '%s' " .
|
||||
'ORDER BY profile_tag.modified DESC%s';
|
||||
|
||||
$profile->query(sprintf($qry, $this->tag, $lim));
|
||||
|
@ -28,7 +28,7 @@ class PostnoticeAction extends Action
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('postnotice'));
|
||||
# Note: server-to-server function!
|
||||
$server = omb_oauth_server();
|
||||
list($consumer, $token) = $server->verify_request($req);
|
||||
@ -79,7 +79,7 @@ class PostnoticeAction extends Action
|
||||
}
|
||||
$notice = Notice::staticGet('uri', $notice_uri);
|
||||
if (!$notice) {
|
||||
$notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, 0, $notice_uri);
|
||||
$notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
|
||||
if (is_string($notice)) {
|
||||
common_server_serror($notice, 500);
|
||||
return false;
|
||||
|
@ -91,9 +91,9 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
$this->element('legend', null, _('Profile information'));
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
# too much common patterns here... abstractable?
|
||||
|
||||
// too much common patterns here... abstractable?
|
||||
$this->elementStart('ul', 'form_data');
|
||||
if (Event::handle('StartProfileFormData', array($this))) {
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'),
|
||||
($this->arg('nickname')) ? $this->arg('nickname') : $profile->nickname,
|
||||
@ -118,6 +118,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
($this->arg('location')) ? $this->arg('location') : $profile->location,
|
||||
_('Where you are, like "City, State (or Region), Country"'));
|
||||
$this->elementEnd('li');
|
||||
Event::handle('EndProfileFormData', array($this));
|
||||
$this->elementStart('li');
|
||||
$this->input('tags', _('Tags'),
|
||||
($this->arg('tags')) ? $this->arg('tags') : implode(' ', $user->getSelfTags()),
|
||||
@ -127,7 +128,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
$language = common_language();
|
||||
$this->dropdown('language', _('Language'),
|
||||
get_nice_language_list(), _('Preferred language'),
|
||||
true, $language);
|
||||
false, $language);
|
||||
$this->elementEnd('li');
|
||||
$timezone = common_timezone();
|
||||
$timezones = array();
|
||||
@ -146,12 +147,12 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
($this->arg('autosubscribe')) ?
|
||||
$this->boolean('autosubscribe') : $user->autosubscribe);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('save', _('Save'));
|
||||
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,8 +166,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
|
||||
function handlePost()
|
||||
{
|
||||
# CSRF protection
|
||||
|
||||
// CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
@ -174,6 +174,8 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
return;
|
||||
}
|
||||
|
||||
if (Event::handle('StartProfileSaveForm', array($this))) {
|
||||
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
@ -184,8 +186,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
$timezone = $this->trimmed('timezone');
|
||||
$tagstring = $this->trimmed('tags');
|
||||
|
||||
# Some validation
|
||||
|
||||
// Some validation
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
@ -259,13 +260,12 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
$this->serverError(_('Couldn\'t update user.'));
|
||||
return;
|
||||
} else {
|
||||
# Re-initialize language environment if it changed
|
||||
// Re-initialize language environment if it changed
|
||||
common_init_language();
|
||||
}
|
||||
}
|
||||
|
||||
# XXX: XOR
|
||||
|
||||
// XXX: XOR
|
||||
if ($user->autosubscribe ^ $autosubscribe) {
|
||||
|
||||
$original = clone($user);
|
||||
@ -303,8 +303,7 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
return;
|
||||
}
|
||||
|
||||
# Set the user tags
|
||||
|
||||
// Set the user tags
|
||||
$result = $user->setSelfTags($tags);
|
||||
|
||||
if (!$result) {
|
||||
@ -313,10 +312,12 @@ class ProfilesettingsAction extends AccountSettingsAction
|
||||
}
|
||||
|
||||
$user->query('COMMIT');
|
||||
|
||||
Event::handle('EndProfileSaveForm', array($this));
|
||||
common_broadcast_profile($profile);
|
||||
|
||||
$this->showForm(_('Settings saved.'), true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function nicknameExists($nickname)
|
||||
|
@ -56,7 +56,7 @@ class PublicAction extends Action
|
||||
|
||||
var $page = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -135,6 +135,17 @@ class PublicAction extends Action
|
||||
_('Public Stream Feed (Atom)')));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra head elements
|
||||
*
|
||||
@ -166,6 +177,22 @@ class PublicAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
function showEmptyList()
|
||||
{
|
||||
$message = _('This is the public timeline for %%site.name%% but no one has posted anything yet.') . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$message .= _('Be the first to post!');
|
||||
}
|
||||
else {
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to post!');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the content area
|
||||
*
|
||||
@ -189,6 +216,10 @@ class PublicAction extends Action
|
||||
|
||||
$cnt = $nl->show();
|
||||
|
||||
if ($cnt == 0) {
|
||||
$this->showEmptyList();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'public');
|
||||
}
|
||||
@ -207,9 +238,14 @@ class PublicAction extends Action
|
||||
|
||||
function showAnonymousMessage()
|
||||
{
|
||||
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
|
||||
'[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))');
|
||||
} else {
|
||||
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool.');
|
||||
}
|
||||
$this->elementStart('div', array('id' => 'anon_notice'));
|
||||
$this->raw(common_markup_to_html($m));
|
||||
$this->elementEnd('div');
|
||||
|
@ -84,12 +84,11 @@ class PublicrssAction extends Rss10Action
|
||||
*/
|
||||
function getChannel()
|
||||
{
|
||||
global $config;
|
||||
$c = array(
|
||||
'url' => common_local_url('publicrss')
|
||||
, 'title' => sprintf(_('%s Public Stream'), $config['site']['name'])
|
||||
, 'title' => sprintf(_('%s Public Stream'), common_config('site', 'name'))
|
||||
, 'link' => common_local_url('public')
|
||||
, 'description' => sprintf(_('All updates for %s'), $config['site']['name']));
|
||||
, 'description' => sprintf(_('All updates for %s'), common_config('site', 'name')));
|
||||
return $c;
|
||||
}
|
||||
|
||||
@ -103,7 +102,7 @@ class PublicrssAction extends Rss10Action
|
||||
// nop
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ define('TAGS_PER_PAGE', 100);
|
||||
|
||||
class PublictagcloudAction extends Action
|
||||
{
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -64,6 +64,22 @@ class PublictagcloudAction extends Action
|
||||
common_config('site', 'name')));
|
||||
}
|
||||
|
||||
function showEmptyList()
|
||||
{
|
||||
$message = _('No one has posted a notice with a [hashtag](%%doc.tags%%) yet.') . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$message .= _('Be the first to post one!');
|
||||
}
|
||||
else {
|
||||
$message .= _('Why not [register an account](%%action.register%%) and be the first to post one!');
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showLocalNav()
|
||||
{
|
||||
$nav = new PublicGroupNav($this);
|
||||
@ -126,6 +142,8 @@ class PublictagcloudAction extends Action
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
$this->elementEnd('div');
|
||||
} else {
|
||||
$this->showEmptyList();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ class PublicxrdsAction extends Action
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -70,19 +70,19 @@ class PublicxrdsAction extends Action
|
||||
{
|
||||
parent::handle($args);
|
||||
header('Content-Type: application/xrds+xml');
|
||||
common_start_xml();
|
||||
$this->startXML();
|
||||
$this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
|
||||
$this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
|
||||
'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
|
||||
'version' => '2.0'));
|
||||
$this->element('Type', null, 'xri://$xrds*simple');
|
||||
foreach (array('finishopenidlogin', 'finishaddopenid', 'finishimmediate') as $finish) {
|
||||
foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
|
||||
$this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
|
||||
common_local_url($finish));
|
||||
}
|
||||
$this->elementEnd('XRD');
|
||||
$this->elementEnd('XRDS');
|
||||
common_end_xml();
|
||||
$this->endXML();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -181,13 +181,21 @@ class RecoverpasswordAction extends Action
|
||||
function showRecoverForm()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'recoverpassword',
|
||||
'id' => 'form_password_recover',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('recoverpassword')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Password recover'));
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->input('nicknameoremail', _('Nickname or email'),
|
||||
$this->trimmed('nicknameoremail'),
|
||||
_('Your nickname on this server, ' .
|
||||
'or your registered email address.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('recover', _('Recover'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
@ -213,14 +221,24 @@ class RecoverpasswordAction extends Action
|
||||
function showResetForm()
|
||||
{
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'recoverpassword',
|
||||
'id' => 'form_password_change',
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('recoverpassword')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Password change'));
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->password('newpassword', _('New password'),
|
||||
_('6 or more characters, and don\'t forget it!'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
$this->password('confirm', _('Confirm'),
|
||||
_('Same as password above'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('reset', _('Reset'));
|
||||
$this->elementEnd('fieldset');
|
||||
$this->elementEnd('form');
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,45 @@ class RegisterAction extends Action
|
||||
|
||||
var $registered = false;
|
||||
|
||||
/**
|
||||
* Prepare page to run
|
||||
*
|
||||
*
|
||||
* @param $args
|
||||
* @return string title
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$this->code = $this->trimmed('code');
|
||||
|
||||
if (empty($this->code)) {
|
||||
common_ensure_session();
|
||||
if (array_key_exists('invitecode', $_SESSION)) {
|
||||
$this->code = $_SESSION['invitecode'];
|
||||
}
|
||||
}
|
||||
|
||||
if (common_config('site', 'inviteonly') && empty($this->code)) {
|
||||
$this->clientError(_('Sorry, only invited people can register.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($this->code)) {
|
||||
$this->invite = Invitation::staticGet('code', $this->code);
|
||||
if (empty($this->invite)) {
|
||||
$this->clientError(_('Sorry, invalid invitation code.'));
|
||||
return false;
|
||||
}
|
||||
// Store this in case we need it
|
||||
common_ensure_session();
|
||||
$_SESSION['invitecode'] = $this->code;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Title of the page
|
||||
*
|
||||
@ -108,6 +147,7 @@ class RegisterAction extends Action
|
||||
|
||||
function tryRegister()
|
||||
{
|
||||
if (Event::handle('StartRegistrationTry', array($this))) {
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$this->showForm(_('There was a problem with your session token. '.
|
||||
@ -123,12 +163,10 @@ class RegisterAction extends Action
|
||||
$location = $this->trimmed('location');
|
||||
|
||||
// We don't trim these... whitespace is OK in a password!
|
||||
|
||||
$password = $this->arg('password');
|
||||
$confirm = $this->arg('confirm');
|
||||
|
||||
// invitation code, if any
|
||||
|
||||
$code = $this->trimmed('code');
|
||||
|
||||
if ($code) {
|
||||
@ -141,7 +179,6 @@ class RegisterAction extends Action
|
||||
}
|
||||
|
||||
// Input scrubbing
|
||||
|
||||
$nickname = common_canonical_nickname($nickname);
|
||||
$email = common_canonical_email($email);
|
||||
|
||||
@ -204,6 +241,9 @@ class RegisterAction extends Action
|
||||
common_debug('Adding rememberme cookie for ' . $nickname);
|
||||
common_rememberme($user);
|
||||
}
|
||||
|
||||
Event::handle('EndRegistrationTry', array($this));
|
||||
|
||||
// Re-init language env in case it changed (not yet, but soon)
|
||||
common_init_language();
|
||||
$this->showSuccess();
|
||||
@ -211,6 +251,7 @@ class RegisterAction extends Action
|
||||
$this->showForm(_('Invalid username or password.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the given nickname already exist?
|
||||
@ -250,8 +291,10 @@ class RegisterAction extends Action
|
||||
|
||||
// overrrided to add entry-title class
|
||||
function showPageTitle() {
|
||||
if (Event::handle('StartShowPageTitle', array($this))) {
|
||||
$this->element('h1', array('class' => 'entry-title'), $this->title());
|
||||
}
|
||||
}
|
||||
|
||||
// overrided to add hentry, and content-inner class
|
||||
function showContentBlock()
|
||||
@ -341,6 +384,8 @@ class RegisterAction extends Action
|
||||
{
|
||||
$code = $this->trimmed('code');
|
||||
|
||||
$invite = null;
|
||||
|
||||
if ($code) {
|
||||
$invite = Invitation::staticGet($code);
|
||||
}
|
||||
@ -358,11 +403,12 @@ class RegisterAction extends Action
|
||||
$this->element('legend', null, 'Account settings');
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
if ($code) {
|
||||
$this->hidden('code', $code);
|
||||
if ($this->code) {
|
||||
$this->hidden('code', $this->code);
|
||||
}
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
if (Event::handle('StartRegistrationFormData', array($this))) {
|
||||
$this->elementStart('li');
|
||||
$this->input('nickname', _('Nickname'), $this->trimmed('nickname'),
|
||||
_('1-64 lowercase letters or numbers, '.
|
||||
@ -377,8 +423,8 @@ class RegisterAction extends Action
|
||||
_('Same as password above. Required.'));
|
||||
$this->elementEnd('li');
|
||||
$this->elementStart('li');
|
||||
if ($invite && $invite->address_type == 'email') {
|
||||
$this->input('email', _('Email'), $invite->address,
|
||||
if ($this->invite && $this->invite->address_type == 'email') {
|
||||
$this->input('email', _('Email'), $this->invite->address,
|
||||
_('Used only for updates, announcements, '.
|
||||
'and password recovery'));
|
||||
} else {
|
||||
@ -410,6 +456,7 @@ class RegisterAction extends Action
|
||||
_('Where you are, like "City, '.
|
||||
'State (or Region), Country"'));
|
||||
$this->elementEnd('li');
|
||||
Event::handle('EndRegistrationFormData', array($this));
|
||||
$this->elementStart('li', array('id' => 'settings_rememberme'));
|
||||
$this->checkbox('rememberme', _('Remember me'),
|
||||
$this->boolean('rememberme'),
|
||||
@ -434,6 +481,7 @@ class RegisterAction extends Action
|
||||
'email address, IM address, and phone number.'));
|
||||
$this->elementEnd('label');
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
$this->submit('submit', _('Register'));
|
||||
$this->elementEnd('fieldset');
|
||||
@ -515,3 +563,4 @@ class RegisterAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ class RemotesubscribeAction extends Action
|
||||
'class' => 'form_settings',
|
||||
'action' => common_local_url('remotesubscribe')));
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', 'Subscribe to a remote user');
|
||||
$this->element('legend', _('Subscribe to a remote user'));
|
||||
$this->hidden('token', common_session_token());
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
@ -321,8 +321,7 @@ class RemotesubscribeAction extends Action
|
||||
|
||||
$result = $fetcher->post($req->get_normalized_http_url(),
|
||||
$req->to_postdata(),
|
||||
array('User-Agent' => 'Laconica/' . LACONICA_VERSION));
|
||||
|
||||
array('User-Agent: Laconica/' . LACONICA_VERSION));
|
||||
if ($result->status != 200) {
|
||||
return null;
|
||||
}
|
||||
@ -334,8 +333,6 @@ class RemotesubscribeAction extends Action
|
||||
|
||||
function requestAuthorization($user, $omb, $token, $secret)
|
||||
{
|
||||
global $config; # for license URL
|
||||
|
||||
$con = omb_oauth_consumer();
|
||||
$tok = new OAuthToken($token, $secret);
|
||||
|
||||
@ -359,7 +356,7 @@ class RemotesubscribeAction extends Action
|
||||
$req->set_parameter('omb_listenee', $user->uri);
|
||||
$req->set_parameter('omb_listenee_profile', common_profile_url($user->nickname));
|
||||
$req->set_parameter('omb_listenee_nickname', $user->nickname);
|
||||
$req->set_parameter('omb_listenee_license', $config['license']['url']);
|
||||
$req->set_parameter('omb_listenee_license', common_config('license', 'url'));
|
||||
|
||||
$profile = $user->getProfile();
|
||||
if (!$profile) {
|
||||
@ -368,16 +365,16 @@ class RemotesubscribeAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
if ($profile->fullname) {
|
||||
if (!is_null($profile->fullname)) {
|
||||
$req->set_parameter('omb_listenee_fullname', $profile->fullname);
|
||||
}
|
||||
if ($profile->homepage) {
|
||||
if (!is_null($profile->homepage)) {
|
||||
$req->set_parameter('omb_listenee_homepage', $profile->homepage);
|
||||
}
|
||||
if ($profile->bio) {
|
||||
if (!is_null($profile->bio)) {
|
||||
$req->set_parameter('omb_listenee_bio', $profile->bio);
|
||||
}
|
||||
if ($profile->location) {
|
||||
if (!is_null($profile->location)) {
|
||||
$req->set_parameter('omb_listenee_location', $profile->location);
|
||||
}
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
@ -410,7 +407,7 @@ class RemotesubscribeAction extends Action
|
||||
|
||||
# Redirect to authorization service
|
||||
|
||||
common_redirect($req->to_url());
|
||||
common_redirect($req->to_url(), 303);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -138,6 +138,17 @@ class RepliesAction extends Action
|
||||
return array(new Feed(Feed::RSS1, $rssurl, $rsstitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'replies', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* show the personal group nav
|
||||
*
|
||||
@ -166,13 +177,37 @@ class RepliesAction extends Action
|
||||
$nl = new NoticeList($notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
if (0 === $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'replies',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('This is the timeline showing replies to %s but %s hasn\'t received a notice to his attention yet.'), $this->user->nickname, $this->user->nickname) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message .= _('You can engage other users in a conversation, subscribe to more people or [join groups](%%action.groups%%).');
|
||||
} else {
|
||||
$message .= sprintf(_('You can try to [nudge %s](../%s) or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, $this->user->nickname, '@' . $this->user->nickname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ class RepliesrssAction extends Rss10Action
|
||||
return ($avatar) ? $avatar->url : null;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class RequesttokenAction extends Action
|
||||
*
|
||||
* @return boolean false
|
||||
*/
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -69,7 +69,7 @@ class RequesttokenAction extends Action
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('requesttoken'));
|
||||
$server = omb_oauth_server();
|
||||
$token = $server->fetch_request_token($req);
|
||||
print $token;
|
||||
|
@ -58,7 +58,7 @@ class ShowfavoritesAction extends Action
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -74,9 +74,9 @@ class ShowfavoritesAction extends Action
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("%s favorite notices"), $this->user->nickname);
|
||||
return sprintf(_("%s's favorite notices"), $this->user->nickname);
|
||||
} else {
|
||||
return sprintf(_("%s favorite notices, page %d"),
|
||||
return sprintf(_("%s's favorite notices, page %d"),
|
||||
$this->user->nickname,
|
||||
$this->page);
|
||||
}
|
||||
@ -150,6 +150,18 @@ class ShowfavoritesAction extends Action
|
||||
return array(new Feed(Feed::RSS1, $feedurl, $feedtitle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'showfavorites', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* show the personal group nav
|
||||
*
|
||||
@ -162,6 +174,25 @@ class ShowfavoritesAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message = _('You haven\'t chosen any favorite notices yet. Click the fave button on notices you like to bookmark them for later or shed a spotlight on them.');
|
||||
} else {
|
||||
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Post something interesting they would add to their favorites :)'), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message = sprintf(_('%s hasn\'t added any notices to his favorites yet. Why not [register an account](%%%%action.register%%%%) and then post something interesting they would add to thier favorites :)'), $this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the content
|
||||
*
|
||||
@ -183,9 +214,17 @@ class ShowfavoritesAction extends Action
|
||||
$nl = new NoticeList($notice, $this);
|
||||
|
||||
$cnt = $nl->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'showfavorites',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function showPageNotice() {
|
||||
$this->element('p', 'instructions', _('This is a way to share what you like.'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ if (!defined('LACONICA')) {
|
||||
require_once INSTALLDIR.'/lib/noticelist.php';
|
||||
require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
|
||||
define('MEMBERS_PER_SECTION', 81);
|
||||
define('MEMBERS_PER_SECTION', 27);
|
||||
|
||||
/**
|
||||
* Group main page
|
||||
@ -60,7 +60,7 @@ class ShowgroupAction extends Action
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -73,11 +73,17 @@ class ShowgroupAction extends Action
|
||||
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->group->fullname)) {
|
||||
$base = $this->group->fullname . ' (' . $this->group->nickname . ')';
|
||||
} else {
|
||||
$base = $this->group->nickname;
|
||||
}
|
||||
|
||||
if ($this->page == 1) {
|
||||
return sprintf(_("%s group"), $this->group->nickname);
|
||||
return sprintf(_("%s group"), $base);
|
||||
} else {
|
||||
return sprintf(_("%s group, page %d"),
|
||||
$this->group->nickname,
|
||||
$base,
|
||||
$this->page);
|
||||
}
|
||||
}
|
||||
@ -275,10 +281,8 @@ class ShowgroupAction extends Action
|
||||
$cur = common_current_user();
|
||||
if ($cur) {
|
||||
if ($cur->isMember($this->group)) {
|
||||
if (!$cur->isAdmin($this->group)) {
|
||||
$lf = new LeaveForm($this, $this->group);
|
||||
$lf->show();
|
||||
}
|
||||
} else {
|
||||
$jf = new JoinForm($this, $this->group);
|
||||
$jf->show();
|
||||
@ -307,6 +311,17 @@ class ShowgroupAction extends Action
|
||||
$this->group->nickname)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'showgroup', array('nickname' => $this->group->nickname));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill in the sidebar.
|
||||
*
|
||||
@ -346,7 +361,7 @@ class ShowgroupAction extends Action
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
|
||||
if ($cnt == MEMBERS_PER_SECTION) {
|
||||
if ($cnt > MEMBERS_PER_SECTION) {
|
||||
$this->element('a', array('href' => common_local_url('groupmembers',
|
||||
array('nickname' => $this->group->nickname))),
|
||||
_('All members'));
|
||||
@ -392,11 +407,18 @@ class ShowgroupAction extends Action
|
||||
|
||||
function showAnonymousMessage()
|
||||
{
|
||||
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
|
||||
'short messages about their life and interests. '.
|
||||
'[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->group->nickname);
|
||||
} else {
|
||||
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
|
||||
'short messages about their life and interests. '),
|
||||
$this->group->nickname);
|
||||
}
|
||||
$this->elementStart('div', array('id' => 'anon_notice'));
|
||||
$this->raw(common_markup_to_html($m));
|
||||
$this->elementEnd('div');
|
||||
|
@ -177,7 +177,7 @@ class ShowmessageAction extends MailboxAction
|
||||
return '';
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ class ShownoticeAction extends Action
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -177,9 +177,16 @@ class ShownoticeAction extends Action
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
if ($this->notice->is_local == 0) {
|
||||
if (!empty($this->notice->url)) {
|
||||
common_redirect($this->notice->url, 301);
|
||||
} else if (!empty($this->notice->uri) && preg_match('/^https?:/', $this->notice->uri)) {
|
||||
common_redirect($this->notice->uri, 301);
|
||||
}
|
||||
} else {
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't show local navigation
|
||||
@ -191,7 +198,6 @@ class ShownoticeAction extends Action
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fill the content area of the page
|
||||
*
|
||||
@ -208,8 +214,6 @@ class ShownoticeAction extends Action
|
||||
$this->elementEnd('ul');
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Don't show page notice
|
||||
*
|
||||
@ -220,7 +224,6 @@ class ShownoticeAction extends Action
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Don't show aside
|
||||
*
|
||||
@ -230,7 +233,6 @@ class ShownoticeAction extends Action
|
||||
function showAside() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extra <head> content
|
||||
*
|
||||
|
@ -54,67 +54,33 @@ require_once INSTALLDIR.'/lib/feedlist.php';
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
class ShowstreamAction extends Action
|
||||
class ShowstreamAction extends ProfileAction
|
||||
{
|
||||
var $user = null;
|
||||
var $page = null;
|
||||
var $profile = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
if (!empty($this->profile->fullname)) {
|
||||
$base = $this->profile->fullname . ' (' . $this->user->nickname . ') ';
|
||||
} else {
|
||||
$base = $this->user->nickname;
|
||||
}
|
||||
if (!empty($this->tag)) {
|
||||
$base .= sprintf(_(' tagged %s'), $this->tag);
|
||||
}
|
||||
|
||||
if ($this->page == 1) {
|
||||
return $this->user->nickname;
|
||||
return $base;
|
||||
} else {
|
||||
return sprintf(_("%s, page %d"),
|
||||
$this->user->nickname,
|
||||
$base,
|
||||
$this->page);
|
||||
}
|
||||
}
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$nickname_arg = $this->arg('nickname');
|
||||
$nickname = common_canonical_nickname($nickname_arg);
|
||||
|
||||
// Permanent redirect on non-canonical nickname
|
||||
|
||||
if ($nickname_arg != $nickname) {
|
||||
$args = array('nickname' => $nickname);
|
||||
if ($this->arg('page') && $this->arg('page') != 1) {
|
||||
$args['page'] = $this->arg['page'];
|
||||
}
|
||||
common_redirect(common_local_url('showstream', $args), 301);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->user = User::staticGet('nickname', $nickname);
|
||||
|
||||
if (!$this->user) {
|
||||
$this->clientError(_('No such user.'), 404);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->profile = $this->user->getProfile();
|
||||
|
||||
if (!$this->profile) {
|
||||
$this->serverError(_('User has no profile.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
|
||||
common_set_returnto($this->selfUrl());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
|
||||
@ -140,16 +106,6 @@ class ShowstreamAction extends Action
|
||||
$nav->show();
|
||||
}
|
||||
|
||||
function showPageTitle()
|
||||
{
|
||||
$user =& common_current_user();
|
||||
if ($user && ($user->id == $this->profile->id)) {
|
||||
$this->element('h1', NULL, _("Your profile"));
|
||||
} else {
|
||||
$this->element('h1', NULL, sprintf(_('%s\'s profile'), $this->profile->nickname));
|
||||
}
|
||||
}
|
||||
|
||||
function showPageNoticeBlock()
|
||||
{
|
||||
return;
|
||||
@ -157,6 +113,15 @@ class ShowstreamAction extends Action
|
||||
|
||||
function getFeeds()
|
||||
{
|
||||
if (!empty($this->tag)) {
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('userrss',
|
||||
array('nickname' => $this->user->nickname,
|
||||
'tag' => $this->tag)),
|
||||
sprintf(_('Notice feed for %s tagged %s (RSS 1.0)'),
|
||||
$this->user->nickname, $this->tag)));
|
||||
}
|
||||
|
||||
return array(new Feed(Feed::RSS1,
|
||||
common_local_url('userrss',
|
||||
array('nickname' => $this->user->nickname)),
|
||||
@ -182,6 +147,17 @@ class ShowstreamAction extends Action
|
||||
sprintf(_('FOAF for %s'), $this->user->nickname)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'showstream', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function extraHead()
|
||||
{
|
||||
// for remote subscriptions etc.
|
||||
@ -292,11 +268,11 @@ class ShowstreamAction extends Action
|
||||
$this->elementStart('ul', 'tags xoxo');
|
||||
foreach ($tags as $tag) {
|
||||
$this->elementStart('li');
|
||||
$this->element('span', 'mark_hash', '#');
|
||||
$this->element('a', array('rel' => 'tag',
|
||||
'href' => common_local_url('peopletag',
|
||||
array('tag' => $tag))),
|
||||
$tag);
|
||||
// Avoid space by using raw output.
|
||||
$pt = '<span class="mark_hash">#</span><a rel="tag" href="' .
|
||||
common_local_url('peopletag', array('tag' => $tag)) .
|
||||
'">' . $tag . '</a>';
|
||||
$this->raw($pt);
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
@ -376,178 +352,66 @@ class ShowstreamAction extends Action
|
||||
_('Subscribe'));
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('This is the timeline for %s but %s hasn\'t posted anything yet.'), $this->user->nickname, $this->user->nickname) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message .= _('Seen anything interesting recently? You haven\'t posted any notices yet, now would be a good time to start :)');
|
||||
} else {
|
||||
$message .= sprintf(_('You can try to nudge %s or [post something to his or her attention](%%%%action.newnotice%%%%?status_textarea=%s).'), $this->user->nickname, '@' . $this->user->nickname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message .= sprintf(_('Why not [register an account](%%%%action.register%%%%) and then nudge %s or post a notice to his or her attention.'), $this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showNotices()
|
||||
{
|
||||
$notice = $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
|
||||
$notice = empty($this->tag)
|
||||
? $this->user->getNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1)
|
||||
: $this->user->getTaggedNotices(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1, 0, 0, null, $this->tag);
|
||||
|
||||
$pnl = new ProfileNoticeList($notice, $this);
|
||||
$cnt = $pnl->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
|
||||
$this->pagination($this->page>1, $cnt>NOTICES_PER_PAGE, $this->page,
|
||||
'showstream', array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
$this->showSubscriptions();
|
||||
$this->showSubscribers();
|
||||
$this->showGroups();
|
||||
$this->showStatistics();
|
||||
$cloud = new PersonalTagCloudSection($this, $this->user);
|
||||
$cloud->show();
|
||||
}
|
||||
|
||||
function showSubscriptions()
|
||||
{
|
||||
$profile = $this->user->getSubscriptions(0, PROFILES_PER_MINILIST + 1);
|
||||
|
||||
$this->elementStart('div', array('id' => 'entity_subscriptions',
|
||||
'class' => 'section'));
|
||||
|
||||
$this->element('h2', null, _('Subscriptions'));
|
||||
|
||||
if ($profile) {
|
||||
$pml = new ProfileMiniList($profile, $this->user, $this);
|
||||
$cnt = $pml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > PROFILES_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('subscriptions',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All subscriptions'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSubscribers()
|
||||
{
|
||||
$profile = $this->user->getSubscribers(0, PROFILES_PER_MINILIST + 1);
|
||||
|
||||
$this->elementStart('div', array('id' => 'entity_subscribers',
|
||||
'class' => 'section'));
|
||||
|
||||
$this->element('h2', null, _('Subscribers'));
|
||||
|
||||
if ($profile) {
|
||||
$pml = new ProfileMiniList($profile, $this->user, $this);
|
||||
$cnt = $pml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > PROFILES_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('subscribers',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All subscribers'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showStatistics()
|
||||
{
|
||||
// XXX: WORM cache this
|
||||
$subs = new Subscription();
|
||||
$subs->subscriber = $this->profile->id;
|
||||
$subs_count = (int) $subs->count() - 1;
|
||||
|
||||
$subbed = new Subscription();
|
||||
$subbed->subscribed = $this->profile->id;
|
||||
$subbed_count = (int) $subbed->count() - 1;
|
||||
|
||||
$notices = new Notice();
|
||||
$notices->profile_id = $this->profile->id;
|
||||
$notice_count = (int) $notices->count();
|
||||
|
||||
$this->elementStart('div', array('id' => 'entity_statistics',
|
||||
'class' => 'section'));
|
||||
|
||||
$this->element('h2', null, _('Statistics'));
|
||||
|
||||
// Other stats...?
|
||||
$this->elementStart('dl', 'entity_member-since');
|
||||
$this->element('dt', null, _('Member since'));
|
||||
$this->element('dd', null, date('j M Y',
|
||||
strtotime($this->profile->created)));
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_subscriptions');
|
||||
$this->elementStart('dt');
|
||||
$this->element('a', array('href' => common_local_url('subscriptions',
|
||||
array('nickname' => $this->profile->nickname))),
|
||||
_('Subscriptions'));
|
||||
$this->elementEnd('dt');
|
||||
$this->element('dd', null, (is_int($subs_count)) ? $subs_count : '0');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_subscribers');
|
||||
$this->elementStart('dt');
|
||||
$this->element('a', array('href' => common_local_url('subscribers',
|
||||
array('nickname' => $this->profile->nickname))),
|
||||
_('Subscribers'));
|
||||
$this->elementEnd('dt');
|
||||
$this->element('dd', 'subscribers', (is_int($subbed_count)) ? $subbed_count : '0');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_notices');
|
||||
$this->element('dt', null, _('Notices'));
|
||||
$this->element('dd', null, (is_int($notice_count)) ? $notice_count : '0');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showGroups()
|
||||
{
|
||||
$groups = $this->user->getGroups(0, GROUPS_PER_MINILIST + 1);
|
||||
|
||||
$this->elementStart('div', array('id' => 'entity_groups',
|
||||
'class' => 'section'));
|
||||
|
||||
$this->element('h2', null, _('Groups'));
|
||||
|
||||
if ($groups) {
|
||||
$gml = new GroupMiniList($groups, $this->user, $this);
|
||||
$cnt = $gml->show();
|
||||
if ($cnt == 0) {
|
||||
$this->element('p', null, _('(None)'));
|
||||
}
|
||||
}
|
||||
|
||||
if ($cnt > GROUPS_PER_MINILIST) {
|
||||
$this->elementStart('p');
|
||||
$this->element('a', array('href' => common_local_url('usergroups',
|
||||
array('nickname' => $this->profile->nickname)),
|
||||
'class' => 'more'),
|
||||
_('All groups'));
|
||||
$this->elementEnd('p');
|
||||
}
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showAnonymousMessage()
|
||||
{
|
||||
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
|
||||
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
|
||||
'[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
|
||||
$this->user->nickname, $this->user->nickname);
|
||||
} else {
|
||||
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
|
||||
'based on the Free Software [Laconica](http://laconi.ca/) tool. '),
|
||||
$this->user->nickname, $this->user->nickname);
|
||||
}
|
||||
$this->elementStart('div', array('id' => 'anon_notice'));
|
||||
$this->raw(common_markup_to_html($m));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
parent::showSections();
|
||||
$cloud = new PersonalTagCloudSection($this, $this->user);
|
||||
$cloud->show();
|
||||
}
|
||||
}
|
||||
|
||||
// We don't show the author for a profile, since we already know who it is!
|
||||
|
@ -488,7 +488,8 @@ class SmssettingsAction extends ConnectSettingsAction
|
||||
}
|
||||
|
||||
common_redirect(common_local_url('confirmaddress',
|
||||
array('code' => $code)));
|
||||
array('code' => $code)),
|
||||
303);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -85,7 +85,8 @@ class SubeditAction extends Action
|
||||
}
|
||||
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $cur->nickname)));
|
||||
array('nickname' => $cur->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,8 @@ class SubscribeAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
||||
$user->nickname)));
|
||||
$user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,9 @@ class SubscribersAction extends GalleryAction
|
||||
if ($subscribers) {
|
||||
$subscribers_list = new SubscribersList($subscribers, $this->user, $this);
|
||||
$cnt = $subscribers_list->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$subscribers->free();
|
||||
@ -96,6 +99,35 @@ class SubscribersAction extends GalleryAction
|
||||
$this->page, 'subscribers',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message = _('You have no subscribers. Try subscribing to people you know and they might return the favor');
|
||||
} else {
|
||||
$message = sprintf(_('%s has no subscribers. Want to be the first?'), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message = sprintf(_('%s has no subscribers. Why not [register an account](%%%%action.register%%%%) and be the first?'), $this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
parent::showSections();
|
||||
$cloud = new SubscribersPeopleTagCloudSection($this);
|
||||
$cloud->show();
|
||||
|
||||
$cloud2 = new SubscribersPeopleSelfTagCloudSection($this);
|
||||
$cloud2->show();
|
||||
}
|
||||
}
|
||||
|
||||
class SubscribersList extends ProfileList
|
||||
@ -108,7 +140,7 @@ class SubscribersList extends ProfileList
|
||||
$bf->show();
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -95,6 +95,9 @@ class SubscriptionsAction extends GalleryAction
|
||||
if ($subscriptions) {
|
||||
$subscriptions_list = new SubscriptionsList($subscriptions, $this->user, $this);
|
||||
$cnt = $subscriptions_list->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$subscriptions->free();
|
||||
@ -103,6 +106,35 @@ class SubscriptionsAction extends GalleryAction
|
||||
$this->page, 'subscriptions',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message = _('You\'re not listening to anyone\'s notices right now, try subscribing to people you know. Try [people search](%%action.peoplesearch%%), look for members in groups you\'re interested in and in our [featured users](%%action.featured%%). If you\'re a [Twitter user](%%action.twittersettings%%), you can automatically subscribe to people you already follow there.');
|
||||
} else {
|
||||
$message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$message = sprintf(_('%s is not listening to anyone.'), $this->user->nickname);
|
||||
}
|
||||
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
parent::showSections();
|
||||
$cloud = new SubscriptionsPeopleTagCloudSection($this);
|
||||
$cloud->show();
|
||||
|
||||
$cloud2 = new SubscriptionsPeopleSelfTagCloudSection($this);
|
||||
$cloud2->show();
|
||||
}
|
||||
}
|
||||
|
||||
class SubscriptionsList extends ProfileList
|
||||
@ -117,7 +149,7 @@ class SubscriptionsList extends ProfileList
|
||||
|
||||
$this->out->elementStart('form', array('id' => 'subedit-' . $profile->id,
|
||||
'method' => 'post',
|
||||
'class' => 'form_subcription_edit',
|
||||
'class' => 'form_subscription_edit',
|
||||
'action' => common_local_url('subedit')));
|
||||
$this->out->hidden('token', common_session_token());
|
||||
$this->out->hidden('profile', $profile->id);
|
||||
|
@ -65,7 +65,9 @@ class SupAction extends Action
|
||||
|
||||
$notice->query('SELECT profile_id, max(id) AS max_id ' .
|
||||
'FROM notice ' .
|
||||
'WHERE created > (now() - ' . $seconds . ') ' .
|
||||
((common_config('db','type') == 'pgsql') ?
|
||||
'WHERE extract(epoch from created) > (extract(epoch from now()) - ' . $seconds . ') ' :
|
||||
'WHERE created > (now() - ' . $seconds . ') ' ) .
|
||||
'GROUP BY profile_id');
|
||||
|
||||
$updates = array();
|
||||
@ -77,7 +79,7 @@ class SupAction extends Action
|
||||
return $updates;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -33,7 +33,9 @@ class TagAction extends Action
|
||||
}
|
||||
|
||||
if ($this->tag != $taginput) {
|
||||
common_redirect(common_local_url('tag', array('tag' => $this->tag)));
|
||||
common_redirect(common_local_url('tag', array('tag' => $this->tag)),
|
||||
301);
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
|
||||
@ -43,6 +45,14 @@ class TagAction extends Action
|
||||
return true;
|
||||
}
|
||||
|
||||
function showSections()
|
||||
{
|
||||
$pop = new PopularNoticeSection($this);
|
||||
$pop->show();
|
||||
$freqatt = new FrequentAttachmentSection($this);
|
||||
$freqatt->show();
|
||||
}
|
||||
|
||||
function title()
|
||||
{
|
||||
if ($this->page == 1) {
|
||||
@ -68,6 +78,17 @@ class TagAction extends Action
|
||||
sprintf(_('Feed for tag %s'), $this->tag)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output document relationship links
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showRelationshipLinks()
|
||||
{
|
||||
$this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME
|
||||
$this->page, 'tag', array('tag' => $this->tag));
|
||||
}
|
||||
|
||||
function showPageNotice()
|
||||
{
|
||||
return sprintf(_('Messages tagged "%s", most recent first'), $this->tag);
|
||||
@ -84,4 +105,9 @@ class TagAction extends Action
|
||||
$this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE,
|
||||
$this->page, 'tag', array('tag' => $this->tag));
|
||||
}
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -135,7 +135,8 @@ class TagotherAction extends Action
|
||||
'id' => 'form_tag_user',
|
||||
'class' => 'form_settings',
|
||||
'name' => 'tagother',
|
||||
'action' => $this->selfUrl()));
|
||||
'action' => common_local_url('tagother', array('id' => $this->profile->id))));
|
||||
|
||||
$this->elementStart('fieldset');
|
||||
$this->element('legend', null, _('Tag user'));
|
||||
$this->hidden('token', common_session_token());
|
||||
@ -220,7 +221,8 @@ class TagotherAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url($action, array('nickname' =>
|
||||
$user->nickname)));
|
||||
$user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,7 +65,7 @@ class TagrssAction extends Rss10Action
|
||||
return $c;
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -23,20 +23,21 @@ require_once(INSTALLDIR.'/lib/twitterapi.php');
|
||||
|
||||
class TwitapiaccountAction extends TwitterapiAction
|
||||
{
|
||||
|
||||
function verify_credentials($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
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 {
|
||||
common_user_error(_('API method not found!'), $code=404);
|
||||
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)
|
||||
|
@ -38,7 +38,6 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
||||
|
||||
function show_messages($args, $apidata, $type)
|
||||
{
|
||||
|
||||
$user = $apidata['user'];
|
||||
|
||||
$count = $this->arg('count');
|
||||
@ -102,7 +101,17 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
||||
$this->show_rss_dmsgs($message, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->show_atom_dmsgs($message, $title, $link, $subtitle);
|
||||
$selfuri = common_root_url() . 'api/direct_messages';
|
||||
$selfuri .= ($type == 'received') ? '.atom' : '/sent.atom';
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
|
||||
if ($type == 'sent') {
|
||||
$id = "tag:$taguribase:SentDirectMessages:" . $user->id;
|
||||
} else {
|
||||
$id = "tag:$taguribase:DirectMessages:" . $user->id;
|
||||
}
|
||||
|
||||
$this->show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_dmsgs($message);
|
||||
@ -190,7 +199,7 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
||||
$this->init_document('xml');
|
||||
$this->elementStart('direct-messages', array('type' => 'array'));
|
||||
|
||||
if (is_array($messages)) {
|
||||
if (is_array($message)) {
|
||||
foreach ($message as $m) {
|
||||
$twitter_dm = $this->twitter_dmsg_array($m);
|
||||
$this->show_twitter_xml_dmsg($twitter_dm);
|
||||
@ -261,16 +270,17 @@ class Twitapidirect_messagesAction extends TwitterapiAction
|
||||
|
||||
}
|
||||
|
||||
function show_atom_dmsgs($message, $title, $link, $subtitle)
|
||||
function show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id)
|
||||
{
|
||||
|
||||
$this->init_document('atom');
|
||||
|
||||
$this->element('title', null, $title);
|
||||
$siteserver = common_config('site', 'server');
|
||||
$this->element('id', null, "tag:$siteserver,2008:DirectMessage");
|
||||
$this->element('id', null, $id);
|
||||
$this->element('link', array('href' => $link, 'rel' => 'alternate', 'type' => 'text/html'), null);
|
||||
$this->element('updated', null, common_date_iso8601(strftime('%c')));
|
||||
$this->element('link', array('href' => $selfuri, 'rel' => 'self',
|
||||
'type' => 'application/atom+xml'), null);
|
||||
$this->element('updated', null, common_date_iso8601('now'));
|
||||
$this->element('subtitle', null, $subtitle);
|
||||
|
||||
if (is_array($message)) {
|
||||
|
@ -61,10 +61,9 @@ class TwitapifavoritesAction extends TwitterapiAction
|
||||
}
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$siteserver = common_config('site', 'server');
|
||||
|
||||
$title = sprintf(_('%s / Favorites from %s'), $sitename, $user->nickname);
|
||||
$id = "tag:$siteserver:favorites:".$user->id;
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:Favorites:".$user->id;
|
||||
$link = common_local_url('favorites', array('nickname' => $user->nickname));
|
||||
$subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename, $profile->getBestName(), $user->nickname);
|
||||
|
||||
@ -76,7 +75,14 @@ class TwitapifavoritesAction extends TwitterapiAction
|
||||
$this->show_rss_timeline($notice, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle);
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
'api/favorites/' . $apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = $selfuri = common_root_url() .
|
||||
'api/favorites.atom';
|
||||
}
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_timeline($notice);
|
||||
|
@ -133,11 +133,7 @@ class TwitapifriendshipsAction extends TwitterapiAction
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user_a->isSubscribed($user_b)) {
|
||||
$result = 'true';
|
||||
} else {
|
||||
$result = 'false';
|
||||
}
|
||||
$result = $user_a->isSubscribed($user_b);
|
||||
|
||||
switch ($apidata['content-type']) {
|
||||
case 'xml':
|
||||
|
377
actions/twitapisearchatom.php
Normal file
377
actions/twitapisearchatom.php
Normal file
@ -0,0 +1,377 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for showing Twitter-like Atom search results
|
||||
*
|
||||
* 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 Search
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
|
||||
/**
|
||||
* Action for outputting search results in Twitter compatible Atom
|
||||
* format.
|
||||
*
|
||||
* TODO: abstract Atom stuff into a ruseable base class like
|
||||
* RSS10Action.
|
||||
*
|
||||
* @category Search
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@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/
|
||||
*
|
||||
* @see TwitterapiAction
|
||||
*/
|
||||
|
||||
class TwitapisearchatomAction extends TwitterapiAction
|
||||
{
|
||||
|
||||
var $cnt;
|
||||
var $query;
|
||||
var $lang;
|
||||
var $rpp;
|
||||
var $page;
|
||||
var $since_id;
|
||||
var $geocode;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* Just wraps the Action constructor.
|
||||
*
|
||||
* @param string $output URI to output to, default = stdout
|
||||
* @param boolean $indent Whether to indent output, default true
|
||||
*
|
||||
* @see Action::__construct
|
||||
*/
|
||||
|
||||
function __construct($output='php://output', $indent=true)
|
||||
{
|
||||
parent::__construct($output, $indent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to write to the database?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadonly()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read arguments and initialize members
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return boolean success
|
||||
*
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->query = $this->trimmed('q');
|
||||
$this->lang = $this->trimmed('lang');
|
||||
$this->rpp = $this->trimmed('rpp');
|
||||
|
||||
if (!$this->rpp) {
|
||||
$this->rpp = 15;
|
||||
}
|
||||
|
||||
if ($this->rpp > 100) {
|
||||
$this->rpp = 100;
|
||||
}
|
||||
|
||||
$this->page = $this->trimmed('page');
|
||||
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
// TODO: Suppport since_id -- we need to tweak the backend
|
||||
// Search classes to support it.
|
||||
|
||||
$this->since_id = $this->trimmed('since_id');
|
||||
$this->geocode = $this->trimmed('geocode');
|
||||
|
||||
// TODO: Also, language and geocode
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showAtom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notices to output as results. This also sets some class
|
||||
* attrs so we can use them to calculate pagination, and output
|
||||
* since_id and max_id.
|
||||
*
|
||||
* @return array an array of Notice objects sorted in reverse chron
|
||||
*/
|
||||
|
||||
function getNotices()
|
||||
{
|
||||
// TODO: Support search operators like from: and to:, boolean, etc.
|
||||
|
||||
$notices = array();
|
||||
$notice = new Notice();
|
||||
|
||||
// lcase it for comparison
|
||||
$q = strtolower($this->query);
|
||||
|
||||
$search_engine = $notice->getSearchEngine('identica_notices');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
$search_engine->limit(($this->page - 1) * $this->rpp,
|
||||
$this->rpp + 1, true);
|
||||
$search_engine->query($q);
|
||||
$this->cnt = $notice->find();
|
||||
|
||||
$cnt = 0;
|
||||
|
||||
while ($notice->fetch()) {
|
||||
|
||||
++$cnt;
|
||||
|
||||
if (!$this->max_id) {
|
||||
$this->max_id = $notice->id;
|
||||
}
|
||||
|
||||
if ($cnt > $this->rpp) {
|
||||
break;
|
||||
}
|
||||
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Output search results as an Atom feed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showAtom()
|
||||
{
|
||||
$notices = $this->getNotices();
|
||||
|
||||
$this->initAtom();
|
||||
$this->showFeed();
|
||||
|
||||
foreach ($notices as $n) {
|
||||
$this->showEntry($n);
|
||||
}
|
||||
|
||||
$this->endAtom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show feed specific Atom elements
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showFeed()
|
||||
{
|
||||
// TODO: A9 OpenSearch stuff like search.twitter.com?
|
||||
|
||||
$server = common_config('site', 'server');
|
||||
$sitename = common_config('site', 'name');
|
||||
|
||||
// XXX: Use xmlns:laconica instead?
|
||||
|
||||
$this->elementStart('feed',
|
||||
array('xmlns' => 'http://www.w3.org/2005/Atom',
|
||||
|
||||
// XXX: xmlns:twitter causes Atom validation to fail
|
||||
// It's used for the source attr on notices
|
||||
|
||||
'xmlns:twitter' => 'http://api.twitter.com/',
|
||||
'xml:lang' => 'en-US')); // XXX Other locales ?
|
||||
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$this->element('id', null, "tag:$taguribase:search/$server");
|
||||
|
||||
$site_uri = common_path(false);
|
||||
|
||||
$search_uri = $site_uri . 'api/search.atom?q=' . urlencode($this->query);
|
||||
|
||||
if ($this->rpp != 15) {
|
||||
$search_uri .= '&rpp=' . $this->rpp;
|
||||
}
|
||||
|
||||
// FIXME: this alternate link is not quite right because our
|
||||
// web-based notice search doesn't support a rpp (responses per
|
||||
// page) param yet
|
||||
|
||||
$this->element('link', array('type' => 'text/html',
|
||||
'rel' => 'alternate',
|
||||
'href' => $site_uri . 'search/notice?q=' .
|
||||
urlencode($this->query)));
|
||||
|
||||
// self link
|
||||
|
||||
$self_uri = $search_uri;
|
||||
$self_uri .= ($this->page > 1) ? '&page=' . $this->page : '';
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'self',
|
||||
'href' => $self_uri));
|
||||
|
||||
$this->element('title', null, "$this->query - $sitename Search");
|
||||
$this->element('updated', null, common_date_iso8601('now'));
|
||||
|
||||
// XXX: The below "rel" links are not valid Atom, but it's what
|
||||
// Twitter does...
|
||||
|
||||
// refresh link
|
||||
|
||||
$refresh_uri = $search_uri . "&since_id=" . $this->max_id;
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'refresh',
|
||||
'href' => $refresh_uri));
|
||||
|
||||
// pagination links
|
||||
|
||||
if ($this->cnt > $this->rpp) {
|
||||
|
||||
$next_uri = $search_uri . "&max_id=" . $this->max_id .
|
||||
'&page=' . ($this->page + 1);
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'next',
|
||||
'href' => $next_uri));
|
||||
}
|
||||
|
||||
if ($this->page > 1) {
|
||||
|
||||
$previous_uri = $search_uri . "&max_id=" . $this->max_id .
|
||||
'&page=' . ($this->page - 1);
|
||||
|
||||
$this->element('link', array('type' => 'application/atom+xml',
|
||||
'rel' => 'previous',
|
||||
'href' => $previous_uri));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an Atom entry similar to search.twitter.com's based on
|
||||
* a given notice
|
||||
*
|
||||
* @param Notice $notice the notice to use
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showEntry($notice)
|
||||
{
|
||||
$server = common_config('site', 'server');
|
||||
$profile = $notice->getProfile();
|
||||
$nurl = common_local_url('shownotice', array('notice' => $notice->id));
|
||||
|
||||
$this->elementStart('entry');
|
||||
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
|
||||
$this->element('id', null, "tag:$taguribase:$notice->id");
|
||||
$this->element('published', null, common_date_w3dtf($notice->created));
|
||||
$this->element('link', array('type' => 'text/html',
|
||||
'rel' => 'alternate',
|
||||
'href' => $nurl));
|
||||
$this->element('title', null, common_xml_safe_str(trim($notice->content)));
|
||||
$this->element('content', array('type' => 'html'), $notice->rendered);
|
||||
$this->element('updated', null, common_date_w3dtf($notice->created));
|
||||
$this->element('link', array('type' => 'image/png',
|
||||
// XXX: Twitter uses rel="image" (not valid)
|
||||
'rel' => 'related',
|
||||
'href' => $profile->avatarUrl()));
|
||||
|
||||
// TODO: Here is where we'd put in a link to an atom feed for threads
|
||||
|
||||
$this->element("twitter:source", null,
|
||||
htmlentities($this->source_link($notice->source)));
|
||||
|
||||
$this->elementStart('author');
|
||||
|
||||
$name = $profile->nickname;
|
||||
|
||||
if ($profile->fullname) {
|
||||
$name .= ' (' . $profile->fullname . ')';
|
||||
}
|
||||
|
||||
$this->element('name', null, $name);
|
||||
$this->element('uri', null, common_profile_uri($profile));
|
||||
$this->elementEnd('author');
|
||||
|
||||
$this->elementEnd('entry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the Atom output, send headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function initAtom()
|
||||
{
|
||||
header('Content-Type: application/atom+xml; charset=utf-8');
|
||||
$this->startXml();
|
||||
}
|
||||
|
||||
/**
|
||||
* End the Atom feed
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function endAtom()
|
||||
{
|
||||
$this->elementEnd('feed');
|
||||
}
|
||||
|
||||
}
|
149
actions/twitapisearchjson.php
Normal file
149
actions/twitapisearchjson.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* Action for showing Twitter-like JSON search results
|
||||
*
|
||||
* 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 Search
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
require_once INSTALLDIR.'/lib/jsonsearchresultslist.php';
|
||||
|
||||
/**
|
||||
* Action handler for Twitter-compatible API search
|
||||
*
|
||||
* @category Search
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@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/
|
||||
* @see TwitterapiAction
|
||||
*/
|
||||
|
||||
class TwitapisearchjsonAction extends TwitterapiAction
|
||||
{
|
||||
var $query;
|
||||
var $lang;
|
||||
var $rpp;
|
||||
var $page;
|
||||
var $since_id;
|
||||
var $limit;
|
||||
var $geocode;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean true if nothing goes wrong
|
||||
*/
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
|
||||
$this->query = $this->trimmed('q');
|
||||
$this->lang = $this->trimmed('lang');
|
||||
$this->rpp = $this->trimmed('rpp');
|
||||
|
||||
if (!$this->rpp) {
|
||||
$this->rpp = 15;
|
||||
}
|
||||
|
||||
if ($this->rpp > 100) {
|
||||
$this->rpp = 100;
|
||||
}
|
||||
|
||||
$this->page = $this->trimmed('page');
|
||||
|
||||
if (!$this->page) {
|
||||
$this->page = 1;
|
||||
}
|
||||
|
||||
$this->since_id = $this->trimmed('since_id');
|
||||
$this->geocode = $this->trimmed('geocode');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showResults();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show search results
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function showResults()
|
||||
{
|
||||
|
||||
// TODO: Support search operators like from: and to:, boolean, etc.
|
||||
|
||||
$notice = new Notice();
|
||||
|
||||
// lcase it for comparison
|
||||
$q = strtolower($this->query);
|
||||
|
||||
$search_engine = $notice->getSearchEngine('identica_notices');
|
||||
$search_engine->set_sort_mode('chron');
|
||||
$search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true);
|
||||
$search_engine->query($q);
|
||||
$cnt = $notice->find();
|
||||
|
||||
// TODO: since_id, lang, geocode
|
||||
|
||||
$results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page);
|
||||
|
||||
$this->init_document('json');
|
||||
$results->show();
|
||||
$this->end_document('json');
|
||||
}
|
||||
|
||||
/**
|
||||
* Do we need to write to the database?
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@ -29,10 +29,12 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
parent::handle($args);
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$siteserver = common_config('site', 'server');
|
||||
$title = sprintf(_("%s public timeline"), $sitename);
|
||||
$id = "tag:$siteserver:Statuses";
|
||||
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:PublicTimeline";
|
||||
$link = common_root_url();
|
||||
|
||||
$subtitle = sprintf(_("%s updates from everyone!"), $sitename);
|
||||
|
||||
// Number of public statuses to return by default -- Twitter sends 20
|
||||
@ -70,7 +72,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show_rss_timeline($notice, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle);
|
||||
$selfuri = common_root_url() . 'api/statuses/public_timeline.atom';
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_timeline($notice);
|
||||
@ -114,17 +117,19 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
}
|
||||
|
||||
$since = strtotime($this->arg('since'));
|
||||
|
||||
$user = $this->get_user(null, $apidata);
|
||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||
$this->auth_user = $user;
|
||||
|
||||
if (empty($user)) {
|
||||
$this->clientError(_('No such user!'), 404, $apidata['content-type']);
|
||||
return;
|
||||
}
|
||||
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$siteserver = common_config('site', 'server');
|
||||
|
||||
$title = sprintf(_("%s and friends"), $user->nickname);
|
||||
$id = "tag:$siteserver:friends:" . $user->id;
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:FriendsTimeline:" . $user->id;
|
||||
$link = common_local_url('all', array('nickname' => $user->nickname));
|
||||
$subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename);
|
||||
|
||||
@ -138,7 +143,14 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show_rss_timeline($notice, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle);
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/friends_timeline.atom';
|
||||
}
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_timeline($notice);
|
||||
@ -194,17 +206,16 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$since = strtotime($this->arg('since'));
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$siteserver = common_config('site', 'server');
|
||||
|
||||
$title = sprintf(_("%s timeline"), $user->nickname);
|
||||
$id = "tag:$siteserver:user:".$user->id;
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:UserTimeline:".$user->id;
|
||||
$link = common_local_url('showstream', array('nickname' => $user->nickname));
|
||||
$subtitle = sprintf(_('Updates from %1$s on %2$s!'), $user->nickname, $sitename);
|
||||
|
||||
# FriendFeed's SUP protocol
|
||||
# Also added RSS and Atom feeds
|
||||
|
||||
$suplink = common_local_url('sup', null, $user->id);
|
||||
$suplink = common_local_url('sup', null, null, $user->id);
|
||||
header('X-SUP-ID: '.$suplink);
|
||||
|
||||
# XXX: since
|
||||
@ -219,7 +230,14 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show_rss_timeline($notice, $title, $link, $subtitle, $suplink);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink);
|
||||
if (isset($apidata['api_arg'])) {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom';
|
||||
} else {
|
||||
$selfuri = common_root_url() .
|
||||
'api/statuses/user_timeline.atom';
|
||||
}
|
||||
$this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_timeline($notice);
|
||||
@ -326,7 +344,7 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show($args, $apidata);
|
||||
}
|
||||
|
||||
function replies($args, $apidata)
|
||||
function mentions($args, $apidata)
|
||||
{
|
||||
|
||||
parent::handle($args);
|
||||
@ -337,17 +355,18 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$since_id = $this->arg('since_id');
|
||||
$before_id = $this->arg('before_id');
|
||||
|
||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||
$this->auth_user = $apidata['user'];
|
||||
$user = $this->auth_user;
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$sitename = common_config('site', 'name');
|
||||
$siteserver = common_config('site', 'server');
|
||||
|
||||
$title = sprintf(_('%1$s / Updates replying to %2$s'), $sitename, $user->nickname);
|
||||
$id = "tag:$siteserver:replies:".$user->id;
|
||||
$title = sprintf(_('%1$s / Updates mentioning %2$s'),
|
||||
$sitename, $user->nickname);
|
||||
$taguribase = common_config('integration', 'taguri');
|
||||
$id = "tag:$taguribase:Mentions:".$user->id;
|
||||
$link = common_local_url('replies', array('nickname' => $user->nickname));
|
||||
$subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), $sitename, $user->nickname, $profile->getBestName());
|
||||
$subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'),
|
||||
$sitename, $user->nickname, $profile->getBestName());
|
||||
|
||||
if (!$page) {
|
||||
$page = 1;
|
||||
@ -368,7 +387,8 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
|
||||
$since = strtotime($this->arg('since'));
|
||||
|
||||
$notice = $user->getReplies((($page-1)*20), $count, $since_id, $before_id, $since);
|
||||
$notice = $user->getReplies((($page-1)*20),
|
||||
$count, $since_id, $before_id, $since);
|
||||
$notices = array();
|
||||
|
||||
while ($notice->fetch()) {
|
||||
@ -383,7 +403,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$this->show_rss_timeline($notices, $title, $link, $subtitle);
|
||||
break;
|
||||
case 'atom':
|
||||
$this->show_atom_timeline($notices, $title, $id, $link, $subtitle);
|
||||
$selfuri = common_root_url() .
|
||||
ltrim($_SERVER['QUERY_STRING'], 'p=');
|
||||
$this->show_atom_timeline($notices, $title, $id, $link, $subtitle,
|
||||
null, $selfuri);
|
||||
break;
|
||||
case 'json':
|
||||
$this->show_json_timeline($notices);
|
||||
@ -394,6 +417,11 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
|
||||
}
|
||||
|
||||
function replies($args, $apidata)
|
||||
{
|
||||
call_user_func(array($this, 'mentions'), $args, $apidata);
|
||||
}
|
||||
|
||||
function show($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
@ -470,19 +498,28 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
return $this->subscriptions($apidata, 'subscribed', 'subscriber');
|
||||
}
|
||||
|
||||
function friendsIDs($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
return $this->subscriptions($apidata, 'subscribed', 'subscriber', true);
|
||||
}
|
||||
|
||||
function followers($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
||||
return $this->subscriptions($apidata, 'subscriber', 'subscribed');
|
||||
}
|
||||
|
||||
function subscriptions($apidata, $other_attr, $user_attr)
|
||||
function followersIDs($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
return $this->subscriptions($apidata, 'subscriber', 'subscribed', true);
|
||||
}
|
||||
|
||||
function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false)
|
||||
{
|
||||
|
||||
# XXX: lite
|
||||
|
||||
$this->auth_user = $apidate['user'];
|
||||
$this->auth_user = $apidata['user'];
|
||||
$user = $this->get_user($apidata['api_arg'], $apidata);
|
||||
|
||||
if (!$user) {
|
||||
@ -514,7 +551,10 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
}
|
||||
|
||||
$sub->orderBy('created DESC');
|
||||
|
||||
if (!$onlyIDs) {
|
||||
$sub->limit(($page-1)*100, 100);
|
||||
}
|
||||
|
||||
$others = array();
|
||||
|
||||
@ -529,7 +569,13 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
$type = $apidata['content-type'];
|
||||
|
||||
$this->init_document($type);
|
||||
|
||||
if ($onlyIDs) {
|
||||
$this->showIDs($others, $type);
|
||||
} else {
|
||||
$this->show_profiles($others, $type);
|
||||
}
|
||||
|
||||
$this->end_document($type);
|
||||
}
|
||||
|
||||
@ -555,6 +601,28 @@ class TwitapistatusesAction extends TwitterapiAction
|
||||
}
|
||||
}
|
||||
|
||||
function showIDs($profiles, $type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'xml':
|
||||
$this->elementStart('ids');
|
||||
foreach ($profiles as $profile) {
|
||||
$this->element('id', null, $profile->id);
|
||||
}
|
||||
$this->elementEnd('ids');
|
||||
break;
|
||||
case 'json':
|
||||
$ids = array();
|
||||
foreach ($profiles as $profile) {
|
||||
$ids[] = (int)$profile->id;
|
||||
}
|
||||
print json_encode($ids);
|
||||
break;
|
||||
default:
|
||||
$this->clientError(_('unsupported file type'));
|
||||
}
|
||||
}
|
||||
|
||||
function featured($args, $apidata)
|
||||
{
|
||||
parent::handle($args);
|
||||
|
90
actions/twitapitrends.php
Normal file
90
actions/twitapitrends.php
Normal file
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* Laconica, the distributed open-source microblogging tool
|
||||
*
|
||||
* List of replies
|
||||
*
|
||||
* 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 Search
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@controlyourself.ca>
|
||||
* @copyright 2008-2009 Control Yourself, Inc.
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://laconi.ca/
|
||||
*/
|
||||
|
||||
if (!defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/twitterapi.php';
|
||||
|
||||
/**
|
||||
* Returns the top ten queries that are currently trending
|
||||
*
|
||||
* @category Search
|
||||
* @package Laconica
|
||||
* @author Zach Copley <zach@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/
|
||||
*
|
||||
* @see TwitterapiAction
|
||||
*/
|
||||
|
||||
class TwitapitrendsAction extends TwitterapiAction
|
||||
{
|
||||
|
||||
var $callback;
|
||||
|
||||
/**
|
||||
* Initialization.
|
||||
*
|
||||
* @param array $args Web and URL arguments
|
||||
*
|
||||
* @return boolean false if user doesn't exist
|
||||
*/
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a request
|
||||
*
|
||||
* @param array $args Arguments from $_REQUEST
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
parent::handle($args);
|
||||
$this->showTrends();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the trends
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function showTrends()
|
||||
{
|
||||
$this->serverError(_('API method under construction.'), $code = 501);
|
||||
}
|
||||
|
||||
}
|
@ -33,14 +33,18 @@ class TwitapiusersAction extends TwitterapiAction
|
||||
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']);
|
||||
} elseif (isset($apidata['user'])) {
|
||||
$user = $apidata['user'];
|
||||
}
|
||||
|
||||
if (!$user) {
|
||||
@ -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,16 +101,17 @@ 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)) {
|
||||
$twitter_user['following'] = 'true';
|
||||
} else {
|
||||
$twitter_user['following'] = 'false';
|
||||
$twitter_user['following'] = $apidata['user']->isSubscribed($profile);
|
||||
|
||||
// Notifications on?
|
||||
$sub = Subscription::pkeyGet(array('subscriber' =>
|
||||
$apidata['user']->id, 'subscribed' => $profile->id));
|
||||
|
||||
if ($sub) {
|
||||
$twitter_user['notifications'] = ($sub->jabber || $sub->sms);
|
||||
}
|
||||
|
||||
// Not implemented yet
|
||||
$twitter_user['notifications'] = 'false';
|
||||
}
|
||||
|
||||
if ($apidata['content-type'] == 'xml') {
|
||||
@ -114,6 +122,12 @@ 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';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$this->elementStart('ul', 'form_data');
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticesync',
|
||||
$this->checkbox('noticesend',
|
||||
_('Automatically send my notices to Twitter.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_SEND) :
|
||||
@ -158,6 +158,22 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
($flink->friendsync & FOREIGN_FRIEND_RECV) :
|
||||
false);
|
||||
$this->elementEnd('li');
|
||||
|
||||
if (common_config('twitterbridge','enabled')) {
|
||||
$this->elementStart('li');
|
||||
$this->checkbox('noticerecv',
|
||||
_('Import my Friends Timeline.'),
|
||||
($flink) ?
|
||||
($flink->noticesync & FOREIGN_NOTICE_RECV) :
|
||||
false);
|
||||
$this->elementEnd('li');
|
||||
} else {
|
||||
// preserve setting even if bidrection bridge toggled off
|
||||
if ($flink && ($flink->noticesync & FOREIGN_NOTICE_RECV)) {
|
||||
$this->hidden('noticerecv', true, 'noticerecv');
|
||||
}
|
||||
}
|
||||
|
||||
$this->elementEnd('ul');
|
||||
|
||||
if ($flink) {
|
||||
@ -186,12 +202,12 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$current_user = common_current_user();
|
||||
|
||||
$qry = 'SELECT user.* ' .
|
||||
$qry = 'SELECT "user".* ' .
|
||||
'FROM subscription ' .
|
||||
'JOIN user ON subscription.subscribed = user.id ' .
|
||||
'JOIN foreign_link ON foreign_link.user_id = user.id ' .
|
||||
'JOIN "user" ON subscription.subscribed = "user".id ' .
|
||||
'JOIN foreign_link ON foreign_link.user_id = "user".id ' .
|
||||
'WHERE subscriber = %d ' .
|
||||
'ORDER BY user.nickname';
|
||||
'ORDER BY "user".nickname';
|
||||
|
||||
$user = new User();
|
||||
|
||||
@ -320,7 +336,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
{
|
||||
$screen_name = $this->trimmed('twitter_username');
|
||||
$password = $this->trimmed('twitter_password');
|
||||
$noticesync = $this->boolean('noticesync');
|
||||
$noticesend = $this->boolean('noticesend');
|
||||
$noticerecv = $this->boolean('noticerecv');
|
||||
$replysync = $this->boolean('replysync');
|
||||
$friendsync = $this->boolean('friendsync');
|
||||
|
||||
@ -363,7 +380,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
$flink->credentials = $password;
|
||||
$flink->created = common_sql_now();
|
||||
|
||||
$flink->set_flags($noticesync, $replysync, $friendsync);
|
||||
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||
|
||||
$flink_id = $flink->insert();
|
||||
|
||||
@ -375,6 +392,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
if ($friendsync) {
|
||||
save_twitter_friends($user, $twit_user->id, $screen_name, $password);
|
||||
$flink->last_friendsync = common_sql_now();
|
||||
$flink->update();
|
||||
}
|
||||
|
||||
$this->showForm(_('Twitter settings saved.'), true);
|
||||
@ -419,7 +438,8 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
function savePreferences()
|
||||
{
|
||||
$noticesync = $this->boolean('noticesync');
|
||||
$noticesend = $this->boolean('noticesend');
|
||||
$noticerecv = $this->boolean('noticerecv');
|
||||
$friendsync = $this->boolean('friendsync');
|
||||
$replysync = $this->boolean('replysync');
|
||||
|
||||
@ -448,7 +468,7 @@ class TwittersettingsAction extends ConnectSettingsAction
|
||||
|
||||
$original = clone($flink);
|
||||
|
||||
$flink->set_flags($noticesync, $replysync, $friendsync);
|
||||
$flink->set_flags($noticesend, $noticerecv, $replysync, $friendsync);
|
||||
|
||||
$result = $flink->update($original);
|
||||
|
||||
|
@ -116,10 +116,11 @@ class UnblockAction extends Action
|
||||
}
|
||||
}
|
||||
if ($action) {
|
||||
common_redirect(common_local_url($action, $args));
|
||||
common_redirect(common_local_url($action, $args), 303);
|
||||
} else {
|
||||
common_redirect(common_local_url('subscriptions',
|
||||
array('nickname' => $cur->nickname)));
|
||||
array('nickname' => $cur->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,8 @@ class UnsubscribeAction extends Action
|
||||
$this->elementEnd('html');
|
||||
} else {
|
||||
common_redirect(common_local_url('subscriptions', array('nickname' =>
|
||||
$user->nickname)));
|
||||
$user->nickname)),
|
||||
303);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,11 +29,13 @@ class UpdateprofileAction extends Action
|
||||
parent::handle($args);
|
||||
try {
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request();
|
||||
$req = OAuthRequest::from_request('POST', common_local_url('updateprofile'));
|
||||
# Note: server-to-server function!
|
||||
$server = omb_oauth_server();
|
||||
list($consumer, $token) = $server->verify_request($req);
|
||||
if ($this->update_profile($req, $consumer, $token)) {
|
||||
header('HTTP/1.1 200 OK');
|
||||
header('Content-type: text/plain');
|
||||
print "omb_version=".OMB_VERSION_01;
|
||||
}
|
||||
} catch (OAuthException $e) {
|
||||
@ -136,22 +138,24 @@ class UpdateprofileAction extends Action
|
||||
|
||||
$orig_profile = clone($profile);
|
||||
|
||||
if ($nickname) {
|
||||
/* Use values even if they are an empty string. Parsing an empty string in
|
||||
updateProfile is the specified way of clearing a parameter in OMB. */
|
||||
if (!is_null($nickname)) {
|
||||
$profile->nickname = $nickname;
|
||||
}
|
||||
if ($profile_url) {
|
||||
if (!is_null($profile_url)) {
|
||||
$profile->profileurl = $profile_url;
|
||||
}
|
||||
if ($fullname) {
|
||||
if (!is_null($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if ($homepage) {
|
||||
if (!is_null($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if ($bio) {
|
||||
if (!is_null($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if ($location) {
|
||||
if (!is_null($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
@ -162,15 +166,17 @@ class UpdateprofileAction extends Action
|
||||
if ($avatar) {
|
||||
$temp_filename = tempnam(sys_get_temp_dir(), 'listenee_avatar');
|
||||
copy($avatar, $temp_filename);
|
||||
if (!$profile->setOriginal($temp_filename)) {
|
||||
$imagefile = new ImageFile($profile->id, $temp_filename);
|
||||
$filename = Avatar::filename($profile->id,
|
||||
image_type_to_extension($imagefile->type),
|
||||
null,
|
||||
common_timestamp());
|
||||
rename($temp_filename, Avatar::path($filename));
|
||||
if (!$profile->setOriginal($filename)) {
|
||||
$this->serverError(_('Could not save avatar info'), 500);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
header('HTTP/1.1 200 OK');
|
||||
header('Content-type: text/plain');
|
||||
print 'Updated profile';
|
||||
print "\n";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ define('TIMESTAMP_THRESHOLD', 300);
|
||||
class UserauthorizationAction extends Action
|
||||
{
|
||||
var $error;
|
||||
var $req;
|
||||
var $params;
|
||||
|
||||
function handle($args)
|
||||
{
|
||||
@ -35,8 +35,8 @@ class UserauthorizationAction extends Action
|
||||
# CSRF protection
|
||||
$token = $this->trimmed('token');
|
||||
if (!$token || $token != common_session_token()) {
|
||||
$req = $this->getStoredRequest();
|
||||
$this->showForm($req, _('There was a problem with your session token. '.
|
||||
$params = $this->getStoredParams();
|
||||
$this->showForm($params, _('There was a problem with your session token. '.
|
||||
'Try again, please.'));
|
||||
return;
|
||||
}
|
||||
@ -50,18 +50,13 @@ class UserauthorizationAction extends Action
|
||||
common_redirect(common_local_url('login'));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
# this must be a new request
|
||||
$req = $this->getNewRequest();
|
||||
if (!$req) {
|
||||
$this->clientError(_('No request found!'));
|
||||
}
|
||||
# XXX: only validate new requests, since nonce is one-time use
|
||||
$this->validateRequest($req);
|
||||
$this->storeRequest($req);
|
||||
$this->showForm($req);
|
||||
$this->validateRequest();
|
||||
$this->storeParams($_GET);
|
||||
$this->showForm($_GET);
|
||||
} catch (OAuthException $e) {
|
||||
$this->clearRequest();
|
||||
$this->clearParams();
|
||||
$this->clientError($e->getMessage());
|
||||
return;
|
||||
}
|
||||
@ -69,9 +64,9 @@ class UserauthorizationAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function showForm($req, $error=null)
|
||||
function showForm($params, $error=null)
|
||||
{
|
||||
$this->req = $req;
|
||||
$this->params = $params;
|
||||
$this->error = $error;
|
||||
$this->showPage();
|
||||
}
|
||||
@ -91,113 +86,157 @@ class UserauthorizationAction extends Action
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$req = $this->req;
|
||||
$params = $this->params;
|
||||
|
||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
||||
$profile = $req->get_parameter('omb_listenee_profile');
|
||||
$license = $req->get_parameter('omb_listenee_license');
|
||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
||||
$bio = $req->get_parameter('omb_listenee_bio');
|
||||
$location = $req->get_parameter('omb_listenee_location');
|
||||
$avatar = $req->get_parameter('omb_listenee_avatar');
|
||||
$nickname = $params['omb_listenee_nickname'];
|
||||
$profile = $params['omb_listenee_profile'];
|
||||
$license = $params['omb_listenee_license'];
|
||||
$fullname = $params['omb_listenee_fullname'];
|
||||
$homepage = $params['omb_listenee_homepage'];
|
||||
$bio = $params['omb_listenee_bio'];
|
||||
$location = $params['omb_listenee_location'];
|
||||
$avatar = $params['omb_listenee_avatar'];
|
||||
|
||||
$this->elementStart('div', 'profile');
|
||||
$this->elementStart('div', array('class' => 'profile'));
|
||||
$this->elementStart('div', 'entity_profile vcard');
|
||||
$this->elementStart('a', array('href' => $profile,
|
||||
'class' => 'url'));
|
||||
if ($avatar) {
|
||||
$this->element('img', array('src' => $avatar,
|
||||
'class' => 'avatar profile',
|
||||
'class' => 'photo avatar',
|
||||
'width' => AVATAR_PROFILE_SIZE,
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $nickname));
|
||||
}
|
||||
$this->element('a', array('href' => $profile,
|
||||
'class' => 'external profile nickname'),
|
||||
$nickname);
|
||||
if ($fullname) {
|
||||
$this->elementStart('div', 'fullname');
|
||||
if ($homepage) {
|
||||
$this->element('a', array('href' => $homepage),
|
||||
$fullname);
|
||||
} else {
|
||||
$this->text($fullname);
|
||||
$hasFN = ($fullname !== '') ? 'nickname' : 'fn nickname';
|
||||
$this->elementStart('span', $hasFN);
|
||||
$this->raw($nickname);
|
||||
$this->elementEnd('span');
|
||||
$this->elementEnd('a');
|
||||
|
||||
if (!is_null($fullname)) {
|
||||
$this->elementStart('dl', 'entity_fn');
|
||||
$this->elementStart('dd');
|
||||
$this->elementStart('span', 'fn');
|
||||
$this->raw($fullname);
|
||||
$this->elementEnd('span');
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
if (!is_null($location)) {
|
||||
$this->elementStart('dl', 'entity_location');
|
||||
$this->element('dt', null, _('Location'));
|
||||
$this->elementStart('dd', 'label');
|
||||
$this->raw($location);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
if ($location) {
|
||||
$this->element('div', 'location', $location);
|
||||
|
||||
if (!is_null($homepage)) {
|
||||
$this->elementStart('dl', 'entity_url');
|
||||
$this->element('dt', null, _('URL'));
|
||||
$this->elementStart('dd');
|
||||
$this->elementStart('a', array('href' => $homepage,
|
||||
'class' => 'url'));
|
||||
$this->raw($homepage);
|
||||
$this->elementEnd('a');
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
if ($bio) {
|
||||
$this->element('div', 'bio', $bio);
|
||||
|
||||
if (!is_null($bio)) {
|
||||
$this->elementStart('dl', 'entity_note');
|
||||
$this->element('dt', null, _('Note'));
|
||||
$this->elementStart('dd', 'note');
|
||||
$this->raw($bio);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
$this->elementStart('div', 'license');
|
||||
|
||||
if (!is_null($license)) {
|
||||
$this->elementStart('dl', 'entity_license');
|
||||
$this->element('dt', null, _('License'));
|
||||
$this->elementStart('dd', 'license');
|
||||
$this->element('a', array('href' => $license,
|
||||
'class' => 'license'),
|
||||
$license);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
|
||||
$this->elementStart('div', 'entity_actions');
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', 'entity_subscribe');
|
||||
$this->elementStart('form', array('method' => 'post',
|
||||
'id' => 'userauthorization',
|
||||
'class' => 'form_user_authorization',
|
||||
'name' => 'userauthorization',
|
||||
'action' => common_local_url('userauthorization')));
|
||||
$this->hidden('token', common_session_token());
|
||||
$this->submit('accept', _('Accept'));
|
||||
$this->submit('reject', _('Reject'));
|
||||
|
||||
$this->submit('accept', _('Accept'), 'submit accept', null, _('Subscribe to this user'));
|
||||
$this->submit('reject', _('Reject'), 'submit reject', null, _('Reject this subscription'));
|
||||
$this->elementEnd('form');
|
||||
$this->elementEnd('li');
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('div');
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function sendAuthorization()
|
||||
{
|
||||
$req = $this->getStoredRequest();
|
||||
$params = $this->getStoredParams();
|
||||
|
||||
if (!$req) {
|
||||
if (!$params) {
|
||||
$this->clientError(_('No authorization request!'));
|
||||
return;
|
||||
}
|
||||
|
||||
$callback = $req->get_parameter('oauth_callback');
|
||||
$callback = $params['oauth_callback'];
|
||||
|
||||
if ($this->arg('accept')) {
|
||||
if (!$this->authorizeToken($req)) {
|
||||
if (!$this->authorizeToken($params)) {
|
||||
$this->clientError(_('Error authorizing token'));
|
||||
}
|
||||
if (!$this->saveRemoteProfile($req)) {
|
||||
if (!$this->saveRemoteProfile($params)) {
|
||||
$this->clientError(_('Error saving remote profile'));
|
||||
}
|
||||
if (!$callback) {
|
||||
$this->showAcceptMessage($req->get_parameter('oauth_token'));
|
||||
$this->showAcceptMessage($params['oauth_token']);
|
||||
} else {
|
||||
$params = array();
|
||||
$params['oauth_token'] = $req->get_parameter('oauth_token');
|
||||
$params['omb_version'] = OMB_VERSION_01;
|
||||
$user = User::staticGet('uri', $req->get_parameter('omb_listener'));
|
||||
$newparams = array();
|
||||
$newparams['oauth_token'] = $params['oauth_token'];
|
||||
$newparams['omb_version'] = OMB_VERSION_01;
|
||||
$user = User::staticGet('uri', $params['omb_listener']);
|
||||
$profile = $user->getProfile();
|
||||
if (!$profile) {
|
||||
common_log_db_error($user, 'SELECT', __FILE__);
|
||||
$this->serverError(_('User without matching profile'));
|
||||
return;
|
||||
}
|
||||
$params['omb_listener_nickname'] = $user->nickname;
|
||||
$params['omb_listener_profile'] = common_local_url('showstream',
|
||||
$newparams['omb_listener_nickname'] = $user->nickname;
|
||||
$newparams['omb_listener_profile'] = common_local_url('showstream',
|
||||
array('nickname' => $user->nickname));
|
||||
if ($profile->fullname) {
|
||||
$params['omb_listener_fullname'] = $profile->fullname;
|
||||
if (!is_null($profile->fullname)) {
|
||||
$newparams['omb_listener_fullname'] = $profile->fullname;
|
||||
}
|
||||
if ($profile->homepage) {
|
||||
$params['omb_listener_homepage'] = $profile->homepage;
|
||||
if (!is_null($profile->homepage)) {
|
||||
$newparams['omb_listener_homepage'] = $profile->homepage;
|
||||
}
|
||||
if ($profile->bio) {
|
||||
$params['omb_listener_bio'] = $profile->bio;
|
||||
if (!is_null($profile->bio)) {
|
||||
$newparams['omb_listener_bio'] = $profile->bio;
|
||||
}
|
||||
if ($profile->location) {
|
||||
$params['omb_listener_location'] = $profile->location;
|
||||
if (!is_null($profile->location)) {
|
||||
$newparams['omb_listener_location'] = $profile->location;
|
||||
}
|
||||
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
|
||||
if ($avatar) {
|
||||
$params['omb_listener_avatar'] = $avatar->url;
|
||||
$newparams['omb_listener_avatar'] = $avatar->url;
|
||||
}
|
||||
$parts = array();
|
||||
foreach ($params as $k => $v) {
|
||||
$parts[] = $k . '=' . OAuthUtil::urlencodeRFC3986($v);
|
||||
foreach ($newparams as $k => $v) {
|
||||
$parts[] = $k . '=' . OAuthUtil::urlencode_rfc3986($v);
|
||||
}
|
||||
$query_string = implode('&', $parts);
|
||||
$parsed = parse_url($callback);
|
||||
@ -214,12 +253,10 @@ class UserauthorizationAction extends Action
|
||||
}
|
||||
}
|
||||
|
||||
function authorizeToken(&$req)
|
||||
function authorizeToken(&$params)
|
||||
{
|
||||
$consumer_key = $req->get_parameter('oauth_consumer_key');
|
||||
$token_field = $req->get_parameter('oauth_token');
|
||||
$token_field = $params['oauth_token'];
|
||||
$rt = new Token();
|
||||
$rt->consumer_key = $consumer_key;
|
||||
$rt->tok = $token_field;
|
||||
$rt->type = 0;
|
||||
$rt->state = 0;
|
||||
@ -235,21 +272,21 @@ class UserauthorizationAction extends Action
|
||||
|
||||
# XXX: refactor with similar code in finishremotesubscribe.php
|
||||
|
||||
function saveRemoteProfile(&$req)
|
||||
function saveRemoteProfile(&$params)
|
||||
{
|
||||
# FIXME: we should really do this when the consumer comes
|
||||
# back for an access token. If they never do, we've got stuff in a
|
||||
# weird state.
|
||||
|
||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
||||
$profile_url = $req->get_parameter('omb_listenee_profile');
|
||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
||||
$bio = $req->get_parameter('omb_listenee_bio');
|
||||
$location = $req->get_parameter('omb_listenee_location');
|
||||
$avatar_url = $req->get_parameter('omb_listenee_avatar');
|
||||
$nickname = $params['omb_listenee_nickname'];
|
||||
$fullname = $params['omb_listenee_fullname'];
|
||||
$profile_url = $params['omb_listenee_profile'];
|
||||
$homepage = $params['omb_listenee_homepage'];
|
||||
$bio = $params['omb_listenee_bio'];
|
||||
$location = $params['omb_listenee_location'];
|
||||
$avatar_url = $params['omb_listenee_avatar'];
|
||||
|
||||
$listenee = $req->get_parameter('omb_listenee');
|
||||
$listenee = $params['omb_listenee'];
|
||||
$remote = Remote_profile::staticGet('uri', $listenee);
|
||||
|
||||
if ($remote) {
|
||||
@ -267,16 +304,16 @@ class UserauthorizationAction extends Action
|
||||
$profile->nickname = $nickname;
|
||||
$profile->profileurl = $profile_url;
|
||||
|
||||
if ($fullname) {
|
||||
if (!is_null($fullname)) {
|
||||
$profile->fullname = $fullname;
|
||||
}
|
||||
if ($homepage) {
|
||||
if (!is_null($homepage)) {
|
||||
$profile->homepage = $homepage;
|
||||
}
|
||||
if ($bio) {
|
||||
if (!is_null($bio)) {
|
||||
$profile->bio = $bio;
|
||||
}
|
||||
if ($location) {
|
||||
if (!is_null($location)) {
|
||||
$profile->location = $location;
|
||||
}
|
||||
|
||||
@ -309,14 +346,11 @@ class UserauthorizationAction extends Action
|
||||
}
|
||||
|
||||
$user = common_current_user();
|
||||
$datastore = omb_oauth_datastore();
|
||||
$consumer = $this->getConsumer($datastore, $req);
|
||||
$token = $this->getToken($datastore, $req, $consumer);
|
||||
|
||||
$sub = new Subscription();
|
||||
$sub->subscriber = $user->id;
|
||||
$sub->subscribed = $remote->id;
|
||||
$sub->token = $token->key; # NOTE: request token, not valid for use!
|
||||
$sub->token = $params['oauth_token']; # NOTE: request token, not valid for use!
|
||||
$sub->created = DB_DataObject_Cast::dateTime(); # current time
|
||||
|
||||
if (!$sub->insert()) {
|
||||
@ -360,65 +394,59 @@ class UserauthorizationAction extends Action
|
||||
common_show_footer();
|
||||
}
|
||||
|
||||
function storeRequest($req)
|
||||
function storeParams($params)
|
||||
{
|
||||
common_ensure_session();
|
||||
$_SESSION['userauthorizationrequest'] = $req;
|
||||
$_SESSION['userauthorizationparams'] = $params;
|
||||
}
|
||||
|
||||
function clearRequest()
|
||||
function clearParams()
|
||||
{
|
||||
common_ensure_session();
|
||||
unset($_SESSION['userauthorizationrequest']);
|
||||
unset($_SESSION['userauthorizationparams']);
|
||||
}
|
||||
|
||||
function getStoredRequest()
|
||||
function getStoredParams()
|
||||
{
|
||||
common_ensure_session();
|
||||
$req = $_SESSION['userauthorizationrequest'];
|
||||
return $req;
|
||||
}
|
||||
|
||||
function getNewRequest()
|
||||
{
|
||||
common_remove_magic_from_request();
|
||||
$req = OAuthRequest::from_request();
|
||||
return $req;
|
||||
$params = $_SESSION['userauthorizationparams'];
|
||||
return $params;
|
||||
}
|
||||
|
||||
# Throws an OAuthException if anything goes wrong
|
||||
|
||||
function validateRequest(&$req)
|
||||
function validateRequest()
|
||||
{
|
||||
# OAuth stuff -- have to copy from OAuth.php since they're
|
||||
# all private methods, and there's no user-authentication method
|
||||
$this->checkVersion($req);
|
||||
$datastore = omb_oauth_datastore();
|
||||
$consumer = $this->getConsumer($datastore, $req);
|
||||
$token = $this->getToken($datastore, $req, $consumer);
|
||||
$this->checkTimestamp($req);
|
||||
$this->checkNonce($datastore, $req, $consumer, $token);
|
||||
$this->checkSignature($req, $consumer, $token);
|
||||
$this->validateOmb($req);
|
||||
/* Find token.
|
||||
TODO: If no token is passed the user should get a prompt to enter it
|
||||
according to OAuth Core 1.0 */
|
||||
$t = new Token();
|
||||
$t->tok = $_GET['oauth_token'];
|
||||
$t->type = 0;
|
||||
if (!$t->find(true)) {
|
||||
throw new OAuthException("Invalid request token: " . $_GET['oauth_token']);
|
||||
}
|
||||
|
||||
$this->validateOmb();
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateOmb(&$req)
|
||||
function validateOmb()
|
||||
{
|
||||
foreach (array('omb_version', 'omb_listener', 'omb_listenee',
|
||||
'omb_listenee_profile', 'omb_listenee_nickname',
|
||||
'omb_listenee_license') as $param)
|
||||
{
|
||||
if (!$req->get_parameter($param)) {
|
||||
if (!isset($_GET[$param]) || is_null($_GET[$param])) {
|
||||
throw new OAuthException("Required parameter '$param' not found");
|
||||
}
|
||||
}
|
||||
# Now, OMB stuff
|
||||
$version = $req->get_parameter('omb_version');
|
||||
$version = $_GET['omb_version'];
|
||||
if ($version != OMB_VERSION_01) {
|
||||
throw new OAuthException("OpenMicroBlogging version '$version' not supported");
|
||||
}
|
||||
$listener = $req->get_parameter('omb_listener');
|
||||
$listener = $_GET['omb_listener'];
|
||||
$user = User::staticGet('uri', $listener);
|
||||
if (!$user) {
|
||||
throw new OAuthException("Listener URI '$listener' not found here");
|
||||
@ -427,7 +455,7 @@ class UserauthorizationAction extends Action
|
||||
if ($cur->id != $user->id) {
|
||||
throw new OAuthException("Can't add for another user!");
|
||||
}
|
||||
$listenee = $req->get_parameter('omb_listenee');
|
||||
$listenee = $_GET['omb_listenee'];
|
||||
if (!Validate::uri($listenee) &&
|
||||
!common_valid_tag($listenee)) {
|
||||
throw new OAuthException("Listenee URI '$listenee' not a recognizable URI");
|
||||
@ -450,13 +478,13 @@ class UserauthorizationAction extends Action
|
||||
throw new OAuthException("Already subscribed to user!");
|
||||
}
|
||||
}
|
||||
$nickname = $req->get_parameter('omb_listenee_nickname');
|
||||
$nickname = $_GET['omb_listenee_nickname'];
|
||||
if (!Validate::string($nickname, array('min_length' => 1,
|
||||
'max_length' => 64,
|
||||
'format' => VALIDATE_NUM . VALIDATE_ALPHA_LOWER))) {
|
||||
throw new OAuthException('Nickname must have only letters and numbers and no spaces.');
|
||||
}
|
||||
$profile = $req->get_parameter('omb_listenee_profile');
|
||||
$profile = $_GET['omb_listenee_profile'];
|
||||
if (!common_valid_http_url($profile)) {
|
||||
throw new OAuthException("Invalid profile URL '$profile'.");
|
||||
}
|
||||
@ -465,7 +493,7 @@ class UserauthorizationAction extends Action
|
||||
throw new OAuthException("Profile URL '$profile' is for a local user.");
|
||||
}
|
||||
|
||||
$license = $req->get_parameter('omb_listenee_license');
|
||||
$license = $_GET['omb_listenee_license'];
|
||||
if (!common_valid_http_url($license)) {
|
||||
throw new OAuthException("Invalid license URL '$license'.");
|
||||
}
|
||||
@ -474,23 +502,23 @@ class UserauthorizationAction extends Action
|
||||
throw new OAuthException("Listenee stream license '$license' not compatible with site license '$site_license'.");
|
||||
}
|
||||
# optional stuff
|
||||
$fullname = $req->get_parameter('omb_listenee_fullname');
|
||||
$fullname = $_GET['omb_listenee_fullname'];
|
||||
if ($fullname && mb_strlen($fullname) > 255) {
|
||||
throw new OAuthException("Full name '$fullname' too long.");
|
||||
}
|
||||
$homepage = $req->get_parameter('omb_listenee_homepage');
|
||||
$homepage = $_GET['omb_listenee_homepage'];
|
||||
if ($homepage && (!common_valid_http_url($homepage) || mb_strlen($homepage) > 255)) {
|
||||
throw new OAuthException("Invalid homepage '$homepage'");
|
||||
}
|
||||
$bio = $req->get_parameter('omb_listenee_bio');
|
||||
$bio = $_GET['omb_listenee_bio'];
|
||||
if ($bio && mb_strlen($bio) > 140) {
|
||||
throw new OAuthException("Bio too long '$bio'");
|
||||
}
|
||||
$location = $req->get_parameter('omb_listenee_location');
|
||||
$location = $_GET['omb_listenee_location'];
|
||||
if ($location && mb_strlen($location) > 255) {
|
||||
throw new OAuthException("Location too long '$location'");
|
||||
}
|
||||
$avatar = $req->get_parameter('omb_listenee_avatar');
|
||||
$avatar = $_GET['omb_listenee_avatar'];
|
||||
if ($avatar) {
|
||||
if (!common_valid_http_url($avatar) || strlen($avatar) > 255) {
|
||||
throw new OAuthException("Invalid avatar URL '$avatar'");
|
||||
@ -507,7 +535,7 @@ class UserauthorizationAction extends Action
|
||||
throw new OAuthException("Wrong image type for '$avatar'");
|
||||
}
|
||||
}
|
||||
$callback = $req->get_parameter('oauth_callback');
|
||||
$callback = $_GET['oauth_callback'];
|
||||
if ($callback && !common_valid_http_url($callback)) {
|
||||
throw new OAuthException("Invalid callback URL '$callback'");
|
||||
}
|
||||
@ -515,92 +543,4 @@ class UserauthorizationAction extends Action
|
||||
throw new OAuthException("Callback URL '$callback' is for local site.");
|
||||
}
|
||||
}
|
||||
|
||||
# Snagged from OAuthServer
|
||||
|
||||
function checkVersion(&$req)
|
||||
{
|
||||
$version = $req->get_parameter("oauth_version");
|
||||
if (!$version) {
|
||||
$version = 1.0;
|
||||
}
|
||||
if ($version != 1.0) {
|
||||
throw new OAuthException("OAuth version '$version' not supported");
|
||||
}
|
||||
return $version;
|
||||
}
|
||||
|
||||
# Snagged from OAuthServer
|
||||
|
||||
function getConsumer($datastore, $req)
|
||||
{
|
||||
$consumer_key = @$req->get_parameter("oauth_consumer_key");
|
||||
if (!$consumer_key) {
|
||||
throw new OAuthException("Invalid consumer key");
|
||||
}
|
||||
|
||||
$consumer = $datastore->lookup_consumer($consumer_key);
|
||||
if (!$consumer) {
|
||||
throw new OAuthException("Invalid consumer");
|
||||
}
|
||||
return $consumer;
|
||||
}
|
||||
|
||||
# Mostly cadged from OAuthServer
|
||||
|
||||
function getToken($datastore, &$req, $consumer)
|
||||
{/*{{{*/
|
||||
$token_field = @$req->get_parameter('oauth_token');
|
||||
$token = $datastore->lookup_token($consumer, 'request', $token_field);
|
||||
if (!$token) {
|
||||
throw new OAuthException("Invalid $token_type token: $token_field");
|
||||
}
|
||||
return $token;
|
||||
}
|
||||
|
||||
function checkTimestamp(&$req)
|
||||
{
|
||||
$timestamp = @$req->get_parameter('oauth_timestamp');
|
||||
$now = time();
|
||||
if ($now - $timestamp > TIMESTAMP_THRESHOLD) {
|
||||
throw new OAuthException("Expired timestamp, yours $timestamp, ours $now");
|
||||
}
|
||||
}
|
||||
|
||||
# NOTE: don't call twice on the same request; will fail!
|
||||
function checkNonce(&$datastore, &$req, $consumer, $token)
|
||||
{
|
||||
$timestamp = @$req->get_parameter('oauth_timestamp');
|
||||
$nonce = @$req->get_parameter('oauth_nonce');
|
||||
$found = $datastore->lookup_nonce($consumer, $token, $nonce, $timestamp);
|
||||
if ($found) {
|
||||
throw new OAuthException("Nonce already used");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkSignature(&$req, $consumer, $token)
|
||||
{
|
||||
$signature_method = $this->getSignatureMethod($req);
|
||||
$signature = $req->get_parameter('oauth_signature');
|
||||
$valid_sig = $signature_method->check_signature($req,
|
||||
$consumer,
|
||||
$token,
|
||||
$signature);
|
||||
if (!$valid_sig) {
|
||||
throw new OAuthException("Invalid signature");
|
||||
}
|
||||
}
|
||||
|
||||
function getSignatureMethod(&$req)
|
||||
{
|
||||
$signature_method = @$req->get_parameter("oauth_signature_method");
|
||||
if (!$signature_method) {
|
||||
$signature_method = "PLAINTEXT";
|
||||
}
|
||||
if ($signature_method != 'HMAC-SHA1') {
|
||||
throw new OAuthException("Signature method '$signature_method' not supported.");
|
||||
}
|
||||
return omb_hmac_sha1();
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class UserbyidAction extends Action
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class UsergroupsAction extends Action
|
||||
var $page = null;
|
||||
var $profile = null;
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -139,10 +139,28 @@ class UsergroupsAction extends Action
|
||||
if ($groups) {
|
||||
$gl = new GroupList($groups, $this->user, $this);
|
||||
$cnt = $gl->show();
|
||||
if (0 == $cnt) {
|
||||
$this->showEmptyListMessage();
|
||||
}
|
||||
}
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > GROUPS_PER_PAGE,
|
||||
$this->page, 'usergroups',
|
||||
array('nickname' => $this->user->nickname));
|
||||
}
|
||||
|
||||
function showEmptyListMessage()
|
||||
{
|
||||
$message = sprintf(_('%s is not a member of any group.'), $this->user->nickname) . ' ';
|
||||
|
||||
if (common_logged_in()) {
|
||||
$current_user = common_current_user();
|
||||
if ($this->user->id === $current_user->id) {
|
||||
$message .= _('Try [searching for groups](%%action.groupsearch%%) and joining them.');
|
||||
}
|
||||
}
|
||||
$this->elementStart('div', 'guide');
|
||||
$this->raw(common_markup_to_html($message));
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,15 @@ require_once(INSTALLDIR.'/lib/rssaction.php');
|
||||
|
||||
class UserrssAction extends Rss10Action
|
||||
{
|
||||
|
||||
var $user = null;
|
||||
var $tag = null;
|
||||
|
||||
function prepare($args)
|
||||
{
|
||||
parent::prepare($args);
|
||||
$nickname = $this->trimmed('nickname');
|
||||
$this->user = User::staticGet('nickname', $nickname);
|
||||
$this->tag = $this->trimmed('tag');
|
||||
|
||||
if (!$this->user) {
|
||||
$this->clientError(_('No such user.'));
|
||||
@ -42,6 +43,25 @@ class UserrssAction extends Rss10Action
|
||||
}
|
||||
}
|
||||
|
||||
function getTaggedNotices($tag = null, $limit=0)
|
||||
{
|
||||
$user = $this->user;
|
||||
|
||||
if (is_null($user)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$notice = $user->getTaggedNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit, 0, 0, null, $tag);
|
||||
|
||||
$notices = array();
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
|
||||
return $notices;
|
||||
}
|
||||
|
||||
|
||||
function getNotices($limit=0)
|
||||
{
|
||||
|
||||
@ -53,6 +73,7 @@ class UserrssAction extends Rss10Action
|
||||
|
||||
$notice = $user->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit);
|
||||
|
||||
$notices = array();
|
||||
while ($notice->fetch()) {
|
||||
$notices[] = clone($notice);
|
||||
}
|
||||
@ -90,14 +111,13 @@ class UserrssAction extends Rss10Action
|
||||
|
||||
function initRss($limit=0)
|
||||
{
|
||||
$url = common_local_url('sup', null, $this->user->id);
|
||||
$url = common_local_url('sup', null, null, $this->user->id);
|
||||
header('X-SUP-ID: '.$url);
|
||||
parent::initRss($limit);
|
||||
}
|
||||
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ class XrdsAction extends Action
|
||||
*
|
||||
* @return boolean true
|
||||
*/
|
||||
function isReadOnly()
|
||||
function isReadOnly($args)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
BIN
apple-touch-icon.png
Normal file
BIN
apple-touch-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -36,4 +36,53 @@ class Fave extends Memcached_DataObject
|
||||
{
|
||||
return Memcached_DataObject::pkeyGet('Fave', $kv);
|
||||
}
|
||||
|
||||
function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE)
|
||||
{
|
||||
$ids = Notice::stream(array('Fave', '_streamDirect'),
|
||||
array($user_id),
|
||||
'fave:ids_by_user:'.$user_id,
|
||||
$offset, $limit);
|
||||
return $ids;
|
||||
}
|
||||
|
||||
function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since)
|
||||
{
|
||||
$fav = new Fave();
|
||||
|
||||
$fav->user_id = $user_id;
|
||||
|
||||
$fav->selectAdd();
|
||||
$fav->selectAdd('notice_id');
|
||||
|
||||
if ($since_id != 0) {
|
||||
$fav->whereAdd('notice_id > ' . $since_id);
|
||||
}
|
||||
|
||||
if ($before_id != 0) {
|
||||
$fav->whereAdd('notice_id < ' . $before_id);
|
||||
}
|
||||
|
||||
if (!is_null($since)) {
|
||||
$fav->whereAdd('modified > \'' . date('Y-m-d H:i:s', $since) . '\'');
|
||||
}
|
||||
|
||||
// NOTE: we sort by fave time, not by notice time!
|
||||
|
||||
$fav->orderBy('modified DESC');
|
||||
|
||||
if (!is_null($offset)) {
|
||||
$fav->limit($offset, $limit);
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
|
||||
if ($fav->find()) {
|
||||
while ($fav->fetch()) {
|
||||
$ids[] = $fav->notice_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user