From 0b6994516c91890753a1b18404f77a60de543980 Mon Sep 17 00:00:00 2001
From: Dan Moore
Date: Fri, 5 Jun 2009 01:01:25 -0400
Subject: Cleaning up comments at top of favor.php.
---
actions/favor.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/actions/favor.php b/actions/favor.php
index 3b7d979eb..a7aff87f2 100644
--- a/actions/favor.php
+++ b/actions/favor.php
@@ -12,8 +12,6 @@
* @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.
*
--
cgit v1.2.3-54-g00ecf
From 40e05a3e86559bb9bd7094519003d3c7d90501a5 Mon Sep 17 00:00:00 2001
From: Dan Moore
Date: Fri, 5 Jun 2009 12:53:17 -0400
Subject: Bringing users/show in line with Twitter as far as specifying user.
---
actions/twitapiusers.php | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index b90bbfa98..0461efcb4 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -35,20 +35,13 @@ class TwitapiusersAction extends TwitterapiAction
$user = null;
$email = $this->arg('email');
- $user_id = $this->arg('user_id');
// XXX: email field deprecated in Twitter's API
- // XXX: Also: need to add screen_name param
-
if ($email) {
$user = User::staticGet('email', $email);
- } elseif ($user_id) {
- $user = $this->get_user($user_id);
- } elseif (isset($apidata['api_arg'])) {
+ } else {
$user = $this->get_user($apidata['api_arg']);
- } elseif (isset($apidata['user'])) {
- $user = $apidata['user'];
}
if (!$user) {
--
cgit v1.2.3-54-g00ecf
From 10d4191bd103d177734ce4cf8006cd7af88e139b Mon Sep 17 00:00:00 2001
From: Jeff Mitchell
Date: Thu, 11 Jun 2009 13:07:41 +0000
Subject: Add site-wide option to change the length at which URLs are
auto-shortened
---
README | 3 +++
lib/Shorturl_api.php | 2 +-
lib/common.php | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/README b/README
index 769c416d3..679a096b3 100644
--- a/README
+++ b/README
@@ -901,6 +901,9 @@ sslserver: use an alternate server name for SSL URLs, like
parameters correctly so that both the SSL server and the
"normal" server can access the session cookie and
preferably other cookies as well.
+shorturllength: Length of URL at which URLs in a message exceeding 140
+ characters will be sent to the user's chosen
+ shortening service.
db
--
diff --git a/lib/Shorturl_api.php b/lib/Shorturl_api.php
index fe106cb83..d1fc5eb6d 100644
--- a/lib/Shorturl_api.php
+++ b/lib/Shorturl_api.php
@@ -39,7 +39,7 @@ class ShortUrlApi
}
private function is_long($url) {
- return strlen($url) >= 30;
+ return strlen($url) >= common_config('site', 'shorturllength');
}
protected function http_post($data) {
diff --git a/lib/common.php b/lib/common.php
index 01d2c78ea..151b31d80 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -89,6 +89,7 @@ $config =
'private' => false,
'ssl' => 'never',
'sslserver' => null,
+ 'shorturllength' => 30,
'dupelimit' => 60), # default for same person saying the same thing
'syslog' =>
array('appname' => 'laconica', # for syslog
--
cgit v1.2.3-54-g00ecf
From 89bf13d5d62c80a9b3bb81bb135f177b20933d64 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 20 Jun 2009 21:45:06 -0700
Subject: Add original of Wordpress.com TOS
---
doc-src/tos | 301 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 301 insertions(+)
create mode 100644 doc-src/tos
diff --git a/doc-src/tos b/doc-src/tos
new file mode 100644
index 000000000..10c5e0fd2
--- /dev/null
+++ b/doc-src/tos
@@ -0,0 +1,301 @@
+The gist
+--------
+
+We (the folks at Automattic) run a service called WordPress.com and
+would love for you to use it. Our basic service is free, and we offer
+paid upgrades for advanced features such as domain hosting and extra
+storage. Our service is designed to give you as much control and
+ownership over what goes on your blog as possible and encourage you to
+express yourself freely. However, be responsible in what you blog. In
+particular, make sure that none of the prohibited items listed below
+appear on your blog or get linked to from your blog (things like spam,
+viruses, or hate content).
+
+You can check our page on types of blogs to get a sense of the types
+of sites that are welcome on our service (or not!). If you find a
+WordPress.com blog that you believe violates our terms of service,
+please check our complaints page.
+
+(Note, we’ve decided to make the below Terms of Service available
+under a Creative Commons Sharealike license, which means you’re more
+than welcome to steal it and repurpose it for your own use, just make
+sure to replace references to us with ones to you, and if you want
+we’d appreciate a link to WordPress.com somewhere on your site. We
+spent a lot of money and time on the below, and other people shouldn’t
+need to do the same.)
+Terms of Service:
+
+The following terms and conditions govern all use of the WordPress.com
+website and all content, services and products available at or through
+the website, including, but not limited to, the WordPress.com VIP
+hosting service (“VIP Service”), (taken together, the Website). The
+Website is owned and operated by Automattic, Inc. (“Automattic”). The
+Website is offered subject to your acceptance without modification of
+all of the terms and conditions contained herein and all other
+operating rules, policies (including, without limitation, Automattic’s
+Privacy Policy) and procedures that may be published from time to time
+on this Site by Automattic (collectively, the “Agreement”).
+
+Please read this Agreement carefully before accessing or using the
+Website. By accessing or using any part of the web site, you agree to
+become bound by the terms and conditions of this agreement. If you do
+not agree to all the terms and conditions of this agreement, then you
+may not access the Website or use any services. If these terms and
+conditions are considered an offer by Automattic, acceptance is
+expressly limited to these terms. The Website is available only to
+individuals who are at least 13 years old.
+
+ 1. Your WordPress.com Account and Site. If you create a blog on the
+Website, you are responsible for maintaining the security of your
+account and blog, and you are fully responsible for all activities
+that occur under the account and any other actions taken in connection
+with the blog. You must not describe or assign keywords to your blog
+in a misleading or unlawful manner, including in a manner intended to
+trade on the name or reputation of others, and Automattic may change
+or remove any description or keyword that it considers inappropriate
+or unlawful, or otherwise likely to cause Automattic liability. You
+must immediately notify Automattic of any unauthorized uses of your
+blog, your account or any other breaches of security. Automattic will
+not be liable for any acts or omissions by You, including any damages
+of any kind incurred as a result of such acts or omissions.
+ 2. Responsibility of Contributors. If you operate a blog, comment
+on a blog, post material to the Website, post links on the Website, or
+otherwise make (or allow any third party to make) material available
+by means of the Website (any such material, “Content”), You are
+entirely responsible for the content of, and any harm resulting from,
+that Content. That is the case regardless of whether the Content in
+question constitutes text, graphics, an audio file, or computer
+software. By making Content available, you represent and warrant that:
+ * the downloading, copying and use of the Content will not
+infringe the proprietary rights, including but not limited to the
+copyright, patent, trademark or trade secret rights, of any third party;
+ * if your employer has rights to intellectual property you
+create, you have either (i) received permission from your employer to
+post or make available the Content, including but not limited to any
+software, or (ii) secured from your employer a waiver as to all rights
+in or to the Content;
+ * you have fully complied with any third-party licenses
+relating to the Content, and have done all things necessary to
+successfully pass through to end users any required terms;
+ * the Content does not contain or install any viruses,
+worms, malware, Trojan horses or other harmful or destructive content;
+ * the Content is not spam, is not machine- or
+randomly-generated, and does not contain unethical or unwanted
+commercial content designed to drive traffic to third party sites or
+boost the search engine rankings of third party sites, or to further
+unlawful acts (such as phishing) or mislead recipients as to the
+source of the material (such as spoofing);
+ * the Content is not libelous or defamatory (more info on
+what that means), does not contain threats or incite violence towards
+individuals or entities, and does not violate the privacy or publicity
+rights of any third party;
+ * your blog is not getting advertised via unwanted
+electronic messages such as spam links on newsgroups, email lists,
+other blogs and web sites, and similar unsolicited promotional methods;
+ * your blog is not named in a manner that misleads your
+readers into thinking that you are another person or company. For
+example, your blog’s URL or name is not the name of a person other
+than yourself or company other than your own; and
+ * you have, in the case of Content that includes computer
+code, accurately categorized and/or described the type, nature, uses
+and effects of the materials, whether requested to do so by Automattic
+or otherwise.
+
+ By submitting Content to Automattic for inclusion on your
+Website, you grant Automattic a world-wide, royalty-free, and
+non-exclusive license to reproduce, modify, adapt and publish the
+Content solely for the purpose of displaying, distributing and
+promoting your blog. If you delete Content, Automattic will use
+reasonable efforts to remove it from the Website, but you acknowledge
+that caching or references to the Content may not be made immediately
+unavailable.
+
+ Without limiting any of those representations or warranties,
+Automattic has the right (though not the obligation) to, in
+Automattic’s sole discretion (i) refuse or remove any content that, in
+Automattic’s reasonable opinion, violates any Automattic policy or is
+in any way harmful or objectionable, or (ii) terminate or deny access
+to and use of the Website to any individual or entity for any reason,
+in Automattic’s sole discretion. Automattic will have no obligation to
+provide a refund of any amounts previously paid.
+ 3. Fees and Payment. Optional premium paid services such as extra
+storage, domain purchases or VIP hosting are available on the Website.
+By selecting a premium service you agree to pay Automattic the monthly
+or annual subscription fees indicated for that service (the payment
+terms for VIP hosting are described below). Payments will be charged
+on the day you sign up for a premium service and will cover the use of
+that service for a monthly or annual period as indicated. Premium
+service fees are not refundable.
+ 4. VIP Services.
+ * Fees; Payment. By signing up for a VIP Services account
+you agree to pay Automattic the setup fees and monthly hosting fees
+indicated at http://wordpress.com/vip-hosting/ in exchange for the
+services listed at http://wordpress.com/vip-hosting/. Applicable fees
+will be invoiced starting from the day your VIP Services are
+established and in advance of using such services. Automattic reserves
+the right to change the payment terms and fees upon thirty (30) days
+prior written notice to you. VIP Services can be canceled by you at
+anytime on 30 days written notice to Automattic.
+ * Support. VIP Services include access to priority email
+support. “Email support” means the ability to make requests for
+technical support assistance by email at any time (with reasonable
+efforts by Automattic to respond within one business day) concerning
+the use of the VIP Services. “Priority” means that support for VIP
+Services customers takes priority over support for users of the
+standard, free WordPress.com blogging services. All VIP Services
+support will be provided in accordance with Automattic standard VIP
+Services practices, procedures and policies.
+ 5. Responsibility of Website Visitors. Automattic has not reviewed,
+and cannot review, all of the material, including computer software,
+posted to the Website, and cannot therefore be responsible for that
+material’s content, use or effects. By operating the Website,
+Automattic does not represent or imply that it endorses the material
+there posted, or that it believes such material to be accurate, useful
+or non-harmful. You are responsible for taking precautions as
+necessary to protect yourself and your computer systems from viruses,
+worms, Trojan horses, and other harmful or destructive content. The
+Website may contain content that is offensive, indecent, or otherwise
+objectionable, as well as content containing technical inaccuracies,
+typographical mistakes, and other errors. The Website may also contain
+material that violates the privacy or publicity rights, or infringes
+the intellectual property and other proprietary rights, of third
+parties, or the downloading, copying or use of which is subject to
+additional terms and conditions, stated or unstated. Automattic
+disclaims any responsibility for any harm resulting from the use by
+visitors of the Website, or from any downloading by those visitors of
+content there posted.
+ 6. Content Posted on Other Websites. We have not reviewed, and
+cannot review, all of the material, including computer software, made
+available through the websites and webpages to which WordPress.com
+links, and that link to WordPress.com. Automattic does not have any
+control over those non-WordPress websites and webpages, and is not
+responsible for their contents or their use. By linking to a
+non-WordPress website or webpage, Automattic does not represent or
+imply that it endorses such website or webpage. You are responsible
+for taking precautions as necessary to protect yourself and your
+computer systems from viruses, worms, Trojan horses, and other harmful
+or destructive content. Automattic disclaims any responsibility for
+any harm resulting from your use of non-WordPress websites and webpages.
+ 7. Copyright Infringement and DMCA Policy. As Automattic asks
+others to respect its intellectual property rights, it respects the
+intellectual property rights of others. If you believe that material
+located on or linked to by WordPress.com violates your copyright, you
+are encouraged to notify Automattic in accordance with Automattic’s
+Digital Millennium Copyright Act (”DMCA”) Policy. Automattic will
+respond to all such notices, including as required or appropriate by
+removing the infringing material or disabling all links to the
+infringing material. In the case of a visitor who may infringe or
+repeatedly infringes the copyrights or other intellectual property
+rights of Automattic or others, Automattic may, in its discretion,
+terminate or deny access to and use of the Website. In the case of
+such termination, Automattic will have no obligation to provide a
+refund of any amounts previously paid to Automattic.
+ 8. Intellectual Property. This Agreement does not transfer from
+Automattic to you any Automattic or third party intellectual property,
+and all right, title and interest in and to such property will remain
+(as between the parties) solely with Automattic. Automattic,
+WordPress, WordPress.com, the WordPress.com logo, and all other
+trademarks, service marks, graphics and logos used in connection with
+WordPress.com, or the Website are trademarks or registered trademarks
+of Automattic or Automattic’s licensors. Other trademarks, service
+marks, graphics and logos used in connection with the Website may be
+the trademarks of other third parties. Your use of the Website grants
+you no right or license to reproduce or otherwise use any Automattic
+or third-party trademarks.
+ 9. Changes. Automattic reserves the right, at its sole discretion,
+to modify or replace any part of this Agreement. It is your
+responsibility to check this Agreement periodically for changes. Your
+continued use of or access to the Website following the posting of any
+changes to this Agreement constitutes acceptance of those changes.
+Automattic may also, in the future, offer new services and/or features
+through the Website (including, the release of new tools and
+resources). Such new features and/or services shall be subject to the
+terms and conditions of this Agreement.
+ 10. Termination. Automattic may terminate your access to all or any
+part of the Website at any time, with or without cause, with or
+without notice, effective immediately. If you wish to terminate this
+Agreement or your WordPress.com account (if you have one), you may
+simply discontinue using the Website. Notwithstanding the foregoing,
+if you have a VIP Services account, such account can only be
+terminated by Automattic if you materially breach this Agreement and
+fail to cure such breach within thirty (30) days from Automattic’s
+notice to you thereof; provided that, Automattic can terminate the
+Website immediately as part of a general shut down of our service. All
+provisions of this Agreement which by their nature should survive
+termination shall survive termination, including, without limitation,
+ownership provisions, warranty disclaimers, indemnity and limitations
+of liability.
+ 11. Disclaimer of Warranties. The Website is provided “as is”.
+Automattic and its suppliers and licensors hereby disclaim all
+warranties of any kind, express or implied, including, without
+limitation, the warranties of merchantability, fitness for a
+particular purpose and non-infringement. Neither Automattic nor its
+suppliers and licensors, makes any warranty that the Website will be
+error free or that access thereto will be continuous or uninterrupted.
+If you’re actually reading this, here’s a treat. You understand that
+you download from, or otherwise obtain content or services through,
+the Website at your own discretion and risk.
+ 12. Limitation of Liability. In no event will Automattic, or its
+suppliers or licensors, be liable with respect to any subject matter
+of this agreement under any contract, negligence, strict liability or
+other legal or equitable theory for: (i) any special, incidental or
+consequential damages; (ii) the cost of procurement or substitute
+products or services; (iii) for interruption of use or loss or
+corruption of data; or (iv) for any amounts that exceed the fees paid
+by you to Automattic under this agreement during the twelve (12) month
+period prior to the cause of action. Automattic shall have no
+liability for any failure or delay due to matters beyond their
+reasonable control. The foregoing shall not apply to the extent
+prohibited by applicable law.
+ 13. General Representation and Warranty. You represent and warrant
+that (i) your use of the Website will be in strict accordance with the
+Automattic Privacy Policy, with this Agreement and with all applicable
+laws and regulations (including without limitation any local laws or
+regulations in your country, state, city, or other governmental area,
+regarding online conduct and acceptable content, and including all
+applicable laws regarding the transmission of technical data exported
+from the United States or the country in which you reside) and (ii)
+your use of the Website will not infringe or misappropriate the
+intellectual property rights of any third party.
+ 14. Indemnification. You agree to indemnify and hold harmless
+Automattic, its contractors, and its licensors, and their respective
+directors, officers, employees and agents from and against any and all
+claims and expenses, including attorneys’ fees, arising out of your
+use of the Website, including but not limited to out of your violation
+this Agreement.
+ 15. Miscellaneous. This Agreement constitutes the entire agreement
+between Automattic and you concerning the subject matter hereof, and
+they may only be modified by a written amendment signed by an
+authorized executive of Automattic, or by the posting by Automattic of
+a revised version. Except to the extent applicable law, if any,
+provides otherwise, this Agreement, any access to or use of the
+Website will be governed by the laws of the state of California,
+U.S.A., excluding its conflict of law provisions, and the proper venue
+for any disputes arising out of or relating to any of the same will be
+the state and federal courts located in San Francisco County,
+California. Except for claims for injunctive or equitable relief or
+claims regarding intellectual property rights (which may be brought in
+any competent court without the posting of a bond), any dispute
+arising under this Agreement shall be finally settled in accordance
+with the Comprehensive Arbitration Rules of the Judicial Arbitration
+and Mediation Service, Inc. (“JAMS”) by three arbitrators appointed in
+accordance with such Rules. The arbitration shall take place in San
+Francisco, California, in the English language and the arbitral
+decision may be enforced in any court. The prevailing party in any
+action or proceeding to enforce this Agreement shall be entitled to
+costs and attorneys’ fees. If any part of this Agreement is held
+invalid or unenforceable, that part will be construed to reflect the
+parties’ original intent, and the remaining portions will remain in
+full force and effect. A waiver by either party of any term or
+condition of this Agreement or any breach thereof, in any one
+instance, will not waive such term or condition or any subsequent
+breach thereof. You may assign your rights under this Agreement to any
+party that consents to, and agrees to be bound by, its terms and
+conditions; Automattic may assign its rights under this Agreement
+without condition. This Agreement will be binding upon and will inure
+to the benefit of the parties, their successors and permitted assigns.
+
+*Originally published by Automattic, Inc. as the [WordPress.com Terms
+of Service](http://en.wordpress.com/tos/) and made available by them
+under the [Creative Commons Attribution-ShareAlike 3.0
+License](http://creativecommons.org/licenses/by-sa/3.0/).*
\ No newline at end of file
--
cgit v1.2.3-54-g00ecf
From 232dac67bd8c1701940c52eb46f2cd6b83e7d4c3 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 20 Jun 2009 22:13:06 -0700
Subject: reformat for Markdown
---
doc-src/tos | 339 ++++++++++++++++++++++++++++++++++--------------------------
1 file changed, 190 insertions(+), 149 deletions(-)
diff --git a/doc-src/tos b/doc-src/tos
index 10c5e0fd2..bfb6a445f 100644
--- a/doc-src/tos
+++ b/doc-src/tos
@@ -1,155 +1,183 @@
The gist
--------
-We (the folks at Automattic) run a service called WordPress.com and
-would love for you to use it. Our basic service is free, and we offer
-paid upgrades for advanced features such as domain hosting and extra
-storage. Our service is designed to give you as much control and
-ownership over what goes on your blog as possible and encourage you to
-express yourself freely. However, be responsible in what you blog. In
-particular, make sure that none of the prohibited items listed below
-appear on your blog or get linked to from your blog (things like spam,
-viruses, or hate content).
+We (the folks at [%%site.broughtby%%](%%site.broughtbyurl%%)) run a
+service called %%site.name%% and would love for you to use it. Our
+basic service is free, and we offer paid upgrades for advanced
+features such as domain hosting and extra storage. Our service is
+designed to give you as much control and ownership over what goes on
+your blog as possible and encourage you to express yourself freely.
+However, be responsible in what you blog. In particular, make sure
+that none of the prohibited items listed below appear on your blog or
+get linked to from your blog (things like spam, viruses, or hate
+content).
You can check our page on types of blogs to get a sense of the types
of sites that are welcome on our service (or not!). If you find a
-WordPress.com blog that you believe violates our terms of service,
+%%site.name%% blog that you believe violates our terms of service,
please check our complaints page.
(Note, we’ve decided to make the below Terms of Service available
under a Creative Commons Sharealike license, which means you’re more
than welcome to steal it and repurpose it for your own use, just make
sure to replace references to us with ones to you, and if you want
-we’d appreciate a link to WordPress.com somewhere on your site. We
+we’d appreciate a link to %%site.name%% somewhere on your site. We
spent a lot of money and time on the below, and other people shouldn’t
need to do the same.)
-Terms of Service:
-The following terms and conditions govern all use of the WordPress.com
+Terms of Service
+----------------
+
+The following terms and conditions govern all use of the %%site.name%%
website and all content, services and products available at or through
-the website, including, but not limited to, the WordPress.com VIP
-hosting service (“VIP Service”), (taken together, the Website). The
-Website is owned and operated by Automattic, Inc. (“Automattic”). The
-Website is offered subject to your acceptance without modification of
-all of the terms and conditions contained herein and all other
-operating rules, policies (including, without limitation, Automattic’s
-Privacy Policy) and procedures that may be published from time to time
-on this Site by Automattic (collectively, the “Agreement”).
+the website (taken together, the Website). The Website is owned and
+operated by %%site.broughtby%% (“Operator”). The Website is offered
+subject to your acceptance without modification of all of the terms
+and conditions contained herein and all other operating rules,
+policies (including, without limitation, Operator’s Privacy Policy)
+and procedures that may be published from time to time on this Site by
+Operator (collectively, the “Agreement”).
Please read this Agreement carefully before accessing or using the
Website. By accessing or using any part of the web site, you agree to
become bound by the terms and conditions of this agreement. If you do
not agree to all the terms and conditions of this agreement, then you
may not access the Website or use any services. If these terms and
-conditions are considered an offer by Automattic, acceptance is
+conditions are considered an offer by Operator, acceptance is
expressly limited to these terms. The Website is available only to
individuals who are at least 13 years old.
- 1. Your WordPress.com Account and Site. If you create a blog on the
-Website, you are responsible for maintaining the security of your
-account and blog, and you are fully responsible for all activities
-that occur under the account and any other actions taken in connection
-with the blog. You must not describe or assign keywords to your blog
-in a misleading or unlawful manner, including in a manner intended to
-trade on the name or reputation of others, and Automattic may change
-or remove any description or keyword that it considers inappropriate
-or unlawful, or otherwise likely to cause Automattic liability. You
-must immediately notify Automattic of any unauthorized uses of your
-blog, your account or any other breaches of security. Automattic will
-not be liable for any acts or omissions by You, including any damages
-of any kind incurred as a result of such acts or omissions.
- 2. Responsibility of Contributors. If you operate a blog, comment
-on a blog, post material to the Website, post links on the Website, or
+
+
+
Your %%site.name%% Account and Site. If you
+create a blog on the Website, you are responsible for maintaining the
+security of your account and blog, and you are fully responsible for
+all activities that occur under the account and any other actions
+taken in connection with the blog. You must not describe or assign
+keywords to your blog in a misleading or unlawful manner, including in
+a manner intended to trade on the name or reputation of others, and
+Operator may change or remove any description or keyword that it
+considers inappropriate or unlawful, or otherwise likely to cause
+Operator liability. You must immediately notify Operator of any
+unauthorized uses of your blog, your account or any other breaches of
+security. Operator will not be liable for any acts or omissions by
+You, including any damages of any kind incurred as a result of such
+acts or omissions.
+
+
Responsibility of Contributors. If you operate a blog, comment on a
+blog, post material to the Website, post links on the Website, or
otherwise make (or allow any third party to make) material available
by means of the Website (any such material, “Content”), You are
entirely responsible for the content of, and any harm resulting from,
that Content. That is the case regardless of whether the Content in
question constitutes text, graphics, an audio file, or computer
software. By making Content available, you represent and warrant that:
- * the downloading, copying and use of the Content will not
-infringe the proprietary rights, including but not limited to the
-copyright, patent, trademark or trade secret rights, of any third party;
- * if your employer has rights to intellectual property you
-create, you have either (i) received permission from your employer to
-post or make available the Content, including but not limited to any
-software, or (ii) secured from your employer a waiver as to all rights
-in or to the Content;
- * you have fully complied with any third-party licenses
+
+
+
+
the downloading, copying and use of the Content will not infringe
+the proprietary rights, including but not limited to the copyright,
+patent, trademark or trade secret rights, of any third party;
+
+
if your employer has rights to intellectual property you create,
+you have either (i) received permission from your employer to post or
+make available the Content, including but not limited to any software,
+or (ii) secured from your employer a waiver as to all rights in or to
+the Content;
+
+
you have fully complied with any third-party licenses
relating to the Content, and have done all things necessary to
-successfully pass through to end users any required terms;
- * the Content does not contain or install any viruses,
-worms, malware, Trojan horses or other harmful or destructive content;
- * the Content is not spam, is not machine- or
-randomly-generated, and does not contain unethical or unwanted
-commercial content designed to drive traffic to third party sites or
-boost the search engine rankings of third party sites, or to further
-unlawful acts (such as phishing) or mislead recipients as to the
-source of the material (such as spoofing);
- * the Content is not libelous or defamatory (more info on
+successfully pass through to end users any required terms;
+
+
the Content does not contain or install any viruses, worms, malware,
+Trojan horses or other harmful or destructive content;
+
+
the Content is not spam, is not machine- or randomly-generated, and does not
+contain unethical or unwanted commercial content designed to drive
+traffic to third party sites or boost the search engine rankings of
+third party sites, or to further unlawful acts (such as phishing) or
+mislead recipients as to the source of the material (such as
+spoofing);
+
+
the Content is not libelous or defamatory (more info on
what that means), does not contain threats or incite violence towards
individuals or entities, and does not violate the privacy or publicity
-rights of any third party;
- * your blog is not getting advertised via unwanted
-electronic messages such as spam links on newsgroups, email lists,
-other blogs and web sites, and similar unsolicited promotional methods;
- * your blog is not named in a manner that misleads your
+rights of any third party;
+
+
your blog is not getting advertised via unwanted electronic
+messages such as spam links on newsgroups, email lists, other blogs
+and web sites, and similar unsolicited promotional methods;
+
+
your blog is not named in a manner that misleads your
readers into thinking that you are another person or company. For
example, your blog’s URL or name is not the name of a person other
-than yourself or company other than your own; and
- * you have, in the case of Content that includes computer
-code, accurately categorized and/or described the type, nature, uses
-and effects of the materials, whether requested to do so by Automattic
-or otherwise.
-
- By submitting Content to Automattic for inclusion on your
-Website, you grant Automattic a world-wide, royalty-free, and
-non-exclusive license to reproduce, modify, adapt and publish the
-Content solely for the purpose of displaying, distributing and
-promoting your blog. If you delete Content, Automattic will use
-reasonable efforts to remove it from the Website, but you acknowledge
-that caching or references to the Content may not be made immediately
-unavailable.
-
- Without limiting any of those representations or warranties,
-Automattic has the right (though not the obligation) to, in
-Automattic’s sole discretion (i) refuse or remove any content that, in
-Automattic’s reasonable opinion, violates any Automattic policy or is
-in any way harmful or objectionable, or (ii) terminate or deny access
-to and use of the Website to any individual or entity for any reason,
-in Automattic’s sole discretion. Automattic will have no obligation to
-provide a refund of any amounts previously paid.
- 3. Fees and Payment. Optional premium paid services such as extra
+than yourself or company other than your own; and
+
+
you have, in the
+case of Content that includes computer code, accurately categorized
+and/or described the type, nature, uses and effects of the materials,
+whether requested to do so by Operator or otherwise.
+
+
+
+
By submitting Content to Operator for inclusion on your Website, you
+grant Operator a world-wide, royalty-free, and non-exclusive license
+to reproduce, modify, adapt and publish the Content solely for the
+purpose of displaying, distributing and promoting your blog. If you
+delete Content, Operator will use reasonable efforts to remove it from
+the Website, but you acknowledge that caching or references to the
+Content may not be made immediately unavailable.
+
+
Without limiting any of those representations or warranties, Operator
+has the right (though not the obligation) to, in Operator’s sole
+discretion (i) refuse or remove any content that, in Operator’s
+reasonable opinion, violates any Operator policy or is in any way
+harmful or objectionable, or (ii) terminate or deny access to and use
+of the Website to any individual or entity for any reason, in
+Operator’s sole discretion. Operator will have no obligation to
+provide a refund of any amounts previously paid.
+
+
+
Fees and Payment. Optional premium paid services such as extra
storage, domain purchases or VIP hosting are available on the Website.
-By selecting a premium service you agree to pay Automattic the monthly
+By selecting a premium service you agree to pay Operator the monthly
or annual subscription fees indicated for that service (the payment
terms for VIP hosting are described below). Payments will be charged
on the day you sign up for a premium service and will cover the use of
that service for a monthly or annual period as indicated. Premium
-service fees are not refundable.
- 4. VIP Services.
- * Fees; Payment. By signing up for a VIP Services account
-you agree to pay Automattic the setup fees and monthly hosting fees
+service fees are not refundable.
+
+
VIP Services.
+
+
+
Fees; Payment. By signing up for a VIP Services account
+you agree to pay Operator the setup fees and monthly hosting fees
indicated at http://wordpress.com/vip-hosting/ in exchange for the
services listed at http://wordpress.com/vip-hosting/. Applicable fees
will be invoiced starting from the day your VIP Services are
-established and in advance of using such services. Automattic reserves
+established and in advance of using such services. Operator reserves
the right to change the payment terms and fees upon thirty (30) days
prior written notice to you. VIP Services can be canceled by you at
-anytime on 30 days written notice to Automattic.
- * Support. VIP Services include access to priority email
+anytime on 30 days written notice to Operator.
+
+
Support. VIP Services include access to priority email
support. “Email support” means the ability to make requests for
technical support assistance by email at any time (with reasonable
-efforts by Automattic to respond within one business day) concerning
+efforts by Operator to respond within one business day) concerning
the use of the VIP Services. “Priority” means that support for VIP
Services customers takes priority over support for users of the
-standard, free WordPress.com blogging services. All VIP Services
-support will be provided in accordance with Automattic standard VIP
+standard, free %%site.name%% blogging services. All VIP Services
+support will be provided in accordance with Operator standard VIP
Services practices, procedures and policies.
- 5. Responsibility of Website Visitors. Automattic has not reviewed,
+
+
+
+
+
Responsibility of Website Visitors. Operator has not reviewed,
and cannot review, all of the material, including computer software,
posted to the Website, and cannot therefore be responsible for that
material’s content, use or effects. By operating the Website,
-Automattic does not represent or imply that it endorses the material
+Operator does not represent or imply that it endorses the material
there posted, or that it believes such material to be accurate, useful
or non-harmful. You are responsible for taking precautions as
necessary to protect yourself and your computer systems from viruses,
@@ -160,113 +188,124 @@ typographical mistakes, and other errors. The Website may also contain
material that violates the privacy or publicity rights, or infringes
the intellectual property and other proprietary rights, of third
parties, or the downloading, copying or use of which is subject to
-additional terms and conditions, stated or unstated. Automattic
+additional terms and conditions, stated or unstated. Operator
disclaims any responsibility for any harm resulting from the use by
visitors of the Website, or from any downloading by those visitors of
-content there posted.
- 6. Content Posted on Other Websites. We have not reviewed, and
+content there posted.
+
+
Content Posted on Other Websites. We have not reviewed, and
cannot review, all of the material, including computer software, made
-available through the websites and webpages to which WordPress.com
-links, and that link to WordPress.com. Automattic does not have any
+available through the websites and webpages to which %%site.name%%
+links, and that link to %%site.name%%. Operator does not have any
control over those non-WordPress websites and webpages, and is not
responsible for their contents or their use. By linking to a
-non-WordPress website or webpage, Automattic does not represent or
+non-WordPress website or webpage, Operator does not represent or
imply that it endorses such website or webpage. You are responsible
for taking precautions as necessary to protect yourself and your
computer systems from viruses, worms, Trojan horses, and other harmful
-or destructive content. Automattic disclaims any responsibility for
-any harm resulting from your use of non-WordPress websites and webpages.
- 7. Copyright Infringement and DMCA Policy. As Automattic asks
+or destructive content. Operator disclaims any responsibility for
+any harm resulting from your use of non-WordPress websites and
+webpages.
+
+
Copyright Infringement and DMCA Policy. As Operator asks
others to respect its intellectual property rights, it respects the
intellectual property rights of others. If you believe that material
-located on or linked to by WordPress.com violates your copyright, you
-are encouraged to notify Automattic in accordance with Automattic’s
-Digital Millennium Copyright Act (”DMCA”) Policy. Automattic will
+located on or linked to by %%site.name%% violates your copyright, you
+are encouraged to notify Operator in accordance with Operator’s
+Digital Millennium Copyright Act (”DMCA”) Policy. Operator will
respond to all such notices, including as required or appropriate by
removing the infringing material or disabling all links to the
infringing material. In the case of a visitor who may infringe or
repeatedly infringes the copyrights or other intellectual property
-rights of Automattic or others, Automattic may, in its discretion,
+rights of Operator or others, Operator may, in its discretion,
terminate or deny access to and use of the Website. In the case of
-such termination, Automattic will have no obligation to provide a
-refund of any amounts previously paid to Automattic.
- 8. Intellectual Property. This Agreement does not transfer from
-Automattic to you any Automattic or third party intellectual property,
+such termination, Operator will have no obligation to provide a
+refund of any amounts previously paid to Operator.
+
+
Intellectual Property. This Agreement does not transfer from
+Operator to you any Operator or third party intellectual property,
and all right, title and interest in and to such property will remain
-(as between the parties) solely with Automattic. Automattic,
-WordPress, WordPress.com, the WordPress.com logo, and all other
+(as between the parties) solely with Operator. Operator,
+WordPress, %%site.name%%, the %%site.name%% logo, and all other
trademarks, service marks, graphics and logos used in connection with
-WordPress.com, or the Website are trademarks or registered trademarks
-of Automattic or Automattic’s licensors. Other trademarks, service
+%%site.name%%, or the Website are trademarks or registered trademarks
+of Operator or Operator’s licensors. Other trademarks, service
marks, graphics and logos used in connection with the Website may be
the trademarks of other third parties. Your use of the Website grants
-you no right or license to reproduce or otherwise use any Automattic
-or third-party trademarks.
- 9. Changes. Automattic reserves the right, at its sole discretion,
+you no right or license to reproduce or otherwise use any Operator
+or third-party trademarks.
+
+
Changes. Operator reserves the right, at its sole discretion,
to modify or replace any part of this Agreement. It is your
responsibility to check this Agreement periodically for changes. Your
continued use of or access to the Website following the posting of any
changes to this Agreement constitutes acceptance of those changes.
-Automattic may also, in the future, offer new services and/or features
+Operator may also, in the future, offer new services and/or features
through the Website (including, the release of new tools and
resources). Such new features and/or services shall be subject to the
-terms and conditions of this Agreement.
- 10. Termination. Automattic may terminate your access to all or any
+terms and conditions of this Agreement.
+
+
Termination. Operator may terminate your access to all or any
part of the Website at any time, with or without cause, with or
without notice, effective immediately. If you wish to terminate this
-Agreement or your WordPress.com account (if you have one), you may
+Agreement or your %%site.name%% account (if you have one), you may
simply discontinue using the Website. Notwithstanding the foregoing,
if you have a VIP Services account, such account can only be
-terminated by Automattic if you materially breach this Agreement and
-fail to cure such breach within thirty (30) days from Automattic’s
-notice to you thereof; provided that, Automattic can terminate the
+terminated by Operator if you materially breach this Agreement and
+fail to cure such breach within thirty (30) days from Operator’s
+notice to you thereof; provided that, Operator can terminate the
Website immediately as part of a general shut down of our service. All
provisions of this Agreement which by their nature should survive
termination shall survive termination, including, without limitation,
ownership provisions, warranty disclaimers, indemnity and limitations
-of liability.
- 11. Disclaimer of Warranties. The Website is provided “as is”.
-Automattic and its suppliers and licensors hereby disclaim all
+of liability.
+
+
Disclaimer of Warranties. The Website is provided “as is”.
+Operator and its suppliers and licensors hereby disclaim all
warranties of any kind, express or implied, including, without
limitation, the warranties of merchantability, fitness for a
-particular purpose and non-infringement. Neither Automattic nor its
+particular purpose and non-infringement. Neither Operator nor its
suppliers and licensors, makes any warranty that the Website will be
error free or that access thereto will be continuous or uninterrupted.
If you’re actually reading this, here’s a treat. You understand that
you download from, or otherwise obtain content or services through,
-the Website at your own discretion and risk.
- 12. Limitation of Liability. In no event will Automattic, or its
+the Website at your own discretion and risk.
+
+
Limitation of Liability. In no event will Operator, or its
suppliers or licensors, be liable with respect to any subject matter
of this agreement under any contract, negligence, strict liability or
other legal or equitable theory for: (i) any special, incidental or
consequential damages; (ii) the cost of procurement or substitute
products or services; (iii) for interruption of use or loss or
corruption of data; or (iv) for any amounts that exceed the fees paid
-by you to Automattic under this agreement during the twelve (12) month
-period prior to the cause of action. Automattic shall have no
+by you to Operator under this agreement during the twelve (12) month
+period prior to the cause of action. Operator shall have no
liability for any failure or delay due to matters beyond their
reasonable control. The foregoing shall not apply to the extent
-prohibited by applicable law.
- 13. General Representation and Warranty. You represent and warrant
+prohibited by applicable law.
+
+
General Representation and Warranty. You represent and warrant
that (i) your use of the Website will be in strict accordance with the
-Automattic Privacy Policy, with this Agreement and with all applicable
+Operator Privacy Policy, with this Agreement and with all applicable
laws and regulations (including without limitation any local laws or
regulations in your country, state, city, or other governmental area,
regarding online conduct and acceptable content, and including all
applicable laws regarding the transmission of technical data exported
from the United States or the country in which you reside) and (ii)
your use of the Website will not infringe or misappropriate the
-intellectual property rights of any third party.
- 14. Indemnification. You agree to indemnify and hold harmless
-Automattic, its contractors, and its licensors, and their respective
+intellectual property rights of any third party.
+
+
Indemnification. You agree to indemnify and hold harmless
+Operator, its contractors, and its licensors, and their respective
directors, officers, employees and agents from and against any and all
claims and expenses, including attorneys’ fees, arising out of your
use of the Website, including but not limited to out of your violation
-this Agreement.
- 15. Miscellaneous. This Agreement constitutes the entire agreement
-between Automattic and you concerning the subject matter hereof, and
+this Agreement.
+
+
Miscellaneous. This Agreement constitutes the entire agreement
+between Operator and you concerning the subject matter hereof, and
they may only be modified by a written amendment signed by an
-authorized executive of Automattic, or by the posting by Automattic of
+authorized executive of Operator, or by the posting by Operator of
a revised version. Except to the extent applicable law, if any,
provides otherwise, this Agreement, any access to or use of the
Website will be governed by the laws of the state of California,
@@ -291,9 +330,11 @@ condition of this Agreement or any breach thereof, in any one
instance, will not waive such term or condition or any subsequent
breach thereof. You may assign your rights under this Agreement to any
party that consents to, and agrees to be bound by, its terms and
-conditions; Automattic may assign its rights under this Agreement
+conditions; Operator may assign its rights under this Agreement
without condition. This Agreement will be binding upon and will inure
-to the benefit of the parties, their successors and permitted assigns.
+to the benefit of the parties, their successors and permitted
+assigns.
+
*Originally published by Automattic, Inc. as the [WordPress.com Terms
of Service](http://en.wordpress.com/tos/) and made available by them
--
cgit v1.2.3-54-g00ecf
From 2f991f93963f60a9a5432816ae64950c7e810a0e Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 20 Jun 2009 22:34:05 -0700
Subject: focus on microblogging
---
doc-src/tos | 336 ++++++++++++++++++++++++++----------------------------------
1 file changed, 147 insertions(+), 189 deletions(-)
diff --git a/doc-src/tos b/doc-src/tos
index bfb6a445f..bcfc31981 100644
--- a/doc-src/tos
+++ b/doc-src/tos
@@ -3,27 +3,26 @@ The gist
We (the folks at [%%site.broughtby%%](%%site.broughtbyurl%%)) run a
service called %%site.name%% and would love for you to use it. Our
-basic service is free, and we offer paid upgrades for advanced
-features such as domain hosting and extra storage. Our service is
-designed to give you as much control and ownership over what goes on
-your blog as possible and encourage you to express yourself freely.
-However, be responsible in what you blog. In particular, make sure
-that none of the prohibited items listed below appear on your blog or
-get linked to from your blog (things like spam, viruses, or hate
-content).
-
-You can check our page on types of blogs to get a sense of the types
-of sites that are welcome on our service (or not!). If you find a
-%%site.name%% blog that you believe violates our terms of service,
-please check our complaints page.
-
-(Note, we’ve decided to make the below Terms of Service available
-under a Creative Commons Sharealike license, which means you’re more
-than welcome to steal it and repurpose it for your own use, just make
-sure to replace references to us with ones to you, and if you want
-we’d appreciate a link to %%site.name%% somewhere on your site. We
-spent a lot of money and time on the below, and other people shouldn’t
-need to do the same.)
+service is designed to give you as much control and ownership over
+what goes in your notice stream as possible and encourage you to
+express yourself freely. However, be responsible in what you post. In
+particular, make sure that none of the prohibited items listed below
+appear in your notice stream or get linked to from your notice stream (things
+like spam, viruses, or hate content).
+
+You can review our [Public Stream](%%action.public%%) to get a sense
+of the types of notices that are welcome on our service (or not!). If
+you find a %%site.name%% account that you believe violates our terms
+of service, please check our [Contact](%%doc.contact%%) documentation.
+
+(Note: Automattic, Inc., original creators of the below Terms of
+Service, decided to make them available under a Creative Commons
+Sharealike license, which means you’re more than welcome to steal it
+and repurpose it for your own use. Just make sure to replace
+references to us with ones to you. They’d appreciate a link to
+[WordPress.com](http://www.wordpress.com/) somewhere on your site.
+They spent a lot of money and time on the below, and other people
+shouldn’t need to do the same. (We didn't!))
Terms of Service
----------------
@@ -34,7 +33,8 @@ the website (taken together, the Website). The Website is owned and
operated by %%site.broughtby%% (“Operator”). The Website is offered
subject to your acceptance without modification of all of the terms
and conditions contained herein and all other operating rules,
-policies (including, without limitation, Operator’s Privacy Policy)
+policies (including, without limitation, Operator’s [Privacy
+Policy](%%doc.privacy%%))
and procedures that may be published from time to time on this Site by
Operator (collectively, the “Agreement”).
@@ -50,28 +50,29 @@ individuals who are at least 13 years old.
Your %%site.name%% Account and Site. If you
-create a blog on the Website, you are responsible for maintaining the
-security of your account and blog, and you are fully responsible for
-all activities that occur under the account and any other actions
-taken in connection with the blog. You must not describe or assign
-keywords to your blog in a misleading or unlawful manner, including in
-a manner intended to trade on the name or reputation of others, and
-Operator may change or remove any description or keyword that it
-considers inappropriate or unlawful, or otherwise likely to cause
-Operator liability. You must immediately notify Operator of any
-unauthorized uses of your blog, your account or any other breaches of
-security. Operator will not be liable for any acts or omissions by
-You, including any damages of any kind incurred as a result of such
-acts or omissions.
-
-
Responsibility of Contributors. If you operate a blog, comment on a
-blog, post material to the Website, post links on the Website, or
-otherwise make (or allow any third party to make) material available
-by means of the Website (any such material, “Content”), You are
-entirely responsible for the content of, and any harm resulting from,
-that Content. That is the case regardless of whether the Content in
-question constitutes text, graphics, an audio file, or computer
-software. By making Content available, you represent and warrant that:
+create a notice stream on the Website, you are responsible for
+maintaining the security of your account and notice stream, and you
+are fully responsible for all activities that occur under the account
+and any other actions taken in connection with the notice stream. You
+must not describe or assign keywords to your notice stream in a
+misleading or unlawful manner, including in a manner intended to trade
+on the name or reputation of others, and Operator may change or remove
+any description or keyword that it considers inappropriate or
+unlawful, or otherwise likely to cause Operator liability. You must
+immediately notify Operator of any unauthorized uses of your notice
+stream, your account or any other breaches of security. Operator will
+not be liable for any acts or omissions by You, including any damages
+of any kind incurred as a result of such acts or omissions.
+
+
Responsibility of Contributors. If you operate a
+notice stream, comment on a notice stream, post material to the
+Website, post links on the Website, or otherwise make (or allow any
+third party to make) material available by means of the Website (any
+such material, “Content”), You are entirely responsible for the
+content of, and any harm resulting from, that Content. That is the
+case regardless of whether the Content in question constitutes text,
+graphics, an audio file, or computer software. By making Content
+available, you represent and warrant that:
@@ -92,39 +93,49 @@ successfully pass through to end users any required terms;
the Content does not contain or install any viruses, worms, malware,
Trojan horses or other harmful or destructive content;
-
the Content is not spam, is not machine- or randomly-generated, and does not
-contain unethical or unwanted commercial content designed to drive
-traffic to third party sites or boost the search engine rankings of
-third party sites, or to further unlawful acts (such as phishing) or
-mislead recipients as to the source of the material (such as
-spoofing);
+
the Content is not spam, and does not contain unethical or
+unwanted commercial content designed to drive traffic to third party
+sites or boost the search engine rankings of third party sites, or to
+further unlawful acts (such as phishing) or mislead recipients as to
+the source of the material (such as spoofing);
+
+
if the Content is machine- or randomly-generated, it is for
+purposes of direct entertainment, information and/or utility for you
+or other users, and not for spam,
the Content is not libelous or defamatory (more info on
what that means), does not contain threats or incite violence towards
individuals or entities, and does not violate the privacy or publicity
rights of any third party;
-
your blog is not getting advertised via unwanted electronic
-messages such as spam links on newsgroups, email lists, other blogs
+
your notice stream is not getting advertised via unwanted electronic
+messages such as spam links on newsgroups, email lists, other notice streams
and web sites, and similar unsolicited promotional methods;
-
your blog is not named in a manner that misleads your
+
your notice stream is not named in a manner that misleads your
readers into thinking that you are another person or company. For
-example, your blog’s URL or name is not the name of a person other
+example, your notice stream’s URL or name is not the name of a person other
than yourself or company other than your own; and
-
you have, in the
-case of Content that includes computer code, accurately categorized
-and/or described the type, nature, uses and effects of the materials,
-whether requested to do so by Operator or otherwise.
+
you have, in the case of Content that includes computer code,
+accurately categorized and/or described the type, nature, uses and
+effects of the materials, whether requested to do so by Operator or
+otherwise.
By submitting Content to Operator for inclusion on your Website, you
grant Operator a world-wide, royalty-free, and non-exclusive license
to reproduce, modify, adapt and publish the Content solely for the
-purpose of displaying, distributing and promoting your blog. If you
-delete Content, Operator will use reasonable efforts to remove it from
+purpose of displaying, distributing and promoting your notice
+stream.
+
+
By submitting Content to Operator for inclusion on your Website,
+you grant all readers the right to use, re-use, modify and/or
+re-distribute the Content under the terms of the %%license.title%%.
+
+
If you delete Content, Operator will use reasonable efforts to remove it from
the Website, but you acknowledge that caching or references to the
Content may not be made immediately unavailable.
@@ -134,43 +145,7 @@ discretion (i) refuse or remove any content that, in Operator’s
reasonable opinion, violates any Operator policy or is in any way
harmful or objectionable, or (ii) terminate or deny access to and use
of the Website to any individual or entity for any reason, in
-Operator’s sole discretion. Operator will have no obligation to
-provide a refund of any amounts previously paid.
-
-
-
Fees and Payment. Optional premium paid services such as extra
-storage, domain purchases or VIP hosting are available on the Website.
-By selecting a premium service you agree to pay Operator the monthly
-or annual subscription fees indicated for that service (the payment
-terms for VIP hosting are described below). Payments will be charged
-on the day you sign up for a premium service and will cover the use of
-that service for a monthly or annual period as indicated. Premium
-service fees are not refundable.
-
-
VIP Services.
-
-
-
Fees; Payment. By signing up for a VIP Services account
-you agree to pay Operator the setup fees and monthly hosting fees
-indicated at http://wordpress.com/vip-hosting/ in exchange for the
-services listed at http://wordpress.com/vip-hosting/. Applicable fees
-will be invoiced starting from the day your VIP Services are
-established and in advance of using such services. Operator reserves
-the right to change the payment terms and fees upon thirty (30) days
-prior written notice to you. VIP Services can be canceled by you at
-anytime on 30 days written notice to Operator.
-
-
Support. VIP Services include access to priority email
-support. “Email support” means the ability to make requests for
-technical support assistance by email at any time (with reasonable
-efforts by Operator to respond within one business day) concerning
-the use of the VIP Services. “Priority” means that support for VIP
-Services customers takes priority over support for users of the
-standard, free %%site.name%% blogging services. All VIP Services
-support will be provided in accordance with Operator standard VIP
-Services practices, procedures and policies.
-
-
+Operator’s sole discretion.
Responsibility of Website Visitors. Operator has not reviewed,
@@ -197,14 +172,14 @@ content there posted.
cannot review, all of the material, including computer software, made
available through the websites and webpages to which %%site.name%%
links, and that link to %%site.name%%. Operator does not have any
-control over those non-WordPress websites and webpages, and is not
+control over those external websites and webpages, and is not
responsible for their contents or their use. By linking to a
-non-WordPress website or webpage, Operator does not represent or
+external website or webpage, Operator does not represent or
imply that it endorses such website or webpage. You are responsible
for taking precautions as necessary to protect yourself and your
computer systems from viruses, worms, Trojan horses, and other harmful
or destructive content. Operator disclaims any responsibility for
-any harm resulting from your use of non-WordPress websites and
+any harm resulting from your use of external websites and
webpages.
Copyright Infringement and DMCA Policy. As Operator asks
@@ -222,46 +197,41 @@ terminate or deny access to and use of the Website. In the case of
such termination, Operator will have no obligation to provide a
refund of any amounts previously paid to Operator.
-
Intellectual Property. This Agreement does not transfer from
-Operator to you any Operator or third party intellectual property,
-and all right, title and interest in and to such property will remain
-(as between the parties) solely with Operator. Operator,
-WordPress, %%site.name%%, the %%site.name%% logo, and all other
-trademarks, service marks, graphics and logos used in connection with
+
Intellectual Property. This Agreement does not
+transfer from Operator to you any Operator or third party intellectual
+property, and all right, title and interest in and to such property
+will remain (as between the parties) solely with Operator.
+%%site.name%%, the %%site.name%% logo, and all other trademarks,
+service marks, graphics and logos used in connection with
%%site.name%%, or the Website are trademarks or registered trademarks
-of Operator or Operator’s licensors. Other trademarks, service
-marks, graphics and logos used in connection with the Website may be
-the trademarks of other third parties. Your use of the Website grants
-you no right or license to reproduce or otherwise use any Operator
-or third-party trademarks.
-
-
Changes. Operator reserves the right, at its sole discretion,
-to modify or replace any part of this Agreement. It is your
-responsibility to check this Agreement periodically for changes. Your
-continued use of or access to the Website following the posting of any
-changes to this Agreement constitutes acceptance of those changes.
-Operator may also, in the future, offer new services and/or features
-through the Website (including, the release of new tools and
+of Operator or Operator’s licensors. Other trademarks, service marks,
+graphics and logos used in connection with the Website may be the
+trademarks of other third parties. Your use of the Website grants you
+no right or license to reproduce or otherwise use any Operator or
+third-party trademarks.
+
+
Changes. Operator reserves the right, at its sole
+discretion, to modify or replace any part of this Agreement. It is
+your responsibility to check this Agreement periodically for changes.
+Your continued use of or access to the Website following the posting
+of any changes to this Agreement constitutes acceptance of those
+changes. Operator may also, in the future, offer new services and/or
+features through the Website (including, the release of new tools and
resources). Such new features and/or services shall be subject to the
terms and conditions of this Agreement.
-
Termination. Operator may terminate your access to all or any
-part of the Website at any time, with or without cause, with or
-without notice, effective immediately. If you wish to terminate this
-Agreement or your %%site.name%% account (if you have one), you may
-simply discontinue using the Website. Notwithstanding the foregoing,
-if you have a VIP Services account, such account can only be
-terminated by Operator if you materially breach this Agreement and
-fail to cure such breach within thirty (30) days from Operator’s
-notice to you thereof; provided that, Operator can terminate the
-Website immediately as part of a general shut down of our service. All
-provisions of this Agreement which by their nature should survive
-termination shall survive termination, including, without limitation,
-ownership provisions, warranty disclaimers, indemnity and limitations
-of liability.
-
-
Disclaimer of Warranties. The Website is provided “as is”.
-Operator and its suppliers and licensors hereby disclaim all
+
Termination. Operator may terminate your access
+to all or any part of the Website at any time, with or without cause,
+with or without notice, effective immediately. If you wish to
+terminate this Agreement or your %%site.name%% account (if you have
+one), you may simply discontinue using the Website. All provisions of
+this Agreement which by their nature should survive termination shall
+survive termination, including, without limitation, ownership
+provisions, warranty disclaimers, indemnity and limitations of
+liability.
+
+
Disclaimer of Warranties. The Website is provided
+“as is”. Operator and its suppliers and licensors hereby disclaim all
warranties of any kind, express or implied, including, without
limitation, the warranties of merchantability, fitness for a
particular purpose and non-infringement. Neither Operator nor its
@@ -271,58 +241,43 @@ If you’re actually reading this, here’s a treat. You understand that
you download from, or otherwise obtain content or services through,
the Website at your own discretion and risk.
-
Limitation of Liability. In no event will Operator, or its
-suppliers or licensors, be liable with respect to any subject matter
-of this agreement under any contract, negligence, strict liability or
-other legal or equitable theory for: (i) any special, incidental or
-consequential damages; (ii) the cost of procurement or substitute
-products or services; (iii) for interruption of use or loss or
-corruption of data; or (iv) for any amounts that exceed the fees paid
-by you to Operator under this agreement during the twelve (12) month
-period prior to the cause of action. Operator shall have no
-liability for any failure or delay due to matters beyond their
-reasonable control. The foregoing shall not apply to the extent
+
Limitation of Liability. In no event will
+Operator, or its suppliers or licensors, be liable with respect to any
+subject matter of this agreement under any contract, negligence,
+strict liability or other legal or equitable theory for: (i) any
+special, incidental or consequential damages; (ii) the cost of
+procurement or substitute products or services; (iii) for interruption
+of use or loss or corruption of data; or (iv) for any amounts that
+exceed the fees paid by you to Operator under this agreement during
+the twelve (12) month period prior to the cause of action. Operator
+shall have no liability for any failure or delay due to matters beyond
+their reasonable control. The foregoing shall not apply to the extent
prohibited by applicable law.
-
General Representation and Warranty. You represent and warrant
-that (i) your use of the Website will be in strict accordance with the
-Operator Privacy Policy, with this Agreement and with all applicable
-laws and regulations (including without limitation any local laws or
-regulations in your country, state, city, or other governmental area,
-regarding online conduct and acceptable content, and including all
-applicable laws regarding the transmission of technical data exported
-from the United States or the country in which you reside) and (ii)
-your use of the Website will not infringe or misappropriate the
-intellectual property rights of any third party.
-
-
Indemnification. You agree to indemnify and hold harmless
-Operator, its contractors, and its licensors, and their respective
-directors, officers, employees and agents from and against any and all
-claims and expenses, including attorneys’ fees, arising out of your
-use of the Website, including but not limited to out of your violation
-this Agreement.
-
-
Miscellaneous. This Agreement constitutes the entire agreement
-between Operator and you concerning the subject matter hereof, and
-they may only be modified by a written amendment signed by an
-authorized executive of Operator, or by the posting by Operator of
-a revised version. Except to the extent applicable law, if any,
-provides otherwise, this Agreement, any access to or use of the
-Website will be governed by the laws of the state of California,
-U.S.A., excluding its conflict of law provisions, and the proper venue
-for any disputes arising out of or relating to any of the same will be
-the state and federal courts located in San Francisco County,
-California. Except for claims for injunctive or equitable relief or
-claims regarding intellectual property rights (which may be brought in
-any competent court without the posting of a bond), any dispute
-arising under this Agreement shall be finally settled in accordance
-with the Comprehensive Arbitration Rules of the Judicial Arbitration
-and Mediation Service, Inc. (“JAMS”) by three arbitrators appointed in
-accordance with such Rules. The arbitration shall take place in San
-Francisco, California, in the English language and the arbitral
-decision may be enforced in any court. The prevailing party in any
-action or proceeding to enforce this Agreement shall be entitled to
-costs and attorneys’ fees. If any part of this Agreement is held
+
General Representation and Warranty. You
+represent and warrant that (i) your use of the Website will be in
+strict accordance with the Operator Privacy Policy, with this
+Agreement and with all applicable laws and regulations (including
+without limitation any local laws or regulations in your country,
+state, city, or other governmental area, regarding online conduct and
+acceptable content, and including all applicable laws regarding the
+transmission of technical data exported from the United States or the
+country in which you reside) and (ii) your use of the Website will not
+infringe or misappropriate the intellectual property rights of any
+third party.
+
+
Indemnification. You agree to indemnify and hold
+harmless Operator, its contractors, and its licensors, and their
+respective directors, officers, employees and agents from and against
+any and all claims and expenses, including attorneys’ fees, arising
+out of your use of the Website, including but not limited to out of
+your violation this Agreement.
+
+
Miscellaneous. This Agreement constitutes the
+entire agreement between Operator and you concerning the subject
+matter hereof, and they may only be modified by a written amendment
+signed by an authorized executive of Operator, or by the posting by
+Operator of a revised version. If any part of this Agreement is held
invalid or unenforceable, that part will be construed to reflect the
parties’ original intent, and the remaining portions will remain in
full force and effect. A waiver by either party of any term or
@@ -333,10 +288,13 @@ party that consents to, and agrees to be bound by, its terms and
conditions; Operator may assign its rights under this Agreement
without condition. This Agreement will be binding upon and will inure
to the benefit of the parties, their successors and permitted
-assigns.
-
+assigns.
*Originally published by Automattic, Inc. as the [WordPress.com Terms
of Service](http://en.wordpress.com/tos/) and made available by them
under the [Creative Commons Attribution-ShareAlike 3.0
-License](http://creativecommons.org/licenses/by-sa/3.0/).*
\ No newline at end of file
+License](http://creativecommons.org/licenses/by-sa/3.0/).
+Modifications to remove reference to "VIP services", rename "blog" to
+"notice stream", remove the choice-of-venue clause, and add variables
+specific to instances of this software made by Control Yourself, Inc.
+and made available under the terms of the same license.*
\ No newline at end of file
--
cgit v1.2.3-54-g00ecf
From de0335fbe946d94a47247d8118b1f57f0f4843aa Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 20 Jun 2009 22:36:56 -0700
Subject: add TOS to footer menu if brought-by available
---
lib/action.php | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lib/action.php b/lib/action.php
index 89a8c8f4d..77a8ee391 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -247,7 +247,6 @@ class Action extends HTMLOutputter // lawsuit
'src' => common_path('js/jquery.joverlay.min.js')),
' ');
-
Event::handle('EndShowJQueryScripts', array($this));
}
if (Event::handle('StartShowLaconicaScripts', array($this))) {
@@ -704,6 +703,11 @@ class Action extends HTMLOutputter // lawsuit
_('About'));
$this->menuItem(common_local_url('doc', array('title' => 'faq')),
_('FAQ'));
+ $bb = common_config('site', 'broughtby');
+ if (!empty($bb)) {
+ $this->menuItem(common_local_url('doc', array('title' => 'tos')),
+ _('TOS'));
+ }
$this->menuItem(common_local_url('doc', array('title' => 'privacy')),
_('Privacy'));
$this->menuItem(common_local_url('doc', array('title' => 'source')),
--
cgit v1.2.3-54-g00ecf
From 56496a2cb56263fed1eb53313057686f9fd55b63 Mon Sep 17 00:00:00 2001
From: Brenda Wallace
Date: Wed, 24 Jun 2009 21:31:10 +1200
Subject: add missing group by item, to make database that aren't mysql happy
---
lib/popularnoticesection.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php
index 375d5538b..e47c9b385 100644
--- a/lib/popularnoticesection.php
+++ b/lib/popularnoticesection.php
@@ -68,7 +68,7 @@ class PopularNoticeSection extends NoticeSection
}
$qry .= ' GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' .
'notice.rendered,notice.url,notice.created,notice.modified,' .
- 'notice.reply_to,notice.is_local,notice.source ' .
+ 'notice.reply_to,notice.is_local,notice.source,notice.conversation ' .
'ORDER BY weight DESC';
$offset = 0;
--
cgit v1.2.3-54-g00ecf
From 72df5c9eb4941eb0770758862e065940e05f2abc Mon Sep 17 00:00:00 2001
From: Brenda Wallace
Date: Thu, 25 Jun 2009 21:59:33 +1200
Subject: removed semicolons from comments (mucks up logic in install.php) and
fixed stray commas that stopped it parsing as valid SQL
---
db/laconica_pg.sql | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql
index b213bbd50..622242bdf 100644
--- a/db/laconica_pg.sql
+++ b/db/laconica_pg.sql
@@ -118,6 +118,7 @@ create table notice (
is_local integer default 0 /* comment 'notice was generated by a user' */,
source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
+
/* FULLTEXT(content) */
);
create index notice_profile_id_idx on notice using btree(profile_id);
@@ -172,7 +173,7 @@ create table token (
tok char(32) not null /* comment 'identifying value' */,
secret char(32) not null /* comment 'secret value' */,
type integer not null default 0 /* comment 'request or access' */,
- state integer default 0 /* comment 'for requests; 0 = initial, 1 = authorized, 2 = used' */,
+ state integer default 0 /* comment 'for requests 0 = initial, 1 = authorized, 2 = used' */,
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
modified timestamp /* comment 'date this record was modified' */,
@@ -346,7 +347,7 @@ create table notice_inbox (
user_id integer not null /* comment 'user receiving the message' */ references "user" (id),
notice_id integer not null /* comment 'notice received' */ references notice (id),
created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
- source integer default 1 /* comment 'reason it is in the inbox; 1=subscription' */,
+ source integer default 1 /* comment 'reason it is in the inbox: 1=subscription' */,
primary key (user_id, notice_id)
);
@@ -436,8 +437,8 @@ create table file (
mimetype varchar(50),
size integer,
title varchar(255),
- date integer(11),
- protected integer(1)
+ date integer,
+ protected integer
);
create sequence file_oembed_seq;
@@ -454,7 +455,7 @@ create table file_oembed (
title varchar(255),
author_name varchar(50),
author_url varchar(255),
- url varchar(255),
+ url varchar(255)
);
create sequence file_redirection_seq;
--
cgit v1.2.3-54-g00ecf
From 2456baa3bce590e516c27c97344ae83edc5f0b66 Mon Sep 17 00:00:00 2001
From: Brenda Wallace
Date: Thu, 25 Jun 2009 22:00:55 +1200
Subject: added missing conversation id to notices
---
db/laconica_pg.sql | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql
index 622242bdf..f8362ae93 100644
--- a/db/laconica_pg.sql
+++ b/db/laconica_pg.sql
@@ -116,7 +116,8 @@ create table notice (
modified timestamp /* comment 'date this record was modified' */,
reply_to integer /* comment 'notice replied to (usually a guess)' */ references notice (id) ,
is_local integer default 0 /* comment 'notice was generated by a user' */,
- source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
+ source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */,
+ conversation integer /*id of root notice in this conversation' */ references notice (id)
/* FULLTEXT(content) */
--
cgit v1.2.3-54-g00ecf
From a38245d4d184903ab4df6ee81396fd3ab8ae7bf5 Mon Sep 17 00:00:00 2001
From: Brenda Wallace
Date: Thu, 25 Jun 2009 22:01:14 +1200
Subject: added missing table "design"
---
db/laconica_pg.sql | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/db/laconica_pg.sql b/db/laconica_pg.sql
index f8362ae93..dae8b8faf 100644
--- a/db/laconica_pg.sql
+++ b/db/laconica_pg.sql
@@ -486,6 +486,18 @@ create table file_to_post (
unique(file_id, post_id)
);
+create sequence design_seq;
+create table design (
+ id bigint default nextval('design_seq') /* comment 'design ID'*/,
+ backgroundcolor integer /* comment 'main background color'*/ ,
+ contentcolor integer /*comment 'content area background color'*/ ,
+ sidebarcolor integer /*comment 'sidebar background color'*/ ,
+ textcolor integer /*comment 'text color'*/ ,
+ linkcolor integer /*comment 'link color'*/,
+ backgroundimage varchar(255) /*comment 'background image, if any'*/,
+ disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
+ primary key (id)
+);
/* Textsearch stuff */
--
cgit v1.2.3-54-g00ecf
From bd9824c8d563bbd2d9f9ed259341f0e2fc1ffdf1 Mon Sep 17 00:00:00 2001
From: Brenda Wallace
Date: Thu, 25 Jun 2009 22:35:41 +1200
Subject: added missing conversation column to group by
---
actions/favorited.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/actions/favorited.php b/actions/favorited.php
index c902d80f5..156c7a700 100644
--- a/actions/favorited.php
+++ b/actions/favorited.php
@@ -194,7 +194,7 @@ class FavoritedAction extends Action
$qry = 'SELECT notice.*, '.
$weightexpr . ' as weight ' .
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
- 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source ' .
+ 'GROUP BY id,profile_id,uri,content,rendered,url,created,notice.modified,reply_to,is_local,source,notice.conversation ' .
'ORDER BY weight DESC';
$offset = ($this->page - 1) * NOTICES_PER_PAGE;
--
cgit v1.2.3-54-g00ecf
From e5b758dbbef6774943abf453a43114a2c3371b4a Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sun, 28 Jun 2009 14:38:31 -0400
Subject: start of queuemanager code
---
lib/dbqueuemanager.php | 106 ++++++++++++++++++++++++++++++++++++++++
lib/queuemanager.php | 78 +++++++++++++++++++++++++++++
lib/stompqueuemanager.php | 122 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 306 insertions(+)
create mode 100644 lib/dbqueuemanager.php
create mode 100644 lib/queuemanager.php
create mode 100644 lib/stompqueuemanager.php
diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php
new file mode 100644
index 000000000..c0d4dcd29
--- /dev/null
+++ b/lib/dbqueuemanager.php
@@ -0,0 +1,106 @@
+.
+ *
+ * @category QueueManager
+ * @package Laconica
+ * @author Evan Prodromou
+ * @author Sarven Capadisli
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+class DBQueueManager extends QueueManager
+{
+ var $qis = array();
+
+ function enqueue($object, $queue)
+ {
+ $notice = (Notice)$object;
+
+ $qi = new Queue_item();
+
+ $qi->notice_id = $notice->id;
+ $qi->transport = $queue;
+ $qi->created = $notice->created;
+ $result = $qi->insert();
+
+ if (!$result) {
+ common_log_db_error($qi, 'INSERT', __FILE__);
+ throw new ServerException('DB error inserting queue item');
+ }
+
+ return true;
+ }
+
+ function nextItem($queue, $timeout=null)
+ {
+ $start = time();
+ $result = null;
+
+ do {
+ $qi = Queue_item::top($queue);
+ if (!empty($qi)) {
+ $notice = Notice::staticGet('id', $qi->notice_id);
+ if (!empty($notice)) {
+ $result = $notice;
+ } else {
+ $this->_log(LOG_INFO, 'dequeued non-existent notice ' . $notice->id);
+ $qi->delete();
+ $qi->free();
+ $qi = null;
+ }
+ }
+ } while (empty($result) && (is_null($timeout) || (time() - $start) < $timeout));
+
+ return $result;
+ }
+
+ function done($object, $queue)
+ {
+ $notice = (Notice)$object;
+
+ $qi = Queue_item::pkeyGet(array('notice_id' => $notice->id,
+ 'transport' => $queue));
+
+ if (empty($qi)) {
+ $this->log(LOG_INFO, 'Cannot find queue item for notice '.$notice->id.', queue '.$queue);
+ } else {
+ if (empty($qi->claimed)) {
+ $this->log(LOG_WARNING, 'Reluctantly releasing unclaimed queue item '.
+ 'for '.$notice->id.', queue '.$queue);
+ }
+ $qi->delete();
+ $qi->free();
+ $qi = null;
+ }
+
+ $this->log(LOG_INFO, 'done with notice ID = ' . $notice->id);
+
+ $notice->free();
+ $notice = null;
+ }
+
+ function _log($level, $msg)
+ {
+ common_log($level, 'DBQueueManager: '.$msg);
+ }
+}
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
new file mode 100644
index 000000000..64aca1bc1
--- /dev/null
+++ b/lib/queuemanager.php
@@ -0,0 +1,78 @@
+.
+ *
+ * @category QueueManager
+ * @package Laconica
+ * @author Evan Prodromou
+ * @author Sarven Capadisli
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+class QueueManager
+{
+ static $qm = null;
+
+ static function get()
+ {
+ if (empty(self::$qm)) {
+
+ if (Event::handle('StartNewQueueManager', self::$qm)) {
+
+ $type = common_config('queue', 'sub');
+
+ switch ($type) {
+ case 'db':
+ self::$qm = new DBQueueManager();
+ break;
+ case 'stomp':
+ self::$qm = new StompQueueManager();
+ break;
+ default:
+ throw new ServerException("No queue manager class for type '$type'");
+ }
+ }
+
+ return self::$qm;
+ }
+ }
+
+ function enqueue($object, $queue)
+ {
+ throw ServerException("Unimplemented function 'enqueue' called");
+ }
+
+ function peek($queue)
+ {
+ throw ServerException("Unimplemented function 'peek' called");
+ }
+
+ function nextItem($queue, $timeout=null)
+ {
+ throw ServerException("Unimplemented function 'nextItem' called");
+ }
+
+ function done($object, $queue)
+ {
+ throw ServerException("Unimplemented function 'done' called");
+ }
+}
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
new file mode 100644
index 000000000..20c6e7a34
--- /dev/null
+++ b/lib/stompqueuemanager.php
@@ -0,0 +1,122 @@
+.
+ *
+ * @category QueueManager
+ * @package Laconica
+ * @author Evan Prodromou
+ * @author Sarven Capadisli
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+require_once 'Stomp.php';
+
+class QueueManager
+{
+ var $server = null;
+ var $username = null;
+ var $password = null;
+ var $base = null;
+ var $con = null;
+ var $frames = array();
+
+ function __construct()
+ {
+ $this->server = common_config('queue', 'stomp_server');
+ $this->username = common_config('queue', 'stomp_username');
+ $this->password = common_config('queue', 'stomp_password');
+ $this->base = common_config('queue', 'queue_basename');
+ }
+
+ function _connect()
+ {
+ if (empty($this->con)) {
+ $this->con = new Stomp($this->server);
+
+ if (!$this->con->connect($this->username, $this->password)) {
+ $this->_log(LOG_ERR, 'Failed to connect to queue server');
+ throw new ServerException('Failed to connect to queue server');
+ }
+ }
+ }
+
+ function enqueue($object, $queue)
+ {
+ $notice = (Notice)$object;
+
+ $this->_connect();
+
+ $result = $this->con->send($this->_queueName($queue),
+ $notice->id, // BODY of the message
+ array ('created' => $notice->created));
+
+ if (!$result) {
+ common_log(LOG_ERR, 'Error sending to '.$transport.' queue');
+ return false;
+ }
+
+ common_log(LOG_DEBUG, 'complete remote queueing notice ID = '
+ . $notice->id . ' for ' . $transport);
+ }
+
+ function nextItem($queue, $timeout=null)
+ {
+ $result = null;
+
+ $this->_connect();
+
+ $frame = $this->con->readFrame();
+
+ if ($frame) {
+ $this->log(LOG_INFO, 'Got item enqueued '.common_exact_date($frame->headers['created']));
+
+ // XXX: Now the queue handler receives only the ID of the
+ // notice, and it has to get it from the DB
+ // A massive improvement would be avoid DB query by transmitting
+ // all the notice details via queue server...
+ $notice = Notice::staticGet($frame->body);
+
+ if ($notice) {
+ } else {
+ $this->log(LOG_WARNING, 'queue item for notice that does not exist');
+ }
+ }
+ }
+
+ function done($object, $queue)
+ {
+ $notice = (Notice)$object;
+
+ $this->_connect();
+
+ $frame = $this->_getFrame($notice, $queue);
+
+ if (empty($frame)) {
+ $this->log(LOG_ERR, 'Cannot find frame for notice '.$notice->id.' in queue '.$queue);
+ } else {
+ // if the msg has been handled positively, ack it
+ // and the queue server will remove it from the queue
+ $this->con->ack($frame);
+ $this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
+ }
+ }
+}
--
cgit v1.2.3-54-g00ecf
From 854c82cfd53cb071afa39259fb467b4730bd6494 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sun, 28 Jun 2009 14:38:34 -0400
Subject: start of queuemanager code
---
classes/Queue_item.php | 11 ++++++--
lib/util.php | 75 --------------------------------------------------
2 files changed, 8 insertions(+), 78 deletions(-)
diff --git a/classes/Queue_item.php b/classes/Queue_item.php
index 9b909ec22..295c321b5 100644
--- a/classes/Queue_item.php
+++ b/classes/Queue_item.php
@@ -4,7 +4,7 @@
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
-class Queue_item extends Memcached_DataObject
+class Queue_item extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
@@ -13,7 +13,7 @@ class Queue_item extends Memcached_DataObject
public $notice_id; // int(4) primary_key not_null
public $transport; // varchar(8) primary_key not_null
public $created; // datetime() not_null
- public $claimed; // datetime()
+ public $claimed; // datetime()
/* Static get */
function staticGet($k,$v=null)
@@ -24,7 +24,7 @@ class Queue_item extends Memcached_DataObject
function sequenceKey()
{ return array(false, false); }
-
+
static function top($transport) {
$qi = new Queue_item();
@@ -54,4 +54,9 @@ class Queue_item extends Memcached_DataObject
$qi = null;
return null;
}
+
+ function &pkeyGet($kv)
+ {
+ return Memcached_DataObject::pkeyGet('Queue_item', $kv);
+ }
}
diff --git a/lib/util.php b/lib/util.php
index 9c1af7a0d..3f924c8de 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -889,69 +889,6 @@ function common_enqueue_notice($notice)
return $result;
}
-function common_enqueue_notice_stomp($notice, $transports)
-{
- // use an external message queue system via STOMP
- require_once("Stomp.php");
-
- $server = common_config('queue','stomp_server');
- $username = common_config('queue', 'stomp_username');
- $password = common_config('queue', 'stomp_password');
-
- $con = new Stomp($server);
-
- if (!$con->connect($username, $password)) {
- common_log(LOG_ERR, 'Failed to connect to queue server');
- return false;
- }
-
- $queue_basename = common_config('queue','queue_basename');
-
- foreach ($transports as $transport) {
- $result = $con->send('/queue/'.$queue_basename.'-'.$transport, // QUEUE
- $notice->id, // BODY of the message
- array ('created' => $notice->created));
- if (!$result) {
- common_log(LOG_ERR, 'Error sending to '.$transport.' queue');
- return false;
- }
- common_log(LOG_DEBUG, 'complete remote queueing notice ID = ' . $notice->id . ' for ' . $transport);
- }
-
- //send tags as headers, so they can be used as JMS selectors
- common_log(LOG_DEBUG, 'searching for tags ' . $notice->id);
- $tags = array();
- $tag = new Notice_tag();
- $tag->notice_id = $notice->id;
- if ($tag->find()) {
- while ($tag->fetch()) {
- common_log(LOG_DEBUG, 'tag found = ' . $tag->tag);
- array_push($tags,$tag->tag);
- }
- }
- $tag->free();
-
- $con->send('/topic/laconica.'.$notice->profile_id,
- $notice->content,
- array(
- 'profile_id' => $notice->profile_id,
- 'created' => $notice->created,
- 'tags' => implode($tags,' - ')
- )
- );
- common_log(LOG_DEBUG, 'sent to personal topic ' . $notice->id);
- $con->send('/topic/laconica.allusers',
- $notice->content,
- array(
- 'profile_id' => $notice->profile_id,
- 'created' => $notice->created,
- 'tags' => implode($tags,' - ')
- )
- );
- common_log(LOG_DEBUG, 'sent to catch-all topic ' . $notice->id);
- $result = true;
-}
-
function common_enqueue_notice_db($notice, $transports)
{
// in any other case, 'internal'
@@ -962,18 +899,6 @@ function common_enqueue_notice_db($notice, $transports)
function common_enqueue_notice_transport($notice, $transport)
{
- $qi = new Queue_item();
- $qi->notice_id = $notice->id;
- $qi->transport = $transport;
- $qi->created = $notice->created;
- $result = $qi->insert();
- if (!$result) {
- $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError');
- common_log(LOG_ERR, 'DB error inserting queue item: ' . $last_error->message);
- throw new ServerException('DB error inserting queue item: ' . $last_error->message);
- }
- common_log(LOG_DEBUG, 'complete queueing notice ID = ' . $notice->id . ' for ' . $transport);
- return true;
}
function common_real_broadcast($notice, $remote=false)
--
cgit v1.2.3-54-g00ecf
From 58b427869a001a91d66cff497f1563b8277f1a67 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 11:09:42 -0400
Subject: compile errors in DBQueueManager
---
lib/dbqueuemanager.php | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php
index c0d4dcd29..46be54b30 100644
--- a/lib/dbqueuemanager.php
+++ b/lib/dbqueuemanager.php
@@ -34,7 +34,7 @@ class DBQueueManager extends QueueManager
function enqueue($object, $queue)
{
- $notice = (Notice)$object;
+ $notice = $object;
$qi = new Queue_item();
@@ -76,7 +76,9 @@ class DBQueueManager extends QueueManager
function done($object, $queue)
{
- $notice = (Notice)$object;
+ // XXX: right now, we only handle notices
+
+ $notice = $object;
$qi = Queue_item::pkeyGet(array('notice_id' => $notice->id,
'transport' => $queue));
--
cgit v1.2.3-54-g00ecf
From 4c256a6d7ee287def5c26f401c8caa6bfe0b8dff Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 11:09:58 -0400
Subject: better hook variables for StartQueueManager
---
lib/queuemanager.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
index 64aca1bc1..92f0e10de 100644
--- a/lib/queuemanager.php
+++ b/lib/queuemanager.php
@@ -36,9 +36,9 @@ class QueueManager
{
if (empty(self::$qm)) {
- if (Event::handle('StartNewQueueManager', self::$qm)) {
+ $type = common_config('queue', 'sub');
- $type = common_config('queue', 'sub');
+ if (Event::handle('StartNewQueueManager', array($type, &self::$qm))) {
switch ($type) {
case 'db':
--
cgit v1.2.3-54-g00ecf
From 7b66a129139d8c2f03677f6a5b71412a111f655d Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 11:10:23 -0400
Subject: save frames for StompQueueManager
---
lib/stompqueuemanager.php | 36 +++++++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 20c6e7a34..1b4a26f2e 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -30,7 +30,7 @@
require_once 'Stomp.php';
-class QueueManager
+class StompQueueManager
{
var $server = null;
var $username = null;
@@ -61,10 +61,12 @@ class QueueManager
function enqueue($object, $queue)
{
- $notice = (Notice)$object;
+ $notice = $object;
$this->_connect();
+ // XXX: serialize and send entire notice
+
$result = $this->con->send($this->_queueName($queue),
$notice->id, // BODY of the message
array ('created' => $notice->created));
@@ -93,9 +95,11 @@ class QueueManager
// notice, and it has to get it from the DB
// A massive improvement would be avoid DB query by transmitting
// all the notice details via queue server...
+
$notice = Notice::staticGet($frame->body);
if ($notice) {
+ $this->_saveFrame($notice, $queue, $frame);
} else {
$this->log(LOG_WARNING, 'queue item for notice that does not exist');
}
@@ -104,7 +108,7 @@ class QueueManager
function done($object, $queue)
{
- $notice = (Notice)$object;
+ $notice = $object;
$this->_connect();
@@ -116,7 +120,33 @@ class QueueManager
// if the msg has been handled positively, ack it
// and the queue server will remove it from the queue
$this->con->ack($frame);
+ $this->_clearFrame($notice, $queue);
+
$this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
}
}
+
+ function _frameKey($notice, $queue)
+ {
+ return ((string)$notice->id) . '-' . $queue;
+ }
+
+ function _saveFrame($notice, $queue, $frame)
+ {
+ $k = $this->_frameKey($notice, $queue);
+ $this->_frames[$k] = $frame;
+ return true;
+ }
+
+ function _getFrame($notice, $queue)
+ {
+ $k = $this->_frameKey($notice, $queue);
+ return $this->_frames[$k];
+ }
+
+ function _clearFrame($notice, $queue)
+ {
+ $k = $this->_frameKey($notice, $queue);
+ unset($this->_frames[$k]);
+ }
}
--
cgit v1.2.3-54-g00ecf
From e0bf8ad95b2d2ddc7b988c25e9cffa20075a5d8c Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 11:34:12 -0400
Subject: Add UnQueueManager for immediate handling
Perhaps it's a little precious, but I took out the switches in
util.php to determine what's supposed to be sent when, and made
a queuemanager class that will just do things when they're supposed to
be done.
---
lib/queuemanager.php | 10 ++++--
lib/unqueuemanager.php | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++
lib/util.php | 85 ++++++++++----------------------------------------
3 files changed, 109 insertions(+), 71 deletions(-)
create mode 100644 lib/unqueuemanager.php
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
index 92f0e10de..6bb21de9b 100644
--- a/lib/queuemanager.php
+++ b/lib/queuemanager.php
@@ -36,9 +36,15 @@ class QueueManager
{
if (empty(self::$qm)) {
- $type = common_config('queue', 'sub');
+ if (Event::handle('StartNewQueueManager', array(&self::$qm))) {
- if (Event::handle('StartNewQueueManager', array($type, &self::$qm))) {
+ $enabled = common_config('queue', 'enabled');
+ $type = common_config('queue', 'sub');
+
+ if (!$enabled) {
+ // does everything immediately
+ return new UnQueueManager();
+ }
switch ($type) {
case 'db':
diff --git a/lib/unqueuemanager.php b/lib/unqueuemanager.php
new file mode 100644
index 000000000..515461072
--- /dev/null
+++ b/lib/unqueuemanager.php
@@ -0,0 +1,85 @@
+.
+ *
+ * @category QueueManager
+ * @package Laconica
+ * @author Evan Prodromou
+ * @author Sarven Capadisli
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+class UnQueueManager
+{
+ function enqueue($object, $queue)
+ {
+ $notice = $object;
+
+ switch ($queue)
+ {
+ case 'omb':
+ if ($this->_isLocal($notice)) {
+ require_once(INSTALLDIR.'/lib/omb.php');
+ omb_broadcast_remote_subscribers($notice);
+ }
+ break;
+ case 'public':
+ if ($this->_isLocal($notice)) {
+ require_once(INSTALLDIR.'/lib/jabber.php');
+ jabber_public_notice($notice);
+ }
+ break;
+ case 'twitter':
+ if ($this->_isLocal($notice)) {
+ broadcast_twitter($notice);
+ }
+ break;
+ case 'facebook':
+ if ($this->_isLocal($notice)) {
+ require_once INSTALLDIR . '/lib/facebookutil.php';
+ return facebookBroadcastNotice($notice);
+ }
+ break;
+ case 'ping':
+ if ($this->_isLocal($notice)) {
+ require_once INSTALLDIR . '/lib/ping.php';
+ return ping_broadcast_notice($notice);
+ }
+ case 'sms':
+ require_once(INSTALLDIR.'/lib/mail.php');
+ mail_broadcast_notice_sms($notice);
+ break;
+ case 'jabber':
+ require_once(INSTALLDIR.'/lib/jabber.php');
+ jabber_broadcast_notice($notice);
+ break;
+ default:
+ throw ServerException("UnQueueManager: Unknown queue: $type");
+ }
+ }
+
+ function _isLocal($notice)
+ {
+ return ($notice->is_local == NOTICE_LOCAL_PUBLIC ||
+ $notice->is_local == NOTICE_LOCAL_NONPUBLIC);
+ }
+}
\ No newline at end of file
diff --git a/lib/util.php b/lib/util.php
index 3f924c8de..b1b4faa7e 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -861,88 +861,35 @@ function common_redirect($url, $code=307)
function common_broadcast_notice($notice, $remote=false)
{
- if (common_config('queue', 'enabled')) {
- // Do it later!
- return common_enqueue_notice($notice);
- } else {
- return common_real_broadcast($notice, $remote);
- }
+ return common_enqueue_notice($notice);
}
// Stick the notice on the queue
function common_enqueue_notice($notice)
{
- $transports = array('omb', 'sms', 'public', 'twitter', 'facebook', 'ping');
+ static $localTransports = array('omb',
+ 'public',
+ 'twitter',
+ 'facebook',
+ 'ping');
+ static $allTransports = array('sms', 'jabber');
- if (common_config('xmpp', 'enabled'))
- {
- $transports[] = 'jabber';
- }
+ $transports = $allTransports;
- if (common_config('queue','subsystem') == 'stomp') {
- common_enqueue_notice_stomp($notice, $transports);
+ if ($notice->is_local == NOTICE_LOCAL_PUBLIC ||
+ $notice->is_local == NOTICE_LOCAL_NONPUBLIC) {
+ $transports = array_merge($transports, $localTransports);
}
- else {
- common_enqueue_notice_db($notice, $transports);
- }
- return $result;
-}
-function common_enqueue_notice_db($notice, $transports)
-{
- // in any other case, 'internal'
- foreach ($transports as $transport) {
- common_enqueue_notice_transport($notice, $transport);
- }
-}
-
-function common_enqueue_notice_transport($notice, $transport)
-{
-}
+ $qm = QueueManager::get();
-function common_real_broadcast($notice, $remote=false)
-{
- $success = true;
- if (!$remote) {
- // Make sure we have the OMB stuff
- require_once(INSTALLDIR.'/lib/omb.php');
- $success = omb_broadcast_remote_subscribers($notice);
- if (!$success) {
- common_log(LOG_ERR, 'Error in OMB broadcast for notice ' . $notice->id);
- }
- }
- if ($success) {
- require_once(INSTALLDIR.'/lib/jabber.php');
- $success = jabber_broadcast_notice($notice);
- if (!$success) {
- common_log(LOG_ERR, 'Error in jabber broadcast for notice ' . $notice->id);
- }
- }
- if ($success) {
- require_once(INSTALLDIR.'/lib/mail.php');
- $success = mail_broadcast_notice_sms($notice);
- if (!$success) {
- common_log(LOG_ERR, 'Error in sms broadcast for notice ' . $notice->id);
- }
- }
- if ($success) {
- $success = jabber_public_notice($notice);
- if (!$success) {
- common_log(LOG_ERR, 'Error in public broadcast for notice ' . $notice->id);
- }
- }
- if ($success) {
- $success = broadcast_twitter($notice);
- if (!$success) {
- common_log(LOG_ERR, 'Error in Twitter broadcast for notice ' . $notice->id);
- }
+ foreach ($transports as $transport)
+ {
+ $qm->enqueue($notice, $transport);
}
- // XXX: Do a real-time FB broadcast here?
-
- // XXX: broadcast notices to other IM
- return $success;
+ return true;
}
function common_broadcast_profile($profile)
--
cgit v1.2.3-54-g00ecf
From 887d35cfc8c1d42e5af67d0161b244545cda464a Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 12:09:18 -0400
Subject: better queue manager detection, new method fail()
---
lib/queuemanager.php | 31 ++++++++++++++++++-------------
1 file changed, 18 insertions(+), 13 deletions(-)
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
index 6bb21de9b..1bf4d4dec 100644
--- a/lib/queuemanager.php
+++ b/lib/queuemanager.php
@@ -39,22 +39,22 @@ class QueueManager
if (Event::handle('StartNewQueueManager', array(&self::$qm))) {
$enabled = common_config('queue', 'enabled');
- $type = common_config('queue', 'sub');
+ $type = common_config('queue', 'subsystem');
if (!$enabled) {
// does everything immediately
- return new UnQueueManager();
- }
-
- switch ($type) {
- case 'db':
- self::$qm = new DBQueueManager();
- break;
- case 'stomp':
- self::$qm = new StompQueueManager();
- break;
- default:
- throw new ServerException("No queue manager class for type '$type'");
+ self::$qm = new UnQueueManager();
+ } else {
+ switch ($type) {
+ case 'db':
+ self::$qm = new DBQueueManager();
+ break;
+ case 'stomp':
+ self::$qm = new StompQueueManager();
+ break;
+ default:
+ throw new ServerException("No queue manager class for type '$type'");
+ }
}
}
@@ -81,4 +81,9 @@ class QueueManager
{
throw ServerException("Unimplemented function 'done' called");
}
+
+ function fail($object, $queue)
+ {
+ throw ServerException("Unimplemented function 'fail' called");
+ }
}
--
cgit v1.2.3-54-g00ecf
From 557418bc1e4e9d8a06025910ad7be5f60557f71e Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 12:09:41 -0400
Subject: better transport choices when xmpp is disabled
---
lib/util.php | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/lib/util.php b/lib/util.php
index b1b4faa7e..656374516 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -869,17 +869,25 @@ function common_broadcast_notice($notice, $remote=false)
function common_enqueue_notice($notice)
{
static $localTransports = array('omb',
- 'public',
'twitter',
'facebook',
'ping');
- static $allTransports = array('sms', 'jabber');
+ static $allTransports = array('sms');
$transports = $allTransports;
+ $xmpp = common_config('xmpp', 'enabled');
+
+ if ($xmpp) {
+ $transports[] = 'jabber';
+ }
+
if ($notice->is_local == NOTICE_LOCAL_PUBLIC ||
$notice->is_local == NOTICE_LOCAL_NONPUBLIC) {
$transports = array_merge($transports, $localTransports);
+ if ($xmpp) {
+ $transports[] = 'public';
+ }
}
$qm = QueueManager::get();
--
cgit v1.2.3-54-g00ecf
From 2325d934a8abfc611f455d4f0b816e2dd62c5ec4 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 12:10:11 -0400
Subject: add fail() method to stompqueuemanager
---
lib/stompqueuemanager.php | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 1b4a26f2e..badcd4abb 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -126,6 +126,17 @@ class StompQueueManager
}
}
+ function fail($object, $queue)
+ {
+ $notice = $object;
+
+ // STOMP server will requeue it after a while anyways,
+ // so no need to notify. Just get it out of our little
+ // array
+
+ $this->_clearFrame($notice, $queue);
+ }
+
function _frameKey($notice, $queue)
{
return ((string)$notice->id) . '-' . $queue;
--
cgit v1.2.3-54-g00ecf
From a35138b2684ec5275a1ffd7badfe7826cf2173b1 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 12:10:25 -0400
Subject: add fail() method to dbqueuemanager and fix logging
---
lib/dbqueuemanager.php | 35 ++++++++++++++++++++++++++++++++---
1 file changed, 32 insertions(+), 3 deletions(-)
diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php
index 46be54b30..c9e5ef243 100644
--- a/lib/dbqueuemanager.php
+++ b/lib/dbqueuemanager.php
@@ -84,10 +84,10 @@ class DBQueueManager extends QueueManager
'transport' => $queue));
if (empty($qi)) {
- $this->log(LOG_INFO, 'Cannot find queue item for notice '.$notice->id.', queue '.$queue);
+ $this->_log(LOG_INFO, 'Cannot find queue item for notice '.$notice->id.', queue '.$queue);
} else {
if (empty($qi->claimed)) {
- $this->log(LOG_WARNING, 'Reluctantly releasing unclaimed queue item '.
+ $this->_log(LOG_WARNING, 'Reluctantly releasing unclaimed queue item '.
'for '.$notice->id.', queue '.$queue);
}
$qi->delete();
@@ -95,7 +95,36 @@ class DBQueueManager extends QueueManager
$qi = null;
}
- $this->log(LOG_INFO, 'done with notice ID = ' . $notice->id);
+ $this->_log(LOG_INFO, 'done with notice ID = ' . $notice->id);
+
+ $notice->free();
+ $notice = null;
+ }
+
+ function fail($object, $queue)
+ {
+ // XXX: right now, we only handle notices
+
+ $notice = $object;
+
+ $qi = Queue_item::pkeyGet(array('notice_id' => $notice->id,
+ 'transport' => $queue));
+
+ if (empty($qi)) {
+ $this->_log(LOG_INFO, 'Cannot find queue item for notice '.$notice->id.', queue '.$queue);
+ } else {
+ if (empty($qi->claimed)) {
+ $this->_log(LOG_WARNING, 'Ignoring failure for unclaimed queue item '.
+ 'for '.$notice->id.', queue '.$queue);
+ } else {
+ $orig = clone($qi);
+ $qi->claimed = null;
+ $qi->update($orig);
+ $qi = null;
+ }
+ }
+
+ $this->_log(LOG_INFO, 'done with notice ID = ' . $notice->id);
$notice->free();
$notice = null;
--
cgit v1.2.3-54-g00ecf
From e52997e52fe02960908eb6a9637a3349a2c74dad Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 1 Jul 2009 12:11:02 -0400
Subject: change queuehandler class to use queuemanager interface
---
lib/queuehandler.php | 151 ++++++++++++++-------------------------------------
1 file changed, 41 insertions(+), 110 deletions(-)
diff --git a/lib/queuehandler.php b/lib/queuehandler.php
index ae403c65e..045432ae5 100644
--- a/lib/queuehandler.php
+++ b/lib/queuehandler.php
@@ -17,17 +17,18 @@
* along with this program. If not, see .
*/
-define('CLAIM_TIMEOUT', 1200);
-
if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/daemon.php');
require_once(INSTALLDIR.'/classes/Queue_item.php');
require_once(INSTALLDIR.'/classes/Notice.php');
+define('CLAIM_TIMEOUT', 1200);
+define('QUEUE_HANDLER_MISS_IDLE', 10);
+define('QUEUE_HANDLER_HIT_IDLE', 10);
+
class QueueHandler extends Daemon
{
-
var $_id = 'generic';
function QueueHandler($id=null)
@@ -37,6 +38,11 @@ class QueueHandler extends Daemon
}
}
+ function timeout()
+ {
+ return null;
+ }
+
function class_name()
{
return ucfirst($this->transport()) . 'Handler';
@@ -75,110 +81,45 @@ class QueueHandler extends Daemon
return true;
}
- function db_dispatch() {
- do {
- $qi = Queue_item::top($this->transport());
- if ($qi) {
- $this->log(LOG_INFO, 'Got item enqueued '.common_exact_date($qi->created));
- $notice = Notice::staticGet($qi->notice_id);
- if ($notice) {
- $this->log(LOG_INFO, 'broadcasting notice ID = ' . $notice->id);
- # XXX: what to do if broadcast fails?
- $result = $this->handle_notice($notice);
- if (!$result) {
- $this->log(LOG_WARNING, 'Failed broadcast for notice ID = ' . $notice->id);
- $orig = $qi;
- $qi->claimed = null;
- $qi->update($orig);
- $this->log(LOG_WARNING, 'Abandoned claim for notice ID = ' . $notice->id);
- continue;
- }
- $this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
- $notice->free();
- unset($notice);
- $notice = null;
- } else {
- $this->log(LOG_WARNING, 'queue item for notice that does not exist');
- }
- $qi->delete();
- $qi->free();
- unset($qi);
- $this->idle(0);
- } else {
- $this->clear_old_claims();
- $this->idle(5);
- }
- } while (true);
- }
-
- function stomp_dispatch() {
-
- // use an external message queue system via STOMP
- require_once("Stomp.php");
+ function run()
+ {
+ if (!$this->start()) {
+ return false;
+ }
- $server = common_config('queue','stomp_server');
- $username = common_config('queue', 'stomp_username');
- $password = common_config('queue', 'stomp_password');
+ $this->log(LOG_INFO, 'checking for queued notices');
- $con = new Stomp($server);
+ $queue = $this->transport();
+ $timeout = $this->timeout();
- if (!$con->connect($username, $password)) {
- $this->log(LOG_ERR, 'Failed to connect to queue server');
- return false;
- }
+ $qm = QueueManager::get();
- $queue_basename = common_config('queue','queue_basename');
- // subscribe to the relevant queue (format: basename-transport)
- $con->subscribe('/queue/'.$queue_basename.'-'.$this->transport());
-
- do {
- $frame = $con->readFrame();
- if ($frame) {
- $this->log(LOG_INFO, 'Got item enqueued '.common_exact_date($frame->headers['created']));
-
- // XXX: Now the queue handler receives only the ID of the
- // notice, and it has to get it from the DB
- // A massive improvement would be avoid DB query by transmitting
- // all the notice details via queue server...
- $notice = Notice::staticGet($frame->body);
-
- if ($notice) {
- $this->log(LOG_INFO, 'broadcasting notice ID = ' . $notice->id);
- $result = $this->handle_notice($notice);
- if ($result) {
- // if the msg has been handled positively, ack it
- // and the queue server will remove it from the queue
- $con->ack($frame);
- $this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
- }
- else {
- // no ack
- $this->log(LOG_WARNING, 'Failed broadcast for notice ID = ' . $notice->id);
- }
- $notice->free();
- unset($notice);
- $notice = null;
+ while (true) {
+ $this->log(LOG_DEBUG, 'Checking for notices...');
+ $notice = $qm->nextItem($queue, $timeout);
+ if (empty($notice)) {
+ $this->log(LOG_DEBUG, 'No notices waiting; idling.');
+ // Nothing in the queue. Do you
+ // have other tasks, like servicing your
+ // XMPP connection, to do?
+ $this->idle(QUEUE_HANDLER_MISS_IDLE);
+ } else {
+ $this->log(LOG_INFO, 'Got notice '. $notice->id);
+ // Yay! Got one!
+ if ($this->handle_notice($notice)) {
+ $this->log(LOG_INFO, 'Successfully handled notice '. $notice->id);
+ $qm->done($notice, $queue);
} else {
- $this->log(LOG_WARNING, 'queue item for notice that does not exist');
+ $this->log(LOG_INFO, 'Failed to handle notice '. $notice->id);
+ $qm->fail($notice, $queue);
}
+ // Chance to e.g. service your XMPP connection
+ $this->log(LOG_DEBUG, 'Idling after success.');
+ $this->idle(QUEUE_HANDLER_HIT_IDLE);
}
- } while (true);
-
- $con->disconnect();
- }
-
- function run()
- {
- if (!$this->start()) {
- return false;
- }
- $this->log(LOG_INFO, 'checking for queued notices');
- if (common_config('queue','subsystem') == 'stomp') {
- $this->stomp_dispatch();
- }
- else {
- $this->db_dispatch();
+ // XXX: when do we give up?
}
+
if (!$this->finish()) {
return false;
}
@@ -187,21 +128,11 @@ class QueueHandler extends Daemon
function idle($timeout=0)
{
- if ($timeout>0) {
+ if ($timeout > 0) {
sleep($timeout);
}
}
- function clear_old_claims()
- {
- $qi = new Queue_item();
- $qi->transport = $this->transport();
- $qi->whereAdd('now() - claimed > '.CLAIM_TIMEOUT);
- $qi->update(DB_DATAOBJECT_WHEREADD_ONLY);
- $qi->free();
- unset($qi);
- }
-
function log($level, $msg)
{
common_log($level, $this->class_name() . ' ('. $this->get_id() .'): '.$msg);
--
cgit v1.2.3-54-g00ecf
From e8f27025ba7869057d86fe37a5264e1c742969f5 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 2 Jul 2009 12:43:09 -0400
Subject: more logging in stompqueuemanager
---
lib/stompqueuemanager.php | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index badcd4abb..08a5790d4 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -49,10 +49,14 @@ class StompQueueManager
function _connect()
{
+ $this->_log(LOG_DEBUG, "Connecting to $this->server...");
if (empty($this->con)) {
+ $this->_log(LOG_INFO, "Connecting to '$this->server' as '$this->username'...");
$this->con = new Stomp($this->server);
- if (!$this->con->connect($this->username, $this->password)) {
+ if ($this->con->connect($this->username, $this->password)) {
+ $this->_log(LOG_INFO, "Connected.");
+ } else {
$this->_log(LOG_ERR, 'Failed to connect to queue server');
throw new ServerException('Failed to connect to queue server');
}
@@ -160,4 +164,9 @@ class StompQueueManager
$k = $this->_frameKey($notice, $queue);
unset($this->_frames[$k]);
}
+
+ function _log($level, $msg)
+ {
+ common_log($level, 'StompQueueManager: '.$msg);
+ }
}
--
cgit v1.2.3-54-g00ecf
From 3e4be98ff6de7a1044f0d7b0deef4f6054e64464 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Fri, 3 Jul 2009 10:05:07 -0400
Subject: add _queueName function
---
lib/stompqueuemanager.php | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 08a5790d4..1ad687036 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -165,6 +165,11 @@ class StompQueueManager
unset($this->_frames[$k]);
}
+ function _queueName($queue)
+ {
+ return common_config('queue', 'queue_basename') . $queue;
+ }
+
function _log($level, $msg)
{
common_log($level, 'StompQueueManager: '.$msg);
--
cgit v1.2.3-54-g00ecf
From 49c5c6f92bc1d06e6464eade81eead891d86f10d Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 00:31:28 -0400
Subject: move handling code into queuemanager
---
lib/dbqueuemanager.php | 35 +++++++++++++++++++--
lib/queuehandler.php | 30 ++----------------
lib/queuemanager.php | 19 ++---------
lib/stompqueuemanager.php | 80 +++++++++--------------------------------------
4 files changed, 51 insertions(+), 113 deletions(-)
diff --git a/lib/dbqueuemanager.php b/lib/dbqueuemanager.php
index c9e5ef243..6e7172de0 100644
--- a/lib/dbqueuemanager.php
+++ b/lib/dbqueuemanager.php
@@ -51,7 +51,36 @@ class DBQueueManager extends QueueManager
return true;
}
- function nextItem($queue, $timeout=null)
+ function service($queue, $handler)
+ {
+ while (true) {
+ $this->_log(LOG_DEBUG, 'Checking for notices...');
+ $notice = $this->_nextItem($queue, null);
+ if (empty($notice)) {
+ $this->_log(LOG_DEBUG, 'No notices waiting; idling.');
+ // Nothing in the queue. Do you
+ // have other tasks, like servicing your
+ // XMPP connection, to do?
+ $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ } else {
+ $this->_log(LOG_INFO, 'Got notice '. $notice->id);
+ // Yay! Got one!
+ if ($handler->handle_notice($notice)) {
+ $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id);
+ $this->_done($notice, $queue);
+ } else {
+ $this->_log(LOG_INFO, 'Failed to handle notice '. $notice->id);
+ $this->_fail($notice, $queue);
+ }
+ // Chance to e.g. service your XMPP connection
+ $this->_log(LOG_DEBUG, 'Idling after success.');
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+ }
+ // XXX: when do we give up?
+ }
+ }
+
+ function _nextItem($queue, $timeout=null)
{
$start = time();
$result = null;
@@ -74,7 +103,7 @@ class DBQueueManager extends QueueManager
return $result;
}
- function done($object, $queue)
+ function _done($object, $queue)
{
// XXX: right now, we only handle notices
@@ -101,7 +130,7 @@ class DBQueueManager extends QueueManager
$notice = null;
}
- function fail($object, $queue)
+ function _fail($object, $queue)
{
// XXX: right now, we only handle notices
diff --git a/lib/queuehandler.php b/lib/queuehandler.php
index ddb47a28e..c0f38f4e3 100644
--- a/lib/queuehandler.php
+++ b/lib/queuehandler.php
@@ -25,7 +25,7 @@ require_once(INSTALLDIR.'/classes/Notice.php');
define('CLAIM_TIMEOUT', 1200);
define('QUEUE_HANDLER_MISS_IDLE', 10);
-define('QUEUE_HANDLER_HIT_IDLE', 10);
+define('QUEUE_HANDLER_HIT_IDLE', 0);
class QueueHandler extends Daemon
{
@@ -42,7 +42,7 @@ class QueueHandler extends Daemon
function timeout()
{
- return null;
+ return 60;
}
function class_name()
@@ -96,31 +96,7 @@ class QueueHandler extends Daemon
$qm = QueueManager::get();
- while (true) {
- $this->log(LOG_DEBUG, 'Checking for notices...');
- $notice = $qm->nextItem($queue, $timeout);
- if (empty($notice)) {
- $this->log(LOG_DEBUG, 'No notices waiting; idling.');
- // Nothing in the queue. Do you
- // have other tasks, like servicing your
- // XMPP connection, to do?
- $this->idle(QUEUE_HANDLER_MISS_IDLE);
- } else {
- $this->log(LOG_INFO, 'Got notice '. $notice->id);
- // Yay! Got one!
- if ($this->handle_notice($notice)) {
- $this->log(LOG_INFO, 'Successfully handled notice '. $notice->id);
- $qm->done($notice, $queue);
- } else {
- $this->log(LOG_INFO, 'Failed to handle notice '. $notice->id);
- $qm->fail($notice, $queue);
- }
- // Chance to e.g. service your XMPP connection
- $this->log(LOG_DEBUG, 'Idling after success.');
- $this->idle(QUEUE_HANDLER_HIT_IDLE);
- }
- // XXX: when do we give up?
- }
+ $qm->service($queue, $this);
if (!$this->finish()) {
return false;
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
index 1bf4d4dec..f36e99d16 100644
--- a/lib/queuemanager.php
+++ b/lib/queuemanager.php
@@ -67,23 +67,8 @@ class QueueManager
throw ServerException("Unimplemented function 'enqueue' called");
}
- function peek($queue)
+ function service($queue, $handler)
{
- throw ServerException("Unimplemented function 'peek' called");
- }
-
- function nextItem($queue, $timeout=null)
- {
- throw ServerException("Unimplemented function 'nextItem' called");
- }
-
- function done($object, $queue)
- {
- throw ServerException("Unimplemented function 'done' called");
- }
-
- function fail($object, $queue)
- {
- throw ServerException("Unimplemented function 'fail' called");
+ throw ServerException("Unimplemented function 'service' called");
}
}
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 1ad687036..b8731d543 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -84,85 +84,33 @@ class StompQueueManager
. $notice->id . ' for ' . $transport);
}
- function nextItem($queue, $timeout=null)
+ function service($queue, $handler)
{
$result = null;
$this->_connect();
- $frame = $this->con->readFrame();
+ $this->con->setReadTimeout($handler->timeout());
- if ($frame) {
- $this->log(LOG_INFO, 'Got item enqueued '.common_exact_date($frame->headers['created']));
+ $this->con->subscribe($this->_queueName($queue));
- // XXX: Now the queue handler receives only the ID of the
- // notice, and it has to get it from the DB
- // A massive improvement would be avoid DB query by transmitting
- // all the notice details via queue server...
+ while (true) {
- $notice = Notice::staticGet($frame->body);
+ $frame = $this->con->readFrame();
- if ($notice) {
- $this->_saveFrame($notice, $queue, $frame);
- } else {
- $this->log(LOG_WARNING, 'queue item for notice that does not exist');
- }
- }
- }
-
- function done($object, $queue)
- {
- $notice = $object;
+ if ($frame) {
+ $notice = Notice::staticGet($frame->body);
- $this->_connect();
-
- $frame = $this->_getFrame($notice, $queue);
-
- if (empty($frame)) {
- $this->log(LOG_ERR, 'Cannot find frame for notice '.$notice->id.' in queue '.$queue);
- } else {
- // if the msg has been handled positively, ack it
- // and the queue server will remove it from the queue
- $this->con->ack($frame);
- $this->_clearFrame($notice, $queue);
+ if ($handler->handle_notice($notice)) {
+ $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id);
+ $this->con->ack($frame);
+ }
+ }
- $this->log(LOG_INFO, 'finished broadcasting notice ID = ' . $notice->id);
+ $handler->idle(0);
}
- }
-
- function fail($object, $queue)
- {
- $notice = $object;
-
- // STOMP server will requeue it after a while anyways,
- // so no need to notify. Just get it out of our little
- // array
-
- $this->_clearFrame($notice, $queue);
- }
-
- function _frameKey($notice, $queue)
- {
- return ((string)$notice->id) . '-' . $queue;
- }
- function _saveFrame($notice, $queue, $frame)
- {
- $k = $this->_frameKey($notice, $queue);
- $this->_frames[$k] = $frame;
- return true;
- }
-
- function _getFrame($notice, $queue)
- {
- $k = $this->_frameKey($notice, $queue);
- return $this->_frames[$k];
- }
-
- function _clearFrame($notice, $queue)
- {
- $k = $this->_frameKey($notice, $queue);
- unset($this->_frames[$k]);
+ $this->con->unsubscribe($this->_queueName($queue));
}
function _queueName($queue)
--
cgit v1.2.3-54-g00ecf
From f63702579a672d35c5db262873a4a22835301074 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 01:16:58 -0400
Subject: don't say we're connecting if we're not
---
lib/stompqueuemanager.php | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index b8731d543..a6bac861b 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -49,7 +49,6 @@ class StompQueueManager
function _connect()
{
- $this->_log(LOG_DEBUG, "Connecting to $this->server...");
if (empty($this->con)) {
$this->_log(LOG_INFO, "Connecting to '$this->server' as '$this->username'...");
$this->con = new Stomp($this->server);
--
cgit v1.2.3-54-g00ecf
From 6d72864618b73271a83aa566f35838bb1a5c57c7 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 01:17:37 -0400
Subject: don't try to show non-object
---
lib/util.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/util.php b/lib/util.php
index a40cd3d54..9e8ec41d2 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -1028,6 +1028,9 @@ function common_log_objstring(&$object)
if (is_null($object)) {
return "null";
}
+ if (!($object instanceof DB_DataObject)) {
+ return "(unknown)";
+ }
$arr = $object->toArray();
$fields = array();
foreach ($arr as $k => $v) {
--
cgit v1.2.3-54-g00ecf
From 9dee9e1612ebe6d6f28c21bce8c426658d60f171 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 01:20:39 -0400
Subject: new default daemon jid
---
lib/xmppqueuehandler.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index 986e09c25..c8b5ad1fb 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -91,7 +91,7 @@ class XmppQueueHandler extends QueueHandler
if (common_config('xmpp', 'listener')) {
return common_config('xmpp', 'listener');
} else {
- return jabber_daemon_address() . '/' . common_config('xmpp','resource') . '-listener';
+ return jabber_daemon_address() . '/' . common_config('xmpp','resource') . 'daemon';
}
}
}
--
cgit v1.2.3-54-g00ecf
From 49eaa04b508f6e27533f494dedd4997416670bef Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 01:42:42 -0400
Subject: return singleton if initialized
---
lib/queuemanager.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/queuemanager.php b/lib/queuemanager.php
index f36e99d16..582c24790 100644
--- a/lib/queuemanager.php
+++ b/lib/queuemanager.php
@@ -57,9 +57,9 @@ class QueueManager
}
}
}
-
- return self::$qm;
}
+
+ return self::$qm;
}
function enqueue($object, $queue)
--
cgit v1.2.3-54-g00ecf
From 66a4a60e0bb67ba9094cd94be5992c70e5352e54 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 01:43:18 -0400
Subject: better debug logging in stomp queue manager
---
lib/stompqueuemanager.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index a6bac861b..5f0b88d8a 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -75,12 +75,12 @@ class StompQueueManager
array ('created' => $notice->created));
if (!$result) {
- common_log(LOG_ERR, 'Error sending to '.$transport.' queue');
+ common_log(LOG_ERR, 'Error sending to '.$queue.' queue');
return false;
}
common_log(LOG_DEBUG, 'complete remote queueing notice ID = '
- . $notice->id . ' for ' . $transport);
+ . $notice->id . ' for ' . $queue);
}
function service($queue, $handler)
@@ -101,7 +101,7 @@ class StompQueueManager
$notice = Notice::staticGet($frame->body);
if ($handler->handle_notice($notice)) {
- $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id);
+ $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created']);
$this->con->ack($frame);
}
}
--
cgit v1.2.3-54-g00ecf
From cb019f7aad9c4a618316fb3c2e4a36bc013c8da3 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sat, 4 Jul 2009 01:43:35 -0400
Subject: don't send unused variable for streams
---
classes/Notice.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/classes/Notice.php b/classes/Notice.php
index 8a018068a..5ec0692d9 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -1210,7 +1210,7 @@ class Notice extends Memcached_DataObject
$window = explode(',', $laststr);
$last_id = $window[0];
$new_ids = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW,
- $last_id, 0, null, $tag)));
+ $last_id, 0, null)));
$new_window = array_merge($new_ids, $window);
@@ -1225,7 +1225,7 @@ class Notice extends Memcached_DataObject
}
$window = call_user_func_array($fn, array_merge($args, array(0, NOTICE_CACHE_WINDOW,
- 0, 0, null, $tag)));
+ 0, 0, null)));
$windowstr = implode(',', $window);
--
cgit v1.2.3-54-g00ecf
From 23e6dafff6d82492aa7ab2addc2fae99bd609b57 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sun, 5 Jul 2009 11:01:07 -0400
Subject: better handling of frames and notices
---
lib/stompqueuemanager.php | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 5f0b88d8a..e7e1e00dd 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -37,7 +37,6 @@ class StompQueueManager
var $password = null;
var $base = null;
var $con = null;
- var $frames = array();
function __construct()
{
@@ -97,13 +96,19 @@ class StompQueueManager
$frame = $this->con->readFrame();
- if ($frame) {
- $notice = Notice::staticGet($frame->body);
+ if (!empty($frame)) {
+ $notice = Notice::staticGet('id', $frame->body);
- if ($handler->handle_notice($notice)) {
+ if (empty($notice)) {
+ $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice');
+ $this->con->ack($frame);
+ } else if ($handler->handle_notice($notice)) {
$this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created']);
$this->con->ack($frame);
+ unset($notice);
}
+
+ unset($frame);
}
$handler->idle(0);
--
cgit v1.2.3-54-g00ecf
From d4db9d83d84859d7492438a215c8d7a4baf3ef68 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sun, 5 Jul 2009 12:44:18 -0400
Subject: Revert "Merge branch '0.8.x' into cachenonexistent"
This reverts commit e21d2cfdb5f259a07d7af0e3c7f5421315ed2710.
---
classes/Memcached_DataObject.php | 50 ++++++++--------------------------------
1 file changed, 10 insertions(+), 40 deletions(-)
diff --git a/classes/Memcached_DataObject.php b/classes/Memcached_DataObject.php
index 96f8d520b..f7cbb9d5b 100644
--- a/classes/Memcached_DataObject.php
+++ b/classes/Memcached_DataObject.php
@@ -33,41 +33,21 @@ class Memcached_DataObject extends DB_DataObject
$k = $keys[0];
unset($i);
}
- $i = self::getcached($cls, $k, $v);
+ $i = Memcached_DataObject::getcached($cls, $k, $v);
if ($i) {
return $i;
} else {
$i = DB_DataObject::staticGet($cls, $k, $v);
if ($i) {
$i->encache();
- } else {
- self::cachenull($cls, $k, $v);
}
return $i;
}
}
- function cachenull($cls, $k, $v)
- {
- $c = self::memcache();
- if (empty($c)) {
- return;
- }
- $c->set(self::cacheKey($cls, $k, $v), null);
- }
-
- function multicachenull($cls, $kv)
- {
- $c = self::memcache();
- if (empty($c)) {
- return;
- }
- $c->set(self::multicachekey($cls, $kv), null);
- }
-
function &pkeyGet($cls, $kv)
{
- $i = self::multicache($cls, $kv);
+ $i = Memcached_DataObject::multicache($cls, $kv);
if ($i) {
return $i;
} else {
@@ -78,7 +58,6 @@ class Memcached_DataObject extends DB_DataObject
if ($i->find(true)) {
$i->encache();
} else {
- self::multicachenull($cls, $kv);
$i = null;
}
return $i;
@@ -88,9 +67,6 @@ class Memcached_DataObject extends DB_DataObject
function insert()
{
$result = parent::insert();
- if ($result) {
- $this->encache();
- }
return $result;
}
@@ -121,11 +97,11 @@ class Memcached_DataObject extends DB_DataObject
}
static function getcached($cls, $k, $v) {
- $c = self::memcache();
+ $c = Memcached_DataObject::memcache();
if (!$c) {
return false;
} else {
- return $c->get(self::cacheKey($cls, $k, $v));
+ return $c->get(Memcached_DataObject::cacheKey($cls, $k, $v));
}
}
@@ -192,23 +168,17 @@ class Memcached_DataObject extends DB_DataObject
function multicache($cls, $kv)
{
- $c = self::memcache();
+ ksort($kv);
+ $c = Memcached_DataObject::memcache();
if (!$c) {
return false;
} else {
- return $c->get(self::multicachekey($cls, $kv));
+ $pkeys = implode(',', array_keys($kv));
+ $pvals = implode(',', array_values($kv));
+ return $c->get(Memcached_DataObject::cacheKey($cls, $pkeys, $pvals));
}
}
- function multicachekey($cls, $kv)
- {
- ksort($kv);
- $pkeys = implode(',', array_keys($kv));
- $pvals = implode(',', array_values($kv));
-
- return self::cacheKey($cls, $pkeys, $pvals);
- }
-
function getSearchEngine($table)
{
require_once INSTALLDIR.'/lib/search_engines.php';
@@ -241,7 +211,7 @@ class Memcached_DataObject extends DB_DataObject
static function cachedQuery($cls, $qry, $expiry=3600)
{
- $c = self::memcache();
+ $c = Memcached_DataObject::memcache();
if (!$c) {
$inst = new $cls();
$inst->query($qry);
--
cgit v1.2.3-54-g00ecf
From e6c54a59e140c9ee3b6244dbcb92f9ca9d065887 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sun, 5 Jul 2009 14:33:12 -0400
Subject: set/get viewdesigns flag and use it
---
actions/othersettings.php | 11 ++++++++---
lib/groupdesignaction.php | 16 +++++++++-------
lib/ownerdesignaction.php | 12 ++++++++----
3 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/actions/othersettings.php b/actions/othersettings.php
index b542233ca..1277f8052 100644
--- a/actions/othersettings.php
+++ b/actions/othersettings.php
@@ -83,14 +83,12 @@ class OthersettingsAction extends AccountSettingsAction
{
$user = common_current_user();
-
$this->elementStart('form', array('method' => 'post',
'id' => 'form_settings_other',
'class' => 'form_settings',
'action' =>
common_local_url('othersettings')));
$this->elementStart('fieldset');
- $this->element('legend', null, _('URL Auto-shortening'));
$this->hidden('token', common_session_token());
// I18N
@@ -109,10 +107,14 @@ class OthersettingsAction extends AccountSettingsAction
$this->elementStart('ul', 'form_data');
$this->elementStart('li');
- $this->dropdown('urlshorteningservice', _('Service'),
+ $this->dropdown('urlshorteningservice', _('Shorten URLs with'),
$services, _('Automatic shortening service to use.'),
false, $user->urlshorteningservice);
$this->elementEnd('li');
+ $this->elementStart('li');
+ $this->checkbox('viewdesigns', _('View profile designs'),
+ $user->viewdesigns, _('Show or hide profile designs.'));
+ $this->elementEnd('li');
$this->elementEnd('ul');
$this->submit('save', _('Save'));
$this->elementEnd('fieldset');
@@ -145,6 +147,8 @@ class OthersettingsAction extends AccountSettingsAction
return;
}
+ $viewdesigns = $this->boolean('viewdesigns');
+
$user = common_current_user();
assert(!is_null($user)); // should already be checked
@@ -154,6 +158,7 @@ class OthersettingsAction extends AccountSettingsAction
$original = clone($user);
$user->urlshorteningservice = $urlshorteningservice;
+ $user->viewdesigns = $viewdesigns;
$result = $user->update($original);
diff --git a/lib/groupdesignaction.php b/lib/groupdesignaction.php
index bc95921f1..58777c283 100644
--- a/lib/groupdesignaction.php
+++ b/lib/groupdesignaction.php
@@ -34,7 +34,7 @@ if (!defined('LACONICA')) {
/**
* Base class for actions that use a group's design
*
- * Pages related to groups can be themed with a design.
+ * Pages related to groups can be themed with a design.
* This superclass returns that design.
*
* @category Action
@@ -48,7 +48,7 @@ class GroupDesignAction extends Action {
/** The group in question */
var $group = null;
-
+
/**
* Show the groups's design stylesheet
*
@@ -58,10 +58,14 @@ class GroupDesignAction extends Action {
{
parent::showStylesheets();
- $design = $this->getDesign();
+ $user = common_current_user();
+
+ if (empty($user) || $user->viewdesigns) {
+ $design = $this->getDesign();
- if (!empty($design)) {
- $design->showCSS($this);
+ if (!empty($design)) {
+ $design->showCSS($this);
+ }
}
}
@@ -76,12 +80,10 @@ class GroupDesignAction extends Action {
function getDesign()
{
-
if (empty($this->group)) {
return null;
}
return $this->group->getDesign();
}
-
}
diff --git a/lib/ownerdesignaction.php b/lib/ownerdesignaction.php
index 424474f42..785b8a93d 100644
--- a/lib/ownerdesignaction.php
+++ b/lib/ownerdesignaction.php
@@ -61,11 +61,15 @@ class OwnerDesignAction extends Action {
{
parent::showStylesheets();
- $design = $this->getDesign();
+ $user = common_current_user();
- if (!empty($design)) {
- $design->showCSS($this);
- }
+ if (empty($user) || $user->viewdesigns) {
+ $design = $this->getDesign();
+
+ if (!empty($design)) {
+ $design->showCSS($this);
+ }
+ }
}
/**
--
cgit v1.2.3-54-g00ecf
From 5875c02cbba9c595e6fb73f788776d23905694d5 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Sun, 5 Jul 2009 14:37:37 -0400
Subject: also hide your own design
---
lib/currentuserdesignaction.php | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/lib/currentuserdesignaction.php b/lib/currentuserdesignaction.php
index 7c2520cf6..4c7e15a8b 100644
--- a/lib/currentuserdesignaction.php
+++ b/lib/currentuserdesignaction.php
@@ -53,14 +53,19 @@ class CurrentUserDesignAction extends Action
*
* @return nothing
*/
+
function showStylesheets()
{
parent::showStylesheets();
- $design = $this->getDesign();
+ $user = common_current_user();
+
+ if (empty($user) || $user->viewdesigns) {
+ $design = $this->getDesign();
- if (!empty($design)) {
- $design->showCSS($this);
+ if (!empty($design)) {
+ $design->showCSS($this);
+ }
}
}
@@ -84,5 +89,4 @@ class CurrentUserDesignAction extends Action
return $cur->getDesign();
}
-
}
--
cgit v1.2.3-54-g00ecf
From d48d27d79f9c51aa3bde345c1c69ade1d93e8b2e Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Sun, 5 Jul 2009 22:57:35 +0000
Subject: Updated margin/width value for nested notices
---
theme/base/css/display.css | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index f2b200376..22610bd51 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -783,8 +783,8 @@ list-style-type:none;
}
.notices .notices {
margin-top:7px;
-margin-left:5%;
-width:95%;
+margin-left:2%;
+width:98%;
float:left;
}
--
cgit v1.2.3-54-g00ecf
From d40075ae9c7c2b920a5e9a7cd436aff96f94d8f8 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Mon, 6 Jul 2009 11:57:21 -0700
Subject: Support undocumented 'id' parameter in /statuses/show API method
---
actions/twitapistatuses.php | 15 ++++++++++++---
lib/router.php | 2 +-
2 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php
index 555c746cb..c9943698d 100644
--- a/actions/twitapistatuses.php
+++ b/actions/twitapistatuses.php
@@ -373,9 +373,19 @@ class TwitapistatusesAction extends TwitterapiAction
return;
}
+ // 'id' is an undocumented parameter in Twitter's API. Several
+ // clients make use of it, so we support it too.
+
+ // show.json?id=12345 takes precedence over /show/12345.json
+
$this->auth_user = $apidata['user'];
- $notice_id = $apidata['api_arg'];
- $notice = Notice::staticGet($notice_id);
+ $notice_id = $this->trimmed('id');
+
+ if (empty($notice_id)) {
+ $notice_id = $apidata['api_arg'];
+ }
+
+ $notice = Notice::staticGet((int)$notice_id);
if ($notice) {
if ($apidata['content-type'] == 'xml') {
@@ -389,7 +399,6 @@ class TwitapistatusesAction extends TwitterapiAction
$this->clientError(_('No status with that ID found.'),
404, $apidata['content-type']);
}
-
}
function destroy($args, $apidata)
diff --git a/lib/router.php b/lib/router.php
index 50b733453..75e72f932 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -261,7 +261,7 @@ class Router
$m->connect('api/statuses/:method',
array('action' => 'api',
'apiaction' => 'statuses'),
- array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|mentions|friends|followers|featured)(\.(atom|rss|xml|json))?'));
+ array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|mentions|show|friends|followers|featured)(\.(atom|rss|xml|json))?'));
$m->connect('api/statuses/:method/:argument',
array('action' => 'api',
--
cgit v1.2.3-54-g00ecf
From 5e067c2c813cb51c1162761aaf3a7efd883ba731 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Mon, 6 Jul 2009 13:21:16 -0700
Subject: Add special basic auth handling for friendships/show. Other fixups.
---
actions/api.php | 63 +++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 48 insertions(+), 15 deletions(-)
diff --git a/actions/api.php b/actions/api.php
index 08f5fadad..18c3b68d4 100644
--- a/actions/api.php
+++ b/actions/api.php
@@ -75,14 +75,14 @@ class ApiAction extends Action
}
} else {
- # Caller might give us a username even if not required
- if (isset($_SERVER['PHP_AUTH_USER'])) {
- $user = User::staticGet('nickname', $_SERVER['PHP_AUTH_USER']);
- if ($user) {
- $this->user = $user;
- }
- # Twitter doesn't throw an error if the user isn't found
- }
+ // Caller might give us a username even if not required
+ if (isset($_SERVER['PHP_AUTH_USER'])) {
+ $user = User::staticGet('nickname', $_SERVER['PHP_AUTH_USER']);
+ if ($user) {
+ $this->user = $user;
+ }
+ # Twitter doesn't throw an error if the user isn't found
+ }
$this->process_command();
}
@@ -117,7 +117,7 @@ class ApiAction extends Action
}
}
- # Whitelist of API methods that don't need authentication
+ // Whitelist of API methods that don't need authentication
function requires_auth()
{
static $noauth = array( 'statuses/public_timeline',
@@ -135,28 +135,61 @@ class ApiAction extends Action
'statuses/replies',
'statuses/mentions',
'statuses/followers',
- 'favorites/favorites');
+ 'favorites/favorites',
+ 'friendships/show');
$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;
}
+ // bareauth: only needs auth if without an argument or query param specifying user
+
if (in_array($fullname, $bareauth)) {
- # bareauth: only needs auth if without an argument or query param specifying user
- if ($this->api_arg || $this->arg('id') || is_numeric($this->arg('user_id')) || $this->arg('screen_name')) {
+
+ // Special case: friendships/show only needs auth if source_id or
+ // source_screen_name is not specified as a param
+
+ if ($fullname == 'friendships/show') {
+
+ $source_id = $this->arg('source_id');
+ $source_screen_name = $this->arg('source_screen_name');
+
+ if (empty($source_id) && empty($source_screen_name)) {
+ return true;
+ }
+
return false;
- } else {
+ }
+
+ // if all of these are empty, auth is required
+
+ $id = $this->arg('id');
+ $user_id = $this->arg('user_id');
+ $screen_name = $this->arg('screen_name');
+
+ if (empty($this->api_arg) &&
+ empty($id) &&
+ empty($user_id) &&
+ empty($screen_name)) {
return true;
+ } else {
+ return false;
}
+
} else if (in_array($fullname, $noauth)) {
- # noauth: never needs auth
+
+ // noauth: never needs auth
+
return false;
} else {
- # everybody else needs auth
+
+ // everybody else needs auth
+
return true;
}
}
--
cgit v1.2.3-54-g00ecf
From 91684830e55dd0e6a9e069ff140e17a929dd2364 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Mon, 6 Jul 2009 15:49:26 -0700
Subject: fix bad function call
---
actions/twitapiusers.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index 0461efcb4..a47fdfbc3 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -45,7 +45,7 @@ class TwitapiusersAction extends TwitterapiAction
}
if (!$user) {
- $this->client_error(_('Not found.'), 404, $apidata['content-type']);
+ $this->clientError(_('Not found.'), 404, $apidata['content-type']);
return;
}
--
cgit v1.2.3-54-g00ecf
From a9c1e665701d5f5f20940143aa413faaec1a8c78 Mon Sep 17 00:00:00 2001
From: Dan Moore
Date: Fri, 5 Jun 2009 12:53:17 -0400
Subject: Bringing users/show in line with Twitter as far as specifying user.
---
actions/twitapiusers.php | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index 4057b63e7..ee01c2a43 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -37,20 +37,13 @@ class TwitapiusersAction extends TwitterapiAction
$user = null;
$email = $this->arg('email');
- $user_id = $this->arg('user_id');
// XXX: email field deprecated in Twitter's API
- // XXX: Also: need to add screen_name param
-
if ($email) {
$user = User::staticGet('email', $email);
- } elseif ($user_id) {
- $user = $this->get_user($user_id);
- } elseif (isset($apidata['api_arg'])) {
+ } else {
$user = $this->get_user($apidata['api_arg']);
- } elseif (isset($apidata['user'])) {
- $user = $apidata['user'];
}
if (empty($user)) {
--
cgit v1.2.3-54-g00ecf
From 195ec6820bf0c7fa60bca0f112a2ff8f98345a3c Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Mon, 6 Jul 2009 15:56:10 -0700
Subject: fix bad function call
Conflicts:
actions/twitapiusers.php
---
actions/twitapiusers.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index ee01c2a43..e9fcccbde 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -47,7 +47,7 @@ class TwitapiusersAction extends TwitterapiAction
}
if (empty($user)) {
- $this->client_error(_('Not found.'), 404, $apidata['content-type']);
+ $this->clientError(_('Not found.'), 404, $apidata['content-type']);
return;
}
--
cgit v1.2.3-54-g00ecf
From 4fffe1874f7db6239a42d5a9acdc4279fdde08f8 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Mon, 6 Jul 2009 16:44:35 -0700
Subject: Fix redundant page display for group design settings
---
actions/groupdesignsettings.php | 32 --------------------------------
1 file changed, 32 deletions(-)
diff --git a/actions/groupdesignsettings.php b/actions/groupdesignsettings.php
index 6c1c052cb..bb01243c6 100644
--- a/actions/groupdesignsettings.php
+++ b/actions/groupdesignsettings.php
@@ -312,36 +312,4 @@ class GroupDesignSettingsAction extends DesignSettingsAction
$this->showForm(_('Design preferences saved.'), true);
}
- /**
- * Handle input and output a page (overrided)
- *
- * @param array $args $_REQUEST arguments
- *
- * @return void
- */
-
- function handle($args)
- {
- parent::handle($args);
- if (!common_logged_in()) {
- $this->clientError(_('Not logged in.'));
- return;
- } else if (!common_is_real_login()) {
- // Cookie theft means that automatic logins can't
- // change important settings or see private info, and
- // _all_ our settings are important
- common_set_returnto($this->selfUrl());
- $user = common_current_user();
- if ($user->hasOpenID()) {
- common_redirect(common_local_url('openidlogin'), 303);
- } else {
- common_redirect(common_local_url('login'), 303);
- }
- } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $this->handlePost();
- } else {
- $this->showForm();
- }
- }
-
}
--
cgit v1.2.3-54-g00ecf
From acb305b34a5ff1dcd6f90eeb93ea2634dc77863e Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Tue, 7 Jul 2009 00:22:43 +0000
Subject: Changed img max-width to all attachment views
---
theme/base/css/display.css | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index 22610bd51..854095bad 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -1027,13 +1027,13 @@ border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
}
-#jOverlayContent #content img {
-max-width:480px;
-}
#jOverlayLoading {
top:22.5%;
left:40%;
}
+#attachment_view img {
+max-width:480px;
+}
#attachment_view #oembed_info {
margin-top:11px;
}
--
cgit v1.2.3-54-g00ecf
From c266e0d68c1d39ea5d1d9328d002d5bcf72515e3 Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Tue, 7 Jul 2009 00:43:56 +0000
Subject: Added max-height to designsettings and attachment view images
---
theme/base/css/display.css | 2 ++
1 file changed, 2 insertions(+)
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index 854095bad..8ee3a1d7b 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -1033,6 +1033,7 @@ left:40%;
}
#attachment_view img {
max-width:480px;
+max-height:480px;
}
#attachment_view #oembed_info {
margin-top:11px;
@@ -1278,6 +1279,7 @@ margin-bottom:0;
#form_settings_design #settings_design_background-image img {
max-width:480px;
+max-height:480px;
}
#form_settings_design #settings_design_color .form_data,
--
cgit v1.2.3-54-g00ecf
From 247cf2ea8f2f779b60c445d45e6728e8db67738d Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Tue, 7 Jul 2009 04:08:51 +0000
Subject: Updated support for 800px width design
---
theme/base/css/display.css | 12 ++++++------
theme/base/css/ie.css | 10 +++-------
2 files changed, 9 insertions(+), 13 deletions(-)
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index 8ee3a1d7b..e9f4beaae 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -275,7 +275,7 @@ margin-bottom:18px;
#anon_notice {
float:left;
-width:43.2%;
+width:42.4%;
padding:1.1%;
border-radius:7px;
-moz-border-radius:7px;
@@ -396,7 +396,7 @@ margin-bottom:1em;
}
#content {
-width:64.009%;
+width:63.311%;
min-height:259px;
padding:1.795%;
float:left;
@@ -422,7 +422,7 @@ float:left;
width:27.917%;
min-height:259px;
float:left;
-margin-left:0.5%;
+margin-left:0.699%;
padding:1.795%;
border-radius:7px;
-moz-border-radius:7px;
@@ -432,7 +432,7 @@ border-style:solid;
}
#form_notice {
-width:45.664%;
+width:45%;
float:left;
position:relative;
line-height:1;
@@ -471,12 +471,12 @@ cursor:pointer;
}
#form_notice label[for=notice_data-attach] {
text-indent:-9999px;
-left:394px;
+left:86%;
width:16px;
height:16px;
}
#form_notice #notice_data-attach {
-left:183px;
+left:40.6%;
padding:0;
height:16px;
}
diff --git a/theme/base/css/ie.css b/theme/base/css/ie.css
index 43fb01492..3e128b84e 100644
--- a/theme/base/css/ie.css
+++ b/theme/base/css/ie.css
@@ -9,7 +9,7 @@ width:78%;
#form_notice .form_note + label {
position:absolute;
top:25px;
-left:380px;
+left:83%;
text-indent:-9999px;
height:16px;
width:16px;
@@ -25,10 +25,6 @@ width:78.5%;
#form_notice #notice_data-attach_selected button {
padding:0 4px;
}
-#anon_notice {
-max-width:39%;
-}
-
.notice-options input.submit {
font-size:0;
margin-top:3px;
@@ -49,6 +45,6 @@ z-index:1;
.notice:hover {
z-index:9999;
}
-.notice .thumbnail img {
+.notice .thumbnail img {
z-index:9999;
-}
\ No newline at end of file
+}
--
cgit v1.2.3-54-g00ecf
From 5f72423523c0d95800460cd3342461d3c72eafa1 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Tue, 7 Jul 2009 15:55:10 -0400
Subject: File classes does not use the $FILES array directly, as users of this
class aren't necessarily from the web
---
actions/newnotice.php | 2 +-
classes/File.php | 10 +++++-----
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/actions/newnotice.php b/actions/newnotice.php
index 5f44a32a9..e254eac49 100644
--- a/actions/newnotice.php
+++ b/actions/newnotice.php
@@ -135,7 +135,7 @@ class NewnoticeAction extends Action
function isRespectsQuota($user) {
$file = new File;
- $ret = $file->isRespectsQuota($user);
+ $ret = $file->isRespectsQuota($user,$_FILES['attach']['size']);
if (true === $ret) return true;
$this->clientError($ret);
}
diff --git a/classes/File.php b/classes/File.php
index 5dd7cd865..533cc6e71 100644
--- a/classes/File.php
+++ b/classes/File.php
@@ -122,17 +122,17 @@ class File extends Memcached_DataObject
return $x;
}
- function isRespectsQuota($user) {
- if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) {
+ function isRespectsQuota($user,$fileSize) {
+ if ($fileSize > common_config('attachments', 'file_quota')) {
return sprintf(_('No file may be larger than %d bytes ' .
'and the file you sent was %d bytes. Try to upload a smaller version.'),
- common_config('attachments', 'file_quota'), $_FILES['attach']['size']);
+ common_config('attachments', 'file_quota'), $fileSize);
}
$query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'";
$this->query($query);
$this->fetch();
- $total = $this->total + $_FILES['attach']['size'];
+ $total = $this->total + $fileSize;
if ($total > common_config('attachments', 'user_quota')) {
return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'));
}
@@ -140,7 +140,7 @@ class File extends Memcached_DataObject
$query .= ' month(modified) = month(now()) and year(modified) = year(now())';
$this->query($query);
$this->fetch();
- $total = $this->total + $_FILES['attach']['size'];
+ $total = $this->total + $fileSize;
if ($total > common_config('attachments', 'monthly_quota')) {
return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'));
}
--
cgit v1.2.3-54-g00ecf
From 79c61e0c8c12f98fb4f3984a8297186a3dc847e8 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Tue, 7 Jul 2009 15:56:24 -0400
Subject: maildaemon makes mail attachments into notice attachments
---
scripts/maildaemon.php | 154 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 147 insertions(+), 7 deletions(-)
diff --git a/scripts/maildaemon.php b/scripts/maildaemon.php
index cfb11a36f..11ddf06b7 100755
--- a/scripts/maildaemon.php
+++ b/scripts/maildaemon.php
@@ -42,11 +42,11 @@ class MailerDaemon
function handle_message($fname='php://stdin')
{
- list($from, $to, $msg) = $this->parse_message($fname);
+ list($from, $to, $msg, $attachments) = $this->parse_message($fname);
if (!$from || !$to || !$msg) {
$this->error(null, _('Could not parse message.'));
}
- common_log(LOG_INFO, "Mail from $from to $to: " .substr($msg, 0, 20));
+ common_log(LOG_INFO, "Mail from $from to $to with ".count($attachments) .' attachment(s): ' .substr($msg, 0, 20));
$user = $this->user_from($from);
if (!$user) {
$this->error($from, _('Not a registered user.'));
@@ -65,7 +65,47 @@ class MailerDaemon
return true;
}
$msg = $this->cleanup_msg($msg);
- $err = $this->add_notice($user, $msg);
+ $msg = common_shorten_links($msg);
+ if (mb_strlen($msg) > 140) {
+ $this->error($from,_('That\'s too long. '.
+ 'Max notice size is 140 chars.'));
+ }
+ $fileRecords = array();
+ foreach($attachments as $attachment){
+ $mimetype = $this->getUploadedFileType($attachment);
+ $stream = stream_get_meta_data($attachment);
+ if (!$this->isRespectsQuota($user,filesize($stream['uri']))) {
+ die('error() should trigger an exception before reaching here.');
+ }
+ $filename = $this->saveFile($user, $attachment,$mimetype);
+
+ fclose($attachment);
+
+ if (empty($filename)) {
+ $this->error($from,_('Couldn\'t save file.'));
+ }
+
+ $fileRecord = $this->storeFile($filename, $mimetype);
+ $fileRecords[] = $fileRecord;
+ $fileurl = common_local_url('attachment',
+ array('attachment' => $fileRecord->id));
+
+ // not sure this is necessary -- Zach
+ $this->maybeAddRedir($fileRecord->id, $fileurl);
+
+ $short_fileurl = common_shorten_url($fileurl);
+ $msg .= ' ' . $short_fileurl;
+
+ if (mb_strlen($msg) > 140) {
+ $this->deleteFile($filename);
+ $this->error($from,_('Max notice size is 140 chars, including attachment URL.'));
+ }
+
+ // Also, not sure this is necessary -- Zach
+ $this->maybeAddRedir($fileRecord->id, $short_fileurl);
+ }
+
+ $err = $this->add_notice($user, $msg, $fileRecords);
if (is_string($err)) {
$this->error($from, $err);
return false;
@@ -74,6 +114,89 @@ class MailerDaemon
}
}
+ function saveFile($user, $attachment, $mimetype) {
+
+ $filename = File::filename($user->getProfile(), "email", $mimetype);
+
+ $filepath = File::path($filename);
+
+ $stream = stream_get_meta_data($attachment);
+ if (copy($stream['uri'], $filepath) && chmod($filepath,0664)) {
+ return $filename;
+ } else {
+ $this->error(null,_('File could not be moved to destination directory.' . $stream['uri'] . ' ' . $filepath));
+ }
+ }
+
+ function storeFile($filename, $mimetype) {
+
+ $file = new File;
+ $file->filename = $filename;
+
+ $file->url = File::url($filename);
+
+ $filepath = File::path($filename);
+
+ $file->size = filesize($filepath);
+ $file->date = time();
+ $file->mimetype = $mimetype;
+
+ $file_id = $file->insert();
+
+ if (!$file_id) {
+ common_log_db_error($file, "INSERT", __FILE__);
+ $this->error(null,_('There was a database error while saving your file. Please try again.'));
+ }
+
+ return $file;
+ }
+
+ function maybeAddRedir($file_id, $url)
+ {
+ $file_redir = File_redirection::staticGet('url', $url);
+
+ if (empty($file_redir)) {
+ $file_redir = new File_redirection;
+ $file_redir->url = $url;
+ $file_redir->file_id = $file_id;
+
+ $result = $file_redir->insert();
+
+ if (!$result) {
+ common_log_db_error($file_redir, "INSERT", __FILE__);
+ $this->error(null,_('There was a database error while saving your file. Please try again.'));
+ }
+ }
+ }
+
+ function getUploadedFileType($fileHandle) {
+ require_once 'MIME/Type.php';
+
+ $cmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd');
+ $cmd = common_config('attachments', 'filecommand');
+
+ $stream = stream_get_meta_data($fileHandle);
+ $filetype = MIME_Type::autoDetect($stream['uri']);
+ if (in_array($filetype, common_config('attachments', 'supported'))) {
+ return $filetype;
+ }
+ $media = MIME_Type::getMedia($filetype);
+ if ('application' !== $media) {
+ $hint = sprintf(_(' Try using another %s format.'), $media);
+ } else {
+ $hint = '';
+ }
+ $this->error(null,sprintf(
+ _('%s is not a supported filetype on this server.'), $filetype) . $hint);
+ }
+
+ function isRespectsQuota($user,$fileSize) {
+ $file = new File;
+ $ret = $file->isRespectsQuota($user,$fileSize);
+ if (true === $ret) return true;
+ $this->error(null,$ret);
+ }
+
function error($from, $msg)
{
file_put_contents("php://stderr", $msg . "\n");
@@ -133,19 +256,30 @@ class MailerDaemon
common_log($level, 'MailDaemon: '.$msg);
}
- function add_notice($user, $msg)
+ function add_notice($user, $msg, $fileRecords)
{
$notice = Notice::saveNew($user->id, $msg, 'mail');
if (is_string($notice)) {
$this->log(LOG_ERR, $notice);
return $notice;
}
+ foreach($fileRecords as $fileRecord){
+ $this->attachFile($notice, $fileRecord);
+ }
common_broadcast_notice($notice);
$this->log(LOG_INFO,
'Added notice ' . $notice->id . ' from user ' . $user->nickname);
return true;
}
+ function attachFile($notice, $filerec)
+ {
+ File_to_post::processNew($filerec->id, $notice->id);
+
+ $this->maybeAddRedir($filerec->id,
+ common_local_url('file', array('notice' => $notice->id)));
+ }
+
function parse_message($fname)
{
$contents = file_get_contents($fname);
@@ -163,12 +297,19 @@ class MailerDaemon
$type = $parsed->ctype_primary . '/' . $parsed->ctype_secondary;
+ $attachments = array();
+
if ($parsed->ctype_primary == 'multipart') {
foreach ($parsed->parts as $part) {
if ($part->ctype_primary == 'text' &&
$part->ctype_secondary == 'plain') {
$msg = $part->body;
- break;
+ }else{
+ if ($part->body) {
+ $attachment = tmpfile();
+ fwrite($attachment, $part->body);
+ $attachments[] = $attachment;
+ }
}
}
} else if ($type == 'text/plain') {
@@ -176,8 +317,7 @@ class MailerDaemon
} else {
$this->unsupported_type($type);
}
-
- return array($from, $to, $msg);
+ return array($from, $to, $msg, $attachments);
}
function unsupported_type($type)
--
cgit v1.2.3-54-g00ecf
From 8bc924224b96928e9d41a18a83f515e5e53ba4f7 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Tue, 7 Jul 2009 20:13:39 +0000
Subject: Update translations updater script to use Pootle
---
scripts/update_translations.php | 121 ++++++++++++++++++++++------------------
1 file changed, 68 insertions(+), 53 deletions(-)
diff --git a/scripts/update_translations.php b/scripts/update_translations.php
index 4d7adafea..c0919161a 100755
--- a/scripts/update_translations.php
+++ b/scripts/update_translations.php
@@ -1,66 +1,81 @@
+#!/usr/bin/env php
.
+ */
+
+// Abort if called from a web server
+if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) {
+ print "This script must be run from the command line\n";
+ exit();
+}
+
+define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
+define('LACONICA', true);
+
+require_once(INSTALLDIR . '/lib/common.php');
+
+// Master Laconica .pot file location (created by update_pot.sh)
+$laconica_pot = INSTALLDIR . '/locale/laconica.po';
set_time_limit(60);
-chdir(dirname(__FILE__) . '/..');
/* Languages to pull */
-$languages = array(
- 'da_DK' => 'http://laconi.ca/translate/download.php?file_id=93',
- 'nl_NL' => 'http://laconi.ca/translate/download.php?file_id=97',
- 'en_NZ' => 'http://laconi.ca/translate/download.php?file_id=87',
- 'eo' => 'http://laconi.ca/translate/download.php?file_id=88',
- 'fr_FR' => 'http://laconi.ca/translate/download.php?file_id=99',
- 'de_DE' => 'http://laconi.ca/translate/download.php?file_id=100',
- 'it_IT' => 'http://laconi.ca/translate/download.php?file_id=101',
- 'ko' => 'http://laconi.ca/translate/download.php?file_id=102',
- 'no_NB' => 'http://laconi.ca/translate/download.php?file_id=104',
- 'pt' => 'http://laconi.ca/translate/download.php?file_id=106',
- 'pt_BR' => 'http://laconi.ca/translate/download.php?file_id=107',
- 'ru_RU' => 'http://laconi.ca/translate/download.php?file_id=109',
- 'es' => 'http://laconi.ca/translate/download.php?file_id=110',
- 'tr_TR' => 'http://laconi.ca/translate/download.php?file_id=114',
- 'uk_UA' => 'http://laconi.ca/translate/download.php?file_id=115',
- 'he_IL' => 'http://laconi.ca/translate/download.php?file_id=116',
- 'mk_MK' => 'http://laconi.ca/translate/download.php?file_id=103',
- 'ja_JP' => 'http://laconi.ca/translate/download.php?file_id=117',
- 'cs_CZ' => 'http://laconi.ca/translate/download.php?file_id=96',
- 'ca_ES' => 'http://laconi.ca/translate/download.php?file_id=95',
- 'pl_PL' => 'http://laconi.ca/translate/download.php?file_id=105',
- 'sv_SE' => 'http://laconi.ca/translate/download.php?file_id=128'
-);
+$languages = get_all_languages();
/* Update the languages */
-foreach ($languages as $code => $file) {
- $lcdir='locale/'.$code;
- $msgdir=$lcdir.'/LC_MESSAGES';
- $pofile=$msgdir.'/laconica.po';
- $mofile=$msgdir.'/laconica.mo';
+foreach ($languages as $language) {
+
+ $code = $language['lang'];
+ $file = 'http://laconi.ca/pootle/' . $code .
+ '/laconica/LC_MESSAGES/laconica.po';
+ $lcdir = INSTALLDIR . '/locale/' . $code;
+ $msgdir = "$lcdir/LC_MESSAGES";
+ $pofile = "$msgdir/laconica.po";
+ $mofile = "$msgdir/laconica.mo";
- /* Check for an existing */
- if (!is_dir($msgdir)) {
- mkdir($lcdir);
- mkdir($msgdir);
- $existingSHA1 = '';
- } else {
- $existingSHA1 = file_exists($pofile) ? sha1_file($pofile) : '';
- }
+ /* Check for an existing */
+ if (!is_dir($msgdir)) {
+ mkdir($lcdir);
+ mkdir($msgdir);
+ $existingSHA1 = '';
+ } else {
+ $existingSHA1 = file_exists($pofile) ? sha1_file($pofile) : '';
+ }
- /* Get the remote one */
- $newFile = file_get_contents($file);
+ /* Get the remote one */
+ $newFile = file_get_contents($file);
- // Update if the local .po file is different to the one downloaded, or
- // if the .mo file is not present.
- if(sha1($newFile)!=$existingSHA1 || !file_exists($mofile)) {
- echo "Updating ".$code."\n";
- file_put_contents($pofile, $newFile);
- $prevdir = getcwd();
- chdir($msgdir);
- system('msgmerge -U laconica.po ../../laconica.pot');
- system('msgfmt -f -o laconica.mo laconica.po');
- chdir($prevdir);
- } else {
- echo "Unchanged - ".$code."\n";
- }
+ if ($newfile === FALSE) {
+ echo "Couldn't retrieve .po file for $code: $file\n";
+ continue;
+ }
+
+ // Update if the local .po file is different to the one downloaded, or
+ // if the .mo file is not present.
+ if (sha1($newFile) != $existingSHA1 || !file_exists($mofile)) {
+ echo "Updating ".$code."\n";
+ file_put_contents($pofile, $newFile);
+ system(sprintf('msgmerge -U %s %s', $pofile, $laconica_pot));
+ system(sprintf('msgfmt -f -o %s %s', $mofile, $pofile));
+ } else {
+ echo "Unchanged - ".$code."\n";
+ }
}
+
echo "Finished\n";
--
cgit v1.2.3-54-g00ecf
From 802b9095188d51fd64d459291ca8828530220e83 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Tue, 7 Jul 2009 14:21:44 -0700
Subject: user/show API method needs to fall back to basic auth so that
verify_credentials works correctly.
---
actions/twitapiusers.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php
index e9fcccbde..de8326e3a 100644
--- a/actions/twitapiusers.php
+++ b/actions/twitapiusers.php
@@ -43,7 +43,7 @@ class TwitapiusersAction extends TwitterapiAction
if ($email) {
$user = User::staticGet('email', $email);
} else {
- $user = $this->get_user($apidata['api_arg']);
+ $user = $this->get_user($apidata['api_arg'], $apidata);
}
if (empty($user)) {
--
cgit v1.2.3-54-g00ecf
From 79b06ade27666a10cdfb54ba46af7a26b9a593d2 Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Wed, 8 Jul 2009 00:42:14 +0000
Subject: Removed OpenID link from the primary global navigation in order to
keep a single Login idea because we have several ways to login already:
regular login, OpenID and Facebook (and probably LDAP, Open Social in the
future)
---
lib/action.php | 2 --
plugins/FBConnect/FBConnectPlugin.php | 2 --
2 files changed, 4 deletions(-)
diff --git a/lib/action.php b/lib/action.php
index 928eb48c0..da5b48858 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -439,8 +439,6 @@ class Action extends HTMLOutputter // lawsuit
$this->menuItem(common_local_url('register'),
_('Register'), _('Create an account'), false, 'nav_register');
}
- $this->menuItem(common_local_url('openidlogin'),
- _('OpenID'), _('Login with OpenID'), false, 'nav_openid');
$this->menuItem(common_local_url('login'),
_('Login'), _('Login to the site'), false, 'nav_login');
}
diff --git a/plugins/FBConnect/FBConnectPlugin.php b/plugins/FBConnect/FBConnectPlugin.php
index d8af1a4e8..65870a187 100644
--- a/plugins/FBConnect/FBConnectPlugin.php
+++ b/plugins/FBConnect/FBConnectPlugin.php
@@ -313,8 +313,6 @@ class FBConnectPlugin extends Plugin
$action->menuItem(common_local_url('register'),
_('Register'), _('Create an account'), false, 'nav_register');
}
- $action->menuItem(common_local_url('openidlogin'),
- _('OpenID'), _('Login with OpenID'), false, 'nav_openid');
$action->menuItem(common_local_url('login'),
_('Login'), _('Login to the site'), false, 'nav_login');
}
--
cgit v1.2.3-54-g00ecf
From 72d3ead0c274bd14d6e2851118049338108a6246 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Wed, 8 Jul 2009 01:10:19 +0000
Subject: Use cURL instead of get_file_contents() to do away with warnings.
Also more reliable.
---
scripts/update_translations.php | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/scripts/update_translations.php b/scripts/update_translations.php
index c0919161a..2f4ca8720 100755
--- a/scripts/update_translations.php
+++ b/scripts/update_translations.php
@@ -42,7 +42,7 @@ $languages = get_all_languages();
foreach ($languages as $language) {
$code = $language['lang'];
- $file = 'http://laconi.ca/pootle/' . $code .
+ $file_url = 'http://laconi.ca/pootle/' . $code .
'/laconica/LC_MESSAGES/laconica.po';
$lcdir = INSTALLDIR . '/locale/' . $code;
$msgdir = "$lcdir/LC_MESSAGES";
@@ -59,18 +59,18 @@ foreach ($languages as $language) {
}
/* Get the remote one */
- $newFile = file_get_contents($file);
+ $new_file = curl_get_file($file_url);
- if ($newfile === FALSE) {
- echo "Couldn't retrieve .po file for $code: $file\n";
+ if ($new_file === FALSE) {
+ echo "Couldn't retrieve .po file for $code: $file_url\n";
continue;
}
// Update if the local .po file is different to the one downloaded, or
// if the .mo file is not present.
- if (sha1($newFile) != $existingSHA1 || !file_exists($mofile)) {
+ if (sha1($new_file) != $existingSHA1 || !file_exists($mofile)) {
echo "Updating ".$code."\n";
- file_put_contents($pofile, $newFile);
+ file_put_contents($pofile, $new_file);
system(sprintf('msgmerge -U %s %s', $pofile, $laconica_pot));
system(sprintf('msgfmt -f -o %s %s', $mofile, $pofile));
} else {
@@ -79,3 +79,19 @@ foreach ($languages as $language) {
}
echo "Finished\n";
+
+
+function curl_get_file($url)
+{
+ $c = curl_init();
+ curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($c, CURLOPT_URL, $url);
+ $contents = curl_exec($c);
+ curl_close($c);
+
+ if (!empty($contents)) {
+ return $contents;
+ }
+
+ return FALSE;
+}
--
cgit v1.2.3-54-g00ecf
From b25e6139e8d6b3dcb9ca76ac8c43729dc17eedb4 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Tue, 7 Jul 2009 21:15:39 -0400
Subject: check for array before checking xmlrpc fault
---
lib/ping.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/ping.php b/lib/ping.php
index 3de541e9a..d26c73417 100644
--- a/lib/ping.php
+++ b/lib/ping.php
@@ -59,7 +59,7 @@ function ping_broadcast_notice($notice) {
$response = xmlrpc_decode($file);
- if (xmlrpc_is_fault($response)) {
+ if (is_array($response) && xmlrpc_is_fault($response)) {
common_log(LOG_WARNING,
"XML-RPC error for ping ($notify_url, $notice->id) ".
"$response[faultString] ($response[faultCode])");
--
cgit v1.2.3-54-g00ecf
From be8d77c923370ed72da85fac39908a57556557b4 Mon Sep 17 00:00:00 2001
From: Robin Millette
Date: Tue, 7 Jul 2009 23:27:34 -0400
Subject: Trac #1689: inreplyto hidden value doesn't get cleared after a
successful submit (javascript fix)
---
js/util.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/js/util.js b/js/util.js
index 9bb7c9128..7a7a5e30b 100644
--- a/js/util.js
+++ b/js/util.js
@@ -223,6 +223,7 @@ $(document).ready(function(){
}
$("#notice_data-text").val("");
$("#notice_data-attach").val("");
+ $("#notice_in-reply-to").val("");
$('#notice_data-attach_selected').remove();
counter();
}
--
cgit v1.2.3-54-g00ecf
From a626f32d8e01faa620a11e1f8370a35cc660a579 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 8 Jul 2009 01:36:12 -0400
Subject: log errors in handling notices
---
lib/stompqueuemanager.php | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index e7e1e00dd..06be2ba85 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -100,11 +100,16 @@ class StompQueueManager
$notice = Notice::staticGet('id', $frame->body);
if (empty($notice)) {
- $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice');
- $this->con->ack($frame);
- } else if ($handler->handle_notice($notice)) {
- $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created']);
+ $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice in queue '. $queue);
$this->con->ack($frame);
+ } else {
+ if ($handler->handle_notice($notice)) {
+ $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ $this->con->ack($frame);
+ } else {
+ $this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ // Don't ack; it'll get re-sent
+ }
unset($notice);
}
--
cgit v1.2.3-54-g00ecf
From 2ed9d2dac5c2eb0d44c1168cdd861c925f184fb6 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Wed, 8 Jul 2009 00:30:18 -0700
Subject: Get rid of error ('Trying to get property of non-object')
---
lib/facebookutil.php | 2 +-
lib/twitter.php | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/facebookutil.php b/lib/facebookutil.php
index 4d0df797b..5eb9534b1 100644
--- a/lib/facebookutil.php
+++ b/lib/facebookutil.php
@@ -108,11 +108,11 @@ function facebookBroadcastNotice($notice)
{
$facebook = getFacebook();
$flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE);
- $fbuid = $flink->foreign_id;
if (isFacebookBound($notice, $flink)) {
$status = null;
+ $fbuid = $flink->foreign_id;
// Get the status 'verb' (prefix) the user has set
try {
diff --git a/lib/twitter.php b/lib/twitter.php
index 3ec082686..d5eba084b 100644
--- a/lib/twitter.php
+++ b/lib/twitter.php
@@ -367,7 +367,7 @@ function broadcast_twitter($notice)
// XXX: Not sure WHERE to check whether a notice should go to
// Twitter. Should we even put in the queue if it shouldn't? --Zach
- if (!is_null($flink) && is_twitter_bound($notice, $flink)) {
+ if (is_twitter_bound($notice, $flink)) {
$fuser = $flink->getForeignUser();
$twitter_user = $fuser->nickname;
--
cgit v1.2.3-54-g00ecf
From 06bf2e2413446fe30b9b4b63bccb47d47786cde2 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Wed, 8 Jul 2009 01:02:12 -0700
Subject: Get rid of the other error trying to property on a non-obj
---
lib/facebookutil.php | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/lib/facebookutil.php b/lib/facebookutil.php
index 5eb9534b1..762d17bff 100644
--- a/lib/facebookutil.php
+++ b/lib/facebookutil.php
@@ -51,6 +51,10 @@ function updateProfileBox($facebook, $flink, $notice) {
function isFacebookBound($notice, $flink) {
+ if (empty($flink)) {
+ return false;
+ }
+
// If the user does not want to broadcast to Facebook, move along
if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) {
common_log(LOG_INFO, "Skipping notice $notice->id " .
--
cgit v1.2.3-54-g00ecf
From 8bdb7dc93c9f5f5c4befa2ce3891e4d2f2826dbf Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 8 Jul 2009 15:31:42 -0400
Subject: update the README with new information
---
README | 119 ++++++++++++++++++++++++++++++++++++++++++++---------------------
1 file changed, 80 insertions(+), 39 deletions(-)
diff --git a/README b/README
index 0f1b5a43b..97432e566 100644
--- a/README
+++ b/README
@@ -2,8 +2,8 @@
README
------
-Laconica 0.7.4 ("Can't Get There From Here")
-29 May 2009
+Laconica 0.8.0 ("Shiny Happy People")
+8 July 2009
This is the README file for Laconica, the Open Source microblogging
platform. It includes installation instructions, descriptions of
@@ -71,29 +71,52 @@ for additional terms.
New this version
================
-This is a minor bug-fix and feature release since version 0.7.3,
-released Apr 4 2009. Notable changes this version:
-
-- Improved handling of UTF-8 characters. The new code is *not* backwards
- compatible by default; see "Upgrading" below for instructions on
- converting existing databases to the correct character set.
-- Unroll joins for large queries. This greatly enhanced database
- performance -- up to 50x for some queries -- at the expense of making
- an extra DB hit for some queries.
-- Added an optional plugin to use WikiHashtags
- (http://hashtags.wikia.com/) for the sidebar on hashtag pages.
-- Optimized Twitter friend synchronization.
-- Better error handling for Ajax posting of notices, including
- HTTP errors and timeouts.
-- Experimental Comet plugin -- supports the cometd and the Bayeux
- protocol. Using this plugin, you can show "real time" updates on the
- public and tag pages. However, server configuration is complex.
-- If queues are enabled, update inboxes and memcached off-line. Speeds
- up posting considerably.
-- Correctly shorten links posted through XMPP.
-- elements for pagination, supported by some browsers like Opera.
-- Corrected date format in search API.
-- Made the public XRDS file work correctly.
+This is a major feature release since version 0.7.4, released May 31
+2009. Notable changes this version:
+
+- Support for a hosted service (status network). Multiple sites can
+ share the same codebase but use different databases.
+- OEmbed. Links to pages that support OEmbed (http://www.oembed.com/)
+ become popup links, and the media are shown in a special lightbox.
+- File attachments. Users can attach files of the size and type approved
+ by an administrator, and a shortened link will be included in the
+ notice.
+- Related notices are organized into conversations, with each reply a
+ branch in a tree. Conversations have pages and are linked to from each
+ notice in the conversation.
+- User designs. Users can specify colours and backgrounds
+ for their profile pages and other "personal" pages.
+- Group designs. Group administrators can specify similar designs for
+ group profiles and related pages.
+- Site designs. Site authors can specify a design (background and
+ colors) for the site.
+- New themes. Five new themes are added to the base release; these show
+ off the flexibility of Laconica's theming system.
+- Statistics. Public sites will periodically send usage statistics,
+ configuration options, and dependency information to Laconica dev site.
+ This will help us understand how the software is used and plan future
+ versions of the software.
+- Additional hooks. The hooks and plugins system introduced in 0.7.x was
+ expanded with additional points of access.
+- Facebook Connect. A new plugin allows logging in with Facebook Connect
+ (http://developers.facebook.com/connect.php).
+- A session handler. A new optional session handler class to manage PHP
+ sessions reliably and quickly for large sites.
+- STOMP queuing. Queue management for offline daemons has been
+ abstracted with three concrete instances. A new interface that should
+ work with STOMP servers like ActiveMQ and RabbitMQ is available, which
+ should make things scale better.
+- Group block. Group admins can block users from joining or posting to
+ a group.
+- Group aliases. Groups can be referred to with aliases, additional
+ names. For example, "!yul" and "!montreal" can be the same group.
+- Bidirectional Twitter bridge. Users can read the tweets their Twitter
+ friends post on Twitter.
+- Adaptation of WordPress.com Terms of Service (http://en.wordpress.com/tos/)
+ as default TOS for Laconica sites.
+- Better command-line handling for scripts, including standard options
+ and ability to set hostname and path from the command line.
+- Many, many bug fixes.
Prerequisites
=============
@@ -198,9 +221,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.4.tar.gz
+ tar zxf laconica-0.8.0.tar.gz
- ...which will make a laconica-0.7.4 subdirectory in your current
+ ...which will make a laconica-0.8.0 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.)
@@ -208,7 +231,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.4 /var/www/mublog
+ mv laconica-0.8.0 /var/www/mublog
This will make your Laconica instance available in the mublog path of
your server, like "http://example.net/mublog". "microblog" or
@@ -702,11 +725,11 @@ However, older installations will have the incorrect storage, and will
consequently show up "wrong" in browsers. See below for how to deal
with this situation.
-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.4. Try these step-by-step instructions; read
-to the end first before trying them.
+If you've been using Laconica 0.7, 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.8.0. 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
doing a new install.
@@ -726,20 +749,31 @@ to the end first before trying them.
5. Once all writing processes to your site are turned off, make a
final backup of the Web directory and database.
6. Move your Laconica directory to a backup spot, like "mublog.bak".
-7. Unpack your Laconica 0.6 tarball and move it to "mublog" or
+7. Unpack your Laconica 0.8.0 tarball and move it to "mublog" or
wherever your code used to be.
8. Copy the config.php file and avatar directory from your old
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. For MySQL, go to your Laconica directory and
- run the rebuilddb.sh script like this:
+10. Rebuild the database. NOTE: this step is destructive and cannot be
+ reversed. YOU CAN EASILY DESTROY YOUR SITE WITH THIS STEP. Don't
+ do it without a known-good backup!
+
+ If your database is at version 0.7.4, you can run a special upgrade
+ script:
+
+ mysql -u -p db/074to080.sql
+
+ Otherwise, go to your Laconica directory and AFTER YOU MAKE A
+ BACKUP 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.
+ that's _not_ the user Laconica runs as. Note that rebuilddb.sh drops
+ your database and rebuilds it; if there is an error you have no
+ database. Make sure you have a backup.
For PostgreSQL databases there is an equivalent, rebuilddb_psql.sh,
which operates slightly differently. Read the documentation in that
script before running it.
@@ -791,6 +825,9 @@ problem.
3. When fixup_inboxes is finished, you can set the enabled flag to
'true'.
+NOTE: we will drop support for non-inboxed sites in the 0.9.x version
+of Laconica. It's time to switch now!
+
UTF-8 Database
--------------
@@ -817,7 +854,7 @@ what to do.
Configuration options
=====================
-The sole configuration file for Laconica (excepting configurations for
+The main configuration file for Laconica (excepting configurations for
dependency software) is config.php in your Laconica directory. If you
edit any other file in the directory, like lib/common.php (where most
of the defaults are defined), you will lose your configuration options
@@ -1396,7 +1433,7 @@ if anyone's been overlooked in error.
* Ori Avtalion
* Meitar Moscovitz
* Ken Sheppardson (Trac server, man-about-town)
-* Tiago 'gouki' Faria (i18n managerx)
+* Tiago 'gouki' Faria (i18n manager)
* Sean Murphy
* Leslie Michael Orchard
* Eric Helgeson
@@ -1405,6 +1442,10 @@ if anyone's been overlooked in error.
* Tobias Diekershoff
* Dan Moore
* Fil
+* Jeff Mitchell
+* Brenda Wallace
+* Jeffery To
+* Federico Marani
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,
--
cgit v1.2.3-54-g00ecf
From 8aef0e4271dda4210901de635b4227e6dbefca18 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Wed, 8 Jul 2009 17:55:43 -0400
Subject: manually re-enqueue failed notices
---
lib/stompqueuemanager.php | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 06be2ba85..4cefba113 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -108,7 +108,10 @@ class StompQueueManager
$this->con->ack($frame);
} else {
$this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
- // Don't ack; it'll get re-sent
+ // FIXME we probably shouldn't have to do
+ // this kind of queue management ourselves
+ $this->con->ack($frame);
+ $this->enqueue($notice, $queue);
}
unset($notice);
}
--
cgit v1.2.3-54-g00ecf
From 616d68cf9481f08eae75095e2188fb7fea6d822c Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Thu, 9 Jul 2009 00:40:12 +0000
Subject: Better error handling for TwitterQueueHandler
---
lib/mail.php | 36 +++++++++++++++++++++
lib/twitter.php | 97 +++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 116 insertions(+), 17 deletions(-)
diff --git a/lib/mail.php b/lib/mail.php
index 4e1f1dbb1..c948f83ca 100644
--- a/lib/mail.php
+++ b/lib/mail.php
@@ -625,3 +625,39 @@ function mail_notify_attn($user, $notice)
common_init_locale();
mail_to_user($user, $subject, $body);
}
+
+/**
+ * Send a mail message to notify a user that her Twitter bridge link
+ * has stopped working, and therefore has been removed. This can
+ * happen when the user changes her Twitter password, or otherwise
+ * revokes access.
+ *
+ * @param User $user user whose Twitter bridge link has been removed
+ *
+ * @return boolean success flag
+ */
+
+function mail_twitter_bridge_removed($user)
+{
+ common_init_locale($user->language);
+
+ $profile = $user->getProfile();
+
+ $subject = sprintf(_('Your Twitter bridge has been disabled.'));
+
+ $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that your " .
+ 'link to Twitter has been disabled. Your Twitter credentials ' .
+ 'have either changed (did you recently change your Twitter ' .
+ 'password?) or you have otherwise revoked our access to your ' .
+ "Twitter account.\n\n" .
+ 'You can re-enable your Twitter bridge by visiting your ' .
+ "Twitter settings page:\n\n\t%2\$s\n\n" .
+ "Regards,\n%3\$s\n"),
+ $profile->getBestName(),
+ common_local_url('twittersettings'),
+ common_config('site', 'name'));
+
+ common_init_locale();
+ return mail_to_user($user, $subject, $body);
+}
+
diff --git a/lib/twitter.php b/lib/twitter.php
index d5eba084b..47af32e61 100644
--- a/lib/twitter.php
+++ b/lib/twitter.php
@@ -360,13 +360,10 @@ function is_twitter_bound($notice, $flink) {
function broadcast_twitter($notice)
{
- $success = true;
$flink = Foreign_link::getByUserID($notice->profile_id,
TWITTER_SERVICE);
- // XXX: Not sure WHERE to check whether a notice should go to
- // Twitter. Should we even put in the queue if it shouldn't? --Zach
if (is_twitter_bound($notice, $flink)) {
$fuser = $flink->getForeignUser();
@@ -401,33 +398,99 @@ function broadcast_twitter($notice)
curl_setopt_array($ch, $options);
$data = curl_exec($ch);
$errmsg = curl_error($ch);
+ $errno = curl_errno($ch);
- if ($errmsg) {
- common_debug("cURL error: $errmsg - " .
+ if (!empty($errmsg)) {
+ common_debug("cURL error ($errno): $errmsg - " .
"trying to send notice for $twitter_user.",
__FILE__);
- $success = false;
+
+ $user = $flink->getUser();
+
+ if ($errmsg == 'The requested URL returned error: 401') {
+ common_debug(sprintf('User %s (user id: %s) ' .
+ 'has bad Twitter credentials!',
+ $user->nickname, $user->id));
+
+ // Bad credentials we need to delete the foreign_link
+ // to Twitter and inform the user.
+
+ remove_twitter_link($flink);
+
+ return true;
+
+ } else {
+
+ // Some other error happened, so we should try to
+ // send again later
+
+ return false;
+ }
+
}
curl_close($ch);
- if (!$data) {
+ if (empty($data)) {
common_debug("No data returned by Twitter's " .
"API trying to send update for $twitter_user",
__FILE__);
- $success = false;
- }
- // Twitter should return a status
- $status = json_decode($data);
+ // XXX: Not sure this represents a failure to send, but it
+ // probably does
- if (!$status->id) {
- common_debug("Unexpected data returned by Twitter " .
- " API trying to send update for $twitter_user",
- __FILE__);
- $success = false;
+ return false;
+
+ } else {
+
+ // Twitter should return a status
+ $status = json_decode($data);
+
+ if (empty($status)) {
+ common_debug("Unexpected data returned by Twitter " .
+ " API trying to send update for $twitter_user",
+ __FILE__);
+
+ // XXX: Again, this could represent a failure posting
+ // or the Twitter API might just be behaving flakey.
+ // We're treating it as a failure to post.
+
+ return false;
+ }
}
}
- return $success;
+ return true;
+}
+
+function remove_twitter_link($flink)
+{
+ $user = $flink->getUser();
+
+ common_log(LOG_INFO, 'Removing Twitter bridge Foreign link for ' .
+ "user $user->nickname (user id: $user->id).");
+
+ $result = $flink->delete();
+
+ if (empty($result)) {
+ common_log(LOG_ERR, 'Could not remove Twitter bridge ' .
+ "Foreign_link for $user->nickname (user id: $user->id)!");
+ common_log_db_error($flink, 'DELETE', __FILE__);
+ }
+
+ // Notify the user that her Twitter bridge is down
+
+ $result = mail_twitter_bridge_removed($user);
+
+ if (!$result) {
+
+ $msg = 'Unable to send email to notify ' .
+ "$user->nickname (user id: $user->id) " .
+ 'that their Twitter bridge link was ' .
+ 'removed!';
+
+ common_log(LOG_WARNING, $msg);
+ }
+
}
+
--
cgit v1.2.3-54-g00ecf
From bbb25e2153c3c58053155c7258644738fc9e6ab6 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Thu, 9 Jul 2009 02:04:38 +0000
Subject: Better error handling for FacebookQueueHandler
---
lib/facebookutil.php | 75 ++++++++++++++++++++++++++++++++++++++++++++++------
lib/mail.php | 36 +++++++++++++++++++++++++
2 files changed, 103 insertions(+), 8 deletions(-)
diff --git a/lib/facebookutil.php b/lib/facebookutil.php
index 762d17bff..632ec4bad 100644
--- a/lib/facebookutil.php
+++ b/lib/facebookutil.php
@@ -90,10 +90,10 @@ function isFacebookBound($notice, $flink) {
if ($result != 1) {
$user = $flink->getUser();
- $msg = "Can't send notice $notice->id to Facebook " .
+ $msg = "Not sending notice $notice->id to Facebook " .
"because user $user->nickname hasn't given the " .
'Facebook app \'status_update\' permission.';
- common_log(LOG_INFO, $msg);
+ common_debug($msg);
$success = false;
}
@@ -118,7 +118,10 @@ function facebookBroadcastNotice($notice)
$status = null;
$fbuid = $flink->foreign_id;
+ $user = $flink->getUser();
+
// Get the status 'verb' (prefix) the user has set
+
try {
$prefix = $facebook->api_client->
data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $fbuid);
@@ -126,23 +129,79 @@ function facebookBroadcastNotice($notice)
$status = "$prefix $notice->content";
} catch(FacebookRestClientException $e) {
- common_log(LOG_ERR, $e->getMessage());
- return false;
+ common_log(LOG_WARNING, $e->getMessage());
+ common_log(LOG_WARNING,
+ 'Unable to get the status verb setting from Facebook ' .
+ "for $user->nickname (user id: $user->id).");
}
- // Okay, we're good to go!
+ // Okay, we're good to go, update the FB status
try {
$facebook->api_client->users_setStatus($status, $fbuid, false, true);
- updateProfileBox($facebook, $flink, $notice);
} catch(FacebookRestClientException $e) {
common_log(LOG_ERR, $e->getMessage());
- return false;
+ common_log(LOG_ERR,
+ 'Unable to update Facebook status for ' .
+ "$user->nickname (user id: $user->id)!");
- // Should we remove flink if this fails?
+ $code = $e->getCode();
+
+ if ($code >= 200) {
+
+ // 200 The application does not have permission to operate on the passed in uid parameter.
+ // 250 Updating status requires the extended permission status_update.
+ // see: http://wiki.developers.facebook.com/index.php/Users.setStatus#Example_Return_XML
+
+ remove_facebook_app($flink);
+ }
+
+ }
+
+ // Now try to update the profile box
+
+ try {
+ updateProfileBox($facebook, $flink, $notice);
+ } catch(FacebookRestClientException $e) {
+ common_log(LOG_WARNING, $e->getMessage());
+ common_log(LOG_WARNING,
+ 'Unable to update Facebook profile box for ' .
+ "$user->nickname (user id: $user->id).");
}
}
return true;
}
+
+function remove_facebook_app($flink)
+{
+
+ $user = $flink->getUser();
+
+ common_log(LOG_INFO, 'Removing Facebook App Foreign link for ' .
+ "user $user->nickname (user id: $user->id).");
+
+ $result = $flink->delete();
+
+ if (empty($result)) {
+ common_log(LOG_ERR, 'Could not remove Facebook App ' .
+ "Foreign_link for $user->nickname (user id: $user->id)!");
+ common_log_db_error($flink, 'DELETE', __FILE__);
+ }
+
+ // Notify the user that we are removing their FB app access
+
+ $result = mail_facebook_app_removed($user);
+
+ if (!$result) {
+
+ $msg = 'Unable to send email to notify ' .
+ "$user->nickname (user id: $user->id) " .
+ 'that their Facebook app link was ' .
+ 'removed!';
+
+ common_log(LOG_WARNING, $msg);
+ }
+
+}
diff --git a/lib/mail.php b/lib/mail.php
index c948f83ca..90ee3c992 100644
--- a/lib/mail.php
+++ b/lib/mail.php
@@ -661,3 +661,39 @@ function mail_twitter_bridge_removed($user)
return mail_to_user($user, $subject, $body);
}
+/**
+ * Send a mail message to notify a user that her Facebook Application
+ * access has been removed.
+ *
+ * @param User $user user whose Facebook app link has been removed
+ *
+ * @return boolean success flag
+ */
+
+function mail_facebook_app_removed($user)
+{
+ common_init_locale($user->language);
+
+ $profile = $user->getProfile();
+
+ $site_name = common_config('site', 'name');
+
+ $subject = sprintf(
+ _('Your %s Facebook application access has been disabled.',
+ $site_name));
+
+ $body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " .
+ 'unable to update your Facebook status from %s, and have disabled ' .
+ 'the Facebook application for your account. This may be because ' .
+ 'you have removed the Facebook application\'s authorization, or ' .
+ 'have deleted your Facebook account. You can re-enable the ' .
+ 'Facebook application and automatic status updating by ' .
+ "re-installing the %1\$s Facebook application.\n\nRegards,\n\n%1\$s"),
+ $site_name);
+
+ common_init_locale();
+ return mail_to_user($user, $subject, $body);
+
+}
+
+
--
cgit v1.2.3-54-g00ecf
From d77a2ee6adce4175e20992342623d72842d7593b Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 09:31:10 -0400
Subject: send a ping from the xmppdaemon
---
scripts/xmppdaemon.php | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/scripts/xmppdaemon.php b/scripts/xmppdaemon.php
index bd1918ca9..488b4b514 100755
--- a/scripts/xmppdaemon.php
+++ b/scripts/xmppdaemon.php
@@ -60,7 +60,9 @@ class XMPPDaemon extends Daemon
$this->resource = common_config('xmpp', 'resource') . 'daemon';
}
- $this->log(LOG_INFO, "INITIALIZE XMPPDaemon {$this->user}@{$this->server}/{$this->resource}");
+ $this->jid = $this->user.'@'.$this->server.'/'.$this->resource;
+
+ $this->log(LOG_INFO, "INITIALIZE XMPPDaemon {$this->jid}");
}
function connect()
@@ -106,10 +108,25 @@ class XMPPDaemon extends Daemon
$this->log(LOG_DEBUG, "Beginning processing loop.");
- $this->conn->process();
+ while ($this->conn->processTime(60)) {
+ $this->sendPing();
+ }
}
}
+ function sendPing()
+ {
+ if (!isset($this->pingid)) {
+ $this->pingid = 0;
+ } else {
+ $this->pingid++;
+ }
+
+ $this->log(LOG_DEBUG, "Sending ping #{$this->pingid}");
+
+ $this->conn->send("");
+ }
+
function handle_reconnect(&$pl)
{
$this->log(LOG_DEBUG, "Got reconnection callback.");
--
cgit v1.2.3-54-g00ecf
From a5212dd6e32433bac4c5085e8ffb3c8c27a01936 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 10:11:13 -0400
Subject: timeouts and pings for xmppqueuehandlers
---
lib/xmppqueuehandler.php | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index c8b5ad1fb..9b1a6989e 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -30,6 +30,8 @@ require_once(INSTALLDIR.'/lib/queuehandler.php');
class XmppQueueHandler extends QueueHandler
{
+ var $pingid = 0;
+
function start()
{
# Low priority; we don't want to receive messages
@@ -44,6 +46,11 @@ class XmppQueueHandler extends QueueHandler
return !is_null($this->conn);
}
+ function timeout()
+ {
+ return 10;
+ }
+
function handle_reconnect(&$pl)
{
$this->conn->processUntil('session_start');
@@ -55,7 +62,9 @@ class XmppQueueHandler extends QueueHandler
# Process the queue for as long as needed
try {
if ($this->conn) {
+ $this->log(LOG_DEBUG, "Servicing the XMPP queue.");
$this->conn->processTime($timeout);
+ $this->sendPing();
}
} catch (XMPPHP_Exception $e) {
$this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
@@ -63,6 +72,22 @@ class XmppQueueHandler extends QueueHandler
}
}
+ function sendPing()
+ {
+ $jid = jabber_daemon_address().'/'.$this->_id.$this->transport();
+ $server = common_config('xmpp', 'server');
+
+ if (!isset($this->pingid)) {
+ $this->pingid = 0;
+ } else {
+ $this->pingid++;
+ }
+
+ $this->log(LOG_DEBUG, "Sending ping #{$this->pingid}");
+
+ $this->conn->send("");
+ }
+
function forward_message(&$pl)
{
if ($pl['type'] != 'chat') {
--
cgit v1.2.3-54-g00ecf
From d2e83b6a67fec311f9bc36a7d886f40169d9de15 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 10:40:24 -0400
Subject: give processtime a minimum of 1s
---
lib/xmppqueuehandler.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index 9b1a6989e..7d14422c6 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -63,7 +63,7 @@ class XmppQueueHandler extends QueueHandler
try {
if ($this->conn) {
$this->log(LOG_DEBUG, "Servicing the XMPP queue.");
- $this->conn->processTime($timeout);
+ $this->conn->processTime(max($timeout, 1));
$this->sendPing();
}
} catch (XMPPHP_Exception $e) {
--
cgit v1.2.3-54-g00ecf
From d7611009b11c489abbc7c52d51ec859fd9fa5600 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 11:16:50 -0400
Subject: Revert "give processtime a minimum of 1s"
This reverts commit d2e83b6a67fec311f9bc36a7d886f40169d9de15.
---
lib/xmppqueuehandler.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index 7d14422c6..9b1a6989e 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -63,7 +63,7 @@ class XmppQueueHandler extends QueueHandler
try {
if ($this->conn) {
$this->log(LOG_DEBUG, "Servicing the XMPP queue.");
- $this->conn->processTime(max($timeout, 1));
+ $this->conn->processTime($timeout);
$this->sendPing();
}
} catch (XMPPHP_Exception $e) {
--
cgit v1.2.3-54-g00ecf
From 1daad01f362d72e6ed89f415546220016c32404a Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 11:40:01 -0400
Subject: slightly better timing
---
lib/stompqueuemanager.php | 7 +++++--
lib/xmppqueuehandler.php | 9 ++++++++-
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 4cefba113..4d89806f8 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -117,9 +117,12 @@ class StompQueueManager
}
unset($frame);
- }
- $handler->idle(0);
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+
+ } else {
+ $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ }
}
$this->con->unsubscribe($this->_queueName($queue));
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index 9b1a6989e..cbcfe5e1c 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -21,6 +21,8 @@ if (!defined('LACONICA')) { exit(1); }
require_once(INSTALLDIR.'/lib/queuehandler.php');
+define('PING_INTERVAL', 120);
+
/**
* Common superclass for all XMPP-using queue handlers. They all need to
* service their message queues on idle, and forward any incoming messages
@@ -31,6 +33,7 @@ require_once(INSTALLDIR.'/lib/queuehandler.php');
class XmppQueueHandler extends QueueHandler
{
var $pingid = 0;
+ var $lastping = null;
function start()
{
@@ -64,7 +67,11 @@ class XmppQueueHandler extends QueueHandler
if ($this->conn) {
$this->log(LOG_DEBUG, "Servicing the XMPP queue.");
$this->conn->processTime($timeout);
- $this->sendPing();
+ $now = time();
+ if (empty($this->lastping) || $now - $this->lastping > PING_INTERVAL) {
+ $this->sendPing();
+ $this->lastping = $now;
+ }
}
} catch (XMPPHP_Exception $e) {
$this->log(LOG_ERR, "Got an XMPPHP_Exception: " . $e->getMessage());
--
cgit v1.2.3-54-g00ecf
From 03200235b1a1bba56c24e1bb659023ba24265eb3 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 12:09:20 -0400
Subject: use select() to bring down xmpp latency
---
lib/jabber.php | 10 ++++++-
lib/queuehandler.php | 5 ++++
lib/stompqueuemanager.php | 73 +++++++++++++++++++++++++++++++++--------------
lib/xmppqueuehandler.php | 5 ++++
4 files changed, 71 insertions(+), 22 deletions(-)
diff --git a/lib/jabber.php b/lib/jabber.php
index 7d584ad01..e15076160 100644
--- a/lib/jabber.php
+++ b/lib/jabber.php
@@ -77,6 +77,14 @@ function jabber_daemon_address()
return common_config('xmpp', 'user') . '@' . common_config('xmpp', 'server');
}
+class Sharing_XMPP extends XMPPHP_XMPP
+{
+ function getSocket()
+ {
+ return $this->socket;
+ }
+}
+
/**
* connect the configured Jabber account to the configured server
*
@@ -89,7 +97,7 @@ function jabber_connect($resource=null)
{
static $conn = null;
if (!$conn) {
- $conn = new XMPPHP_XMPP(common_config('xmpp', 'host') ?
+ $conn = new Sharing_XMPP(common_config('xmpp', 'host') ?
common_config('xmpp', 'host') :
common_config('xmpp', 'server'),
common_config('xmpp', 'port'),
diff --git a/lib/queuehandler.php b/lib/queuehandler.php
index c0f38f4e3..c2ff10f32 100644
--- a/lib/queuehandler.php
+++ b/lib/queuehandler.php
@@ -115,5 +115,10 @@ class QueueHandler extends Daemon
{
common_log($level, $this->class_name() . ' ('. $this->get_id() .'): '.$msg);
}
+
+ function getSockets()
+ {
+ return array();
+ }
}
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 4d89806f8..7da7c0011 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -30,6 +30,14 @@
require_once 'Stomp.php';
+class LiberalStomp extends Stomp
+{
+ function getSocket()
+ {
+ return $this->_socket;
+ }
+}
+
class StompQueueManager
{
var $server = null;
@@ -50,7 +58,7 @@ class StompQueueManager
{
if (empty($this->con)) {
$this->_log(LOG_INFO, "Connecting to '$this->server' as '$this->username'...");
- $this->con = new Stomp($this->server);
+ $this->con = new LiberalStomp($this->server);
if ($this->con->connect($this->username, $this->password)) {
$this->_log(LOG_INFO, "Connected.");
@@ -94,34 +102,57 @@ class StompQueueManager
while (true) {
- $frame = $this->con->readFrame();
+ // Wait for something on one of our sockets
- if (!empty($frame)) {
- $notice = Notice::staticGet('id', $frame->body);
+ $stompsock = $this->con->getSocket();
- if (empty($notice)) {
- $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice in queue '. $queue);
- $this->con->ack($frame);
- } else {
- if ($handler->handle_notice($notice)) {
- $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ $handsocks = $handler->getSockets();
+
+ $this->_log(LOG_DEBUG, "Got ".count($handsocks)." sockets from handler.");
+ $this->_log(LOG_DEBUG, print_r($handsocks, true));
+
+ $socks = array_merge(array($stompsock), $handsocks);
+
+ $read = $socks;
+ $write = array();
+ $except = array();
+
+ $this->_log(LOG_DEBUG, "Starting select");
+ $ready = stream_select($read, $write, $except, $handler->timeout(), 0);
+ $this->_log(LOG_DEBUG, "Finished select with value '$ready'");
+
+ if (!$ready || $read[0] !== $stompsock) {
+ $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ } else {
+ $frame = $this->con->readFrame();
+
+ if (!empty($frame)) {
+ $notice = Notice::staticGet('id', $frame->body);
+
+ if (empty($notice)) {
+ $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice in queue '. $queue);
$this->con->ack($frame);
} else {
- $this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
- // FIXME we probably shouldn't have to do
- // this kind of queue management ourselves
- $this->con->ack($frame);
- $this->enqueue($notice, $queue);
+ if ($handler->handle_notice($notice)) {
+ $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ $this->con->ack($frame);
+ } else {
+ $this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ // FIXME we probably shouldn't have to do
+ // this kind of queue management ourselves
+ $this->con->ack($frame);
+ $this->enqueue($notice, $queue);
+ }
+ unset($notice);
}
- unset($notice);
- }
- unset($frame);
+ unset($frame);
- $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
- } else {
- $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ } else {
+ $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ }
}
}
diff --git a/lib/xmppqueuehandler.php b/lib/xmppqueuehandler.php
index cbcfe5e1c..77d476c30 100644
--- a/lib/xmppqueuehandler.php
+++ b/lib/xmppqueuehandler.php
@@ -126,4 +126,9 @@ class XmppQueueHandler extends QueueHandler
return jabber_daemon_address() . '/' . common_config('xmpp','resource') . 'daemon';
}
}
+
+ function getSockets()
+ {
+ return array($this->conn->getSocket());
+ }
}
--
cgit v1.2.3-54-g00ecf
From eccab870444463734b8fcd7ec0f1cf149a0f6a57 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 12:33:38 -0400
Subject: slightly more robust select() logic
---
lib/stompqueuemanager.php | 70 +++++++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 35 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 7da7c0011..ac55f9733 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -108,55 +108,55 @@ class StompQueueManager
$handsocks = $handler->getSockets();
- $this->_log(LOG_DEBUG, "Got ".count($handsocks)." sockets from handler.");
- $this->_log(LOG_DEBUG, print_r($handsocks, true));
-
$socks = array_merge(array($stompsock), $handsocks);
$read = $socks;
$write = array();
$except = array();
- $this->_log(LOG_DEBUG, "Starting select");
$ready = stream_select($read, $write, $except, $handler->timeout(), 0);
- $this->_log(LOG_DEBUG, "Finished select with value '$ready'");
- if (!$ready || $read[0] !== $stompsock) {
+ if ($ready === false) {
+ $this->_log(LOG_ERR, "Error selecting on sockets");
+ } else if ($ready > 0) {
+ if (in_array($stompsock, $read)) {
+ $this->_handleNotice($queue, $handler);
+ }
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+ } else { // timeout
$handler->idle(QUEUE_HANDLER_MISS_IDLE);
- } else {
- $frame = $this->con->readFrame();
-
- if (!empty($frame)) {
- $notice = Notice::staticGet('id', $frame->body);
-
- if (empty($notice)) {
- $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice in queue '. $queue);
- $this->con->ack($frame);
- } else {
- if ($handler->handle_notice($notice)) {
- $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
- $this->con->ack($frame);
- } else {
- $this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
- // FIXME we probably shouldn't have to do
- // this kind of queue management ourselves
- $this->con->ack($frame);
- $this->enqueue($notice, $queue);
- }
- unset($notice);
- }
-
- unset($frame);
-
- $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+ }
+ }
+
+ $this->con->unsubscribe($this->_queueName($queue));
+ }
+ function _handleNotice($queue, $handler)
+ {
+ $frame = $this->con->readFrame();
+
+ if (!empty($frame)) {
+ $notice = Notice::staticGet('id', $frame->body);
+
+ if (empty($notice)) {
+ $this->_log(LOG_WARNING, 'Got ID '. $frame->body .' for non-existent notice in queue '. $queue);
+ $this->con->ack($frame);
+ } else {
+ if ($handler->handle_notice($notice)) {
+ $this->_log(LOG_INFO, 'Successfully handled notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ $this->con->ack($frame);
} else {
- $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ $this->_log(LOG_WARNING, 'Failed handling notice '. $notice->id .' posted at ' . $frame->headers['created'] . ' in queue '. $queue);
+ // FIXME we probably shouldn't have to do
+ // this kind of queue management ourselves
+ $this->con->ack($frame);
+ $this->enqueue($notice, $queue);
}
+ unset($notice);
}
- }
- $this->con->unsubscribe($this->_queueName($queue));
+ unset($frame);
+ }
}
function _queueName($queue)
--
cgit v1.2.3-54-g00ecf
From 031146f4c757ca00fb9f528abf69ef4b229bdc18 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 12:49:37 -0400
Subject: yet another select() refinement
---
lib/stompqueuemanager.php | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index ac55f9733..d13af3fa5 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -122,9 +122,12 @@ class StompQueueManager
if (in_array($stompsock, $read)) {
$this->_handleNotice($queue, $handler);
}
- $handler->idle(QUEUE_HANDLER_HIT_IDLE);
- } else { // timeout
- $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ foreach ($handsocks as $sock) {
+ if (in_array($sock, $read)) {
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+ break;
+ }
+ }
}
}
--
cgit v1.2.3-54-g00ecf
From be0b1495179f1cc1d96ea1849445a19d559283e2 Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Thu, 9 Jul 2009 17:01:45 +0000
Subject: Updated max-width values for attachment view
---
js/util.js | 2 +-
theme/base/css/display.css | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/js/util.js b/js/util.js
index 7a7a5e30b..bbcbc0bbb 100644
--- a/js/util.js
+++ b/js/util.js
@@ -283,7 +283,7 @@ function NoticeAttachments() {
},
timeout : 0,
autoHide : true,
- css : {'max-width':'502px', 'top':'22.5%', 'left':'32.5%'}
+ css : {'max-width':'542px', 'top':'22.5%', 'left':'32.5%'}
};
$('#content .notice a.attachment').click(function() {
diff --git a/theme/base/css/display.css b/theme/base/css/display.css
index e9f4beaae..3426e71c0 100644
--- a/theme/base/css/display.css
+++ b/theme/base/css/display.css
@@ -1020,7 +1020,7 @@ font-weight:bold;
padding:0;
}
#jOverlayContent h1 {
-max-width:475px;
+max-width:425px;
}
#jOverlayContent #content {
border-radius:7px;
--
cgit v1.2.3-54-g00ecf
From 69574591d0ac429475b1099e8d9f3e46f7a004ea Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 9 Jul 2009 13:18:57 -0400
Subject: Notice attachments are enclosures in feeds (Atom, RSS 1.0/RDF, and
RSS 2.0).
http://laconi.ca/trac/ticket/1690
---
classes/Notice.php | 12 ++++++++++++
lib/rssaction.php | 9 +++++++++
lib/twitterapi.php | 21 ++++++++++++++++++++-
3 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/classes/Notice.php b/classes/Notice.php
index 5ec0692d9..e975cab93 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -1164,6 +1164,18 @@ class Notice extends Memcached_DataObject
}
$tag->free();
+ # Enclosures
+ $attachments = $this->attachments();
+ if($attachments){
+ foreach($attachments as $attachment){
+ $attributes = array('rel'=>'enclosure','href'=>$attachment->url,'type'=>$attachment->mimetype,'length'=>$attachment->size);
+ if($attachment->title){
+ $attributes['title']=$attachment->title;
+ }
+ $xs->element('link', $attributes, null);
+ }
+ }
+
$xs->elementEnd('entry');
return $xs->getString();
diff --git a/lib/rssaction.php b/lib/rssaction.php
index 0c8188e88..fe3fd6f4a 100644
--- a/lib/rssaction.php
+++ b/lib/rssaction.php
@@ -216,6 +216,13 @@ class Rss10Action extends Action
$replyurl = common_local_url('shownotice', array('notice' => $notice->reply_to));
$this->element('sioc:reply_of', array('rdf:resource' => $replyurl));
}
+ $attachments = $notice->attachments();
+ if($attachments){
+ foreach($attachments as $attachment){
+ $this->element('enc:enclosure', array('rdf:resource'=>$attachment->url,'enc:type'=>$attachment->mimetype,'enc:length'=>$attachment->size), null);
+ }
+ }
+
$this->elementEnd('item');
$this->creators[$creator_uri] = $profile;
}
@@ -251,6 +258,8 @@ class Rss10Action extends Action
'http://creativecommons.org/ns#',
'xmlns:content' =>
'http://purl.org/rss/1.0/modules/content/',
+ 'xmlns:enc' =>
+ 'http://purl.oclc.org/net/rss_2.0/enc#',
'xmlns:foaf' =>
'http://xmlns.com/foaf/0.1/',
'xmlns:sioc' =>
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index 40e5b5067..8f902cbca 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -207,7 +207,6 @@ class TwitterapiAction extends Action
function twitter_rss_entry_array($notice)
{
-
$profile = $notice->getProfile();
$entry = array();
@@ -224,6 +223,19 @@ class TwitterapiAction extends Action
$entry['updated'] = $entry['published'];
$entry['author'] = $profile->getBestName();
+ # Enclosure
+ $attachments = $notice->attachments();
+ if($attachments){
+ $entry['enclosures']=array();
+ foreach($attachments as $attachment){
+ $enclosure=array();
+ $enclosure['url']=$attachment->url;
+ $enclosure['mimetype']=$attachment->mimetype;
+ $enclosure['size']=$attachment->size;
+ $entry['enclosures'][]=$enclosure;
+ }
+ }
+
# RSS Item specific
$entry['description'] = $entry['content'];
$entry['pubDate'] = common_date_rfc2822($notice->created);
@@ -378,6 +390,13 @@ class TwitterapiAction extends Action
$this->element('pubDate', null, $entry['pubDate']);
$this->element('guid', null, $entry['guid']);
$this->element('link', null, $entry['link']);
+
+ # RSS only supports 1 enclosure per item
+ if($entry['enclosures']){
+ $enclosure = $entry['enclosures'][0];
+ $this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null);
+ }
+
$this->elementEnd('item');
}
--
cgit v1.2.3-54-g00ecf
From fc3442a041a43f2df29deedc0ad96fbd6ba92385 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 13:26:09 -0400
Subject: Let the queue handlers drain their xmpp queues
---
lib/stompqueuemanager.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index d13af3fa5..359f6d9d8 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -124,7 +124,8 @@ class StompQueueManager
}
foreach ($handsocks as $sock) {
if (in_array($sock, $read)) {
- $handler->idle(QUEUE_HANDLER_HIT_IDLE);
+ // let it really handle this stuff
+ $handler->idle(QUEUE_HANDLER_MISS_IDLE);
break;
}
}
--
cgit v1.2.3-54-g00ecf
From 43e0b308fdb32ed434d25b54b4a84b88d329d1bf Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 13:39:22 -0400
Subject: Revert "Let the queue handlers drain their xmpp queues"
This reverts commit fc3442a041a43f2df29deedc0ad96fbd6ba92385.
---
lib/stompqueuemanager.php | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index 359f6d9d8..d13af3fa5 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -124,8 +124,7 @@ class StompQueueManager
}
foreach ($handsocks as $sock) {
if (in_array($sock, $read)) {
- // let it really handle this stuff
- $handler->idle(QUEUE_HANDLER_MISS_IDLE);
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
break;
}
}
--
cgit v1.2.3-54-g00ecf
From 2197d0bacf44d0f2d0ab1a58446c9f4c6bd14190 Mon Sep 17 00:00:00 2001
From: Sarven Capadisli
Date: Thu, 9 Jul 2009 19:12:50 +0000
Subject: Added width/height attribute and values for the creative commons
image
---
lib/action.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/lib/action.php b/lib/action.php
index da5b48858..95ee10c64 100644
--- a/lib/action.php
+++ b/lib/action.php
@@ -772,7 +772,9 @@ class Action extends HTMLOutputter // lawsuit
$this->elementStart('p');
$this->element('img', array('id' => 'license_cc',
'src' => common_config('license', 'image'),
- 'alt' => common_config('license', 'title')));
+ 'alt' => common_config('license', 'title'),
+ 'width' => '80',
+ 'height' => '15'));
//TODO: This is dirty: i18n
$this->text(_('All '.common_config('site', 'name').' content and data are available under the '));
$this->element('a', array('class' => 'license',
--
cgit v1.2.3-54-g00ecf
From 0828fde51ccb1a5629ab33dd23834070b95c0f37 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 15:25:59 -0400
Subject: one more shot at servicing queues
---
lib/stompqueuemanager.php | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/lib/stompqueuemanager.php b/lib/stompqueuemanager.php
index d13af3fa5..46baeb5c7 100644
--- a/lib/stompqueuemanager.php
+++ b/lib/stompqueuemanager.php
@@ -122,12 +122,7 @@ class StompQueueManager
if (in_array($stompsock, $read)) {
$this->_handleNotice($queue, $handler);
}
- foreach ($handsocks as $sock) {
- if (in_array($sock, $read)) {
- $handler->idle(QUEUE_HANDLER_HIT_IDLE);
- break;
- }
- }
+ $handler->idle(QUEUE_HANDLER_HIT_IDLE);
}
}
--
cgit v1.2.3-54-g00ecf
From b78801becbd963a57e3a5b5db9c2f71c0f078e14 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 18:19:13 -0400
Subject: correct the newuser default setting in common.php
---
lib/common.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/common.php b/lib/common.php
index 14be747bc..5bfb35583 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -206,7 +206,7 @@ $config =
'inboxes' =>
array('enabled' => true), # on by default for new sites
'newuser' =>
- array('subscribe' => null,
+ array('default' => null,
'welcome' => null),
'snapshot' =>
array('run' => 'web',
--
cgit v1.2.3-54-g00ecf
From f2b12c6084d1faff5e2c429279a2eed7987f7c34 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 18:19:24 -0400
Subject: update the README for 0.8.0
---
README | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 86 insertions(+), 2 deletions(-)
diff --git a/README b/README
index 97432e566..8622d3797 100644
--- a/README
+++ b/README
@@ -535,6 +535,11 @@ All the daemons write their process IDs (pids) to /var/run/ by
default. This can be useful for starting, stopping, and monitoring the
daemons.
+With version 0.8.0, it's now possible to use a STOMP server instead of
+our kind of hacky home-grown DB-based queue solution. See the "queues"
+config section below for how to configure to use STOMP. As of this
+writing, the software has been tested with ActiveMQ (
+
Twitter Friends Syncing
-----------------------
@@ -892,6 +897,8 @@ fancy: whether or not your site uses fancy URLs (see Fancy URLs
logfile: full path to a file for Laconica to save logging
information to. You may want to use this if you don't have
access to syslog.
+logdebug: whether to log additional debug info like backtraces on
+ hard errors. Default false.
locale_path: full path to the directory for locale data. Unless you
store all your locale data in one place, you probably
don't need to use this.
@@ -946,6 +953,12 @@ sslserver: use an alternate server name for SSL URLs, like
shorturllength: Length of URL at which URLs in a message exceeding 140
characters will be sent to the user's chosen
shortening service.
+design: a default design (colors and background) for the site.
+ Sub-items are: backgroundcolor, contentcolor, sidebarcolor,
+ textcolor, linkcolor, backgroundimage, disposition.
+dupelimit: minimum time allowed for one person to say the same thing
+ twice. Default 60s. Anything lower is considered a user
+ or UI error.
db
--
@@ -996,6 +1009,10 @@ appname: The name that Laconica uses to log messages. By default it's
"laconica", but if you have more than one installation on the
server, you may want to change the name for each instance so
you can track log messages more easily.
+priority: level to log at. Currently ignored.
+facility: what syslog facility to used. Defaults to LOG_USER, only
+ reset if you know what syslog is and have a good reason
+ to change it.
queue
-----
@@ -1005,7 +1022,19 @@ sending out SMS email or XMPP messages, for off-line processing. See
'Queues and daemons' above for how to set this up.
enabled: Whether to uses queues. Defaults to false.
-
+subsystem: Which kind of queueserver to use. Values include "db" for
+ our hacked-together database queuing (no other server
+ required) and "stomp" for a stomp server.
+stomp_server: "broker URI" for stomp server. Something like
+ "tcp://hostname:61613". More complicated ones are
+ possible; see your stomp server's documentation for
+ details.
+queue_basename: a root name to use for queues (stomp only). Typically
+ something like '/queue/sitename/' makes sense.
+stomp_username: username for connecting to the stomp server; defaults
+ to null.
+stomp_password: password for connecting to the stomp server; defaults
+ to null.
license
-------
@@ -1075,6 +1104,8 @@ localonly: If set to true, only messages posted by users of this
blacklist: An array of IDs of users to hide from the public stream.
Useful if you have someone making excessive Twitterfeed posts
to the site, other kinds of automated posts, testing bots, etc.
+autosource: Sources of notices that are from automatic posters, and thus
+ should be kept off the public timeline. Default empty.
theme
-----
@@ -1137,6 +1168,15 @@ dropoff: Decay factor for tag listing, in seconds.
Defaults to exponential decay over ten days; you can twiddle
with it to try and get better results for your site.
+popular
+-------
+
+Settings for the "popular" section of the site.
+
+dropoff: Decay factor for popularity listing, in seconds.
+ Defaults to exponential decay over ten days; you can twiddle
+ with it to try and get better results for your site.
+
daemon
------
@@ -1190,6 +1230,7 @@ source: The name to use for the source of posts to Twitter. Defaults
Twitter , you can use
that here instead. Status updates on Twitter will then have
links to your site.
+taguri: base for tag:// URIs. Defaults to site-server + ',2009'.
inboxes
-------
@@ -1276,7 +1317,7 @@ detection.
supported: an array of mime types you accept to store and distribute,
like 'image/gif', 'video/mpeg', 'audio/mpeg', etc. Make sure you
- setup your server to properly reckognize the types you want to
+ setup your server to properly recognize the types you want to
support.
uploads: false to disable uploading files with notices (true by default).
filecommand: The required MIME_Type library may need to use the 'file'
@@ -1297,6 +1338,17 @@ user_quota: total size in bytes a user can store on this server. Each user
not exceed the user_quota.
monthly_quota: total size permitted in the current month. This is the total
size in bytes that a user can upload each month.
+dir: directory accessible to the Web process where uploads should go.
+ Defaults to the 'file' subdirectory of the install directory, which
+ should be writeable by the Web user.
+server: server name to use when creating URLs for uploaded files.
+ Defaults to null, meaning to use the default Web server. Using
+ a virtual server here can speed up Web performance.
+path: URL path, relative to the server, to find files. Defaults to
+ main path + '/file/'.
+filecommand: command to use for determining the type of a file. May be
+ skipped if fileinfo extension is installed. Defaults to
+ '/usr/bin/file'.
group
-----
@@ -1337,6 +1389,38 @@ handle: boolean. Whether we should register our own PHP session-handling
debug: whether to output debugging info for session storage. Can help
with weird session bugs, sometimes. Default false.
+background
+----------
+
+Users can upload backgrounds for their pages; this section defines
+their use.
+
+server: the server to use for background. Using a separate (even
+ virtual) server for this can speed up load times. Default is
+ null; same as site server.
+dir: directory to write backgrounds too. Default is '/background/'
+ subdir of install dir.
+path: path to backgrounds. Default is sub-path of install path; note
+ that you may need to change this if you change site-path too.
+
+twitterbridge
+-------------
+
+A bi-direction bridge to Twitter (http://twitter.com/).
+
+enabled: default false. If true, will show user's Twitter friends'
+ notices in their inbox and faves pages, only to the user. You
+ must also run the twitterstatusfetcher.php script.
+
+ping
+----
+
+Using the "XML-RPC Ping" method initiated by weblogs.com, the site can
+notify third-party servers of updates.
+
+notify: an array of URLs for ping endpoints. Default is the empty
+ array (no notification).
+
Troubleshooting
===============
--
cgit v1.2.3-54-g00ecf
From efd94b4e5423c72a65cdd6acd252e5d00ec98967 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 18:22:10 -0400
Subject: change version number to 0.8.0
---
lib/common.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/common.php b/lib/common.php
index 5bfb35583..832667d81 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -19,7 +19,7 @@
if (!defined('LACONICA')) { exit(1); }
-define('LACONICA_VERSION', '0.8.0dev');
+define('LACONICA_VERSION', '0.8.0');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
--
cgit v1.2.3-54-g00ecf
From 8250006fbfdc120a4766f85ff5d6ee79798d626d Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Thu, 9 Jul 2009 18:42:19 -0400
Subject: When a notice is posted with an attachment, the facebook stream
update has media displayed inline, or as links.
http://laconi.ca/trac/ticket/1685
---
actions/facebookhome.php | 4 +--
actions/facebooklogin.php | 4 +--
actions/facebooksettings.php | 4 +--
lib/facebookaction.php | 15 ++---------
lib/facebookutil.php | 61 +++++++++++++++++++++++++++++++++++++++++---
5 files changed, 65 insertions(+), 23 deletions(-)
diff --git a/actions/facebookhome.php b/actions/facebookhome.php
index 34989c978..6d8d0745d 100644
--- a/actions/facebookhome.php
+++ b/actions/facebookhome.php
@@ -57,7 +57,7 @@ class FacebookhomeAction extends FacebookAction
// If this is the first time the user has started the app
// prompt for Facebook status update permission
- if (!$this->facebook->api_client->users_hasAppPermission('status_update')) {
+ if (!$this->facebook->api_client->users_hasAppPermission('publish_stream')) {
if ($this->facebook->api_client->data_getUserPreference(
FACEBOOK_PROMPTED_UPDATE_PREF) != 'true') {
@@ -203,7 +203,7 @@ class FacebookhomeAction extends FacebookAction
$api_key = common_config('facebook', 'apikey');
$auth_url = 'http://www.facebook.com/authorize.php?api_key=' .
- $api_key . '&v=1.0&ext_perm=status_update&next=' . $next .
+ $api_key . '&v=1.0&ext_perm=publish_stream&next=' . $next .
'&next_cancel=' . $next . '&submit=skip';
$this->elementStart('span', array('class' => 'facebook-button'));
diff --git a/actions/facebooklogin.php b/actions/facebooklogin.php
index 22007da4f..aa86cfbc0 100644
--- a/actions/facebooklogin.php
+++ b/actions/facebooklogin.php
@@ -31,7 +31,7 @@ class FacebookinviteAction extends FacebookAction
$this->error = $error;
if ($this->flink) {
- if (!$this->facebook->api_client->users_hasAppPermission('status_update') &&
+ if (!$this->facebook->api_client->users_hasAppPermission('publish_stream') &&
$this->facebook->api_client->data_getUserPreference(
FACEBOOK_PROMPTED_UPDATE_PREF) == 'true') {
@@ -60,7 +60,7 @@ class FacebookinviteAction extends FacebookAction
// If this is the first time the user has started the app
// prompt for Facebook status update permission
- if (!$this->facebook->api_client->users_hasAppPermission('status_update')) {
+ if (!$this->facebook->api_client->users_hasAppPermission('publish_stream')) {
if ($this->facebook->api_client->data_getUserPreference(
FACEBOOK_PROMPTED_UPDATE_PREF) != 'true') {
diff --git a/actions/facebooksettings.php b/actions/facebooksettings.php
index ee2c279ab..c3b364743 100644
--- a/actions/facebooksettings.php
+++ b/actions/facebooksettings.php
@@ -78,7 +78,7 @@ class FacebooksettingsAction extends FacebookAction
}
}
- if ($this->facebook->api_client->users_hasAppPermission('status_update')) {
+ if ($this->facebook->api_client->users_hasAppPermission('publish_stream')) {
$this->elementStart('form', array('method' => 'post',
'id' => 'facebook_settings'));
@@ -131,7 +131,7 @@ class FacebooksettingsAction extends FacebookAction
$this->elementStart('ul', array('id' => 'fb-permissions-list'));
$this->elementStart('li', array('id' => 'fb-permissions-item'));
- $this->elementStart('fb:prompt-permission', array('perms' => 'status_update',
+ $this->elementStart('fb:prompt-permission', array('perms' => 'publish_stream',
'next_fbjs' => 'document.setLocation(\'' . "$this->app_uri/settings.php" . '\')'));
$this->element('span', array('class' => 'facebook-button'),
sprintf(_('Allow %s to update my Facebook status'), common_config('site', 'name')));
diff --git a/lib/facebookaction.php b/lib/facebookaction.php
index 1ae90d53b..5be2f2fe6 100644
--- a/lib/facebookaction.php
+++ b/lib/facebookaction.php
@@ -460,16 +460,6 @@ class FacebookAction extends Action
}
}
- function updateFacebookStatus($notice)
- {
- $prefix = $this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $this->fbuid);
- $content = "$prefix $notice->content";
-
- if ($this->facebook->api_client->users_hasAppPermission('status_update', $this->fbuid)) {
- $this->facebook->api_client->users_setStatus($content, $this->fbuid, false, true);
- }
- }
-
function saveNewNotice()
{
@@ -504,7 +494,7 @@ class FacebookAction extends Action
$replyto = $this->trimmed('inreplyto');
$notice = Notice::saveNew($user->id, $content,
- 'Facebook', 1, ($replyto == 'false') ? null : $replyto);
+ 'web', 1, ($replyto == 'false') ? null : $replyto);
if (is_string($notice)) {
$this->showPage($notice);
@@ -514,8 +504,7 @@ class FacebookAction extends Action
common_broadcast_notice($notice);
// Also update the user's Facebook status
- $this->updateFacebookStatus($notice);
- $this->updateProfileBox($notice);
+ facebookBroadcastNotice($notice);
}
diff --git a/lib/facebookutil.php b/lib/facebookutil.php
index 632ec4bad..85077c254 100644
--- a/lib/facebookutil.php
+++ b/lib/facebookutil.php
@@ -86,13 +86,17 @@ function isFacebookBound($notice, $flink) {
// Check to see if the user has given the FB app status update perms
$result = $facebook->api_client->
- users_hasAppPermission('status_update', $fbuid);
+ users_hasAppPermission('publish_stream', $fbuid);
+ if ($result != 1) {
+ $result = $facebook->api_client->
+ users_hasAppPermission('status_update', $fbuid);
+ }
if ($result != 1) {
$user = $flink->getUser();
$msg = "Not sending notice $notice->id to Facebook " .
"because user $user->nickname hasn't given the " .
- 'Facebook app \'status_update\' permission.';
+ 'Facebook app \'status_update\' or \'publish_stream\' permission.';
common_debug($msg);
$success = false;
}
@@ -138,7 +142,56 @@ function facebookBroadcastNotice($notice)
// Okay, we're good to go, update the FB status
try {
- $facebook->api_client->users_setStatus($status, $fbuid, false, true);
+ $result = $facebook->api_client->
+ users_hasAppPermission('publish_stream', $fbuid);
+ if($result == 1){
+ // authorized to use the stream api, so use it
+ $fbattachment = null;
+ $attachments = $notice->attachments();
+ if($attachments){
+ $fbattachment=array();
+ $fbattachment['media']=array();
+ //facebook only supports one attachment per item
+ $attachment = $attachments[0];
+ $fbmedia=array();
+ if(strncmp($attachment->mimetype,'image/',strlen('image/'))==0){
+ $fbmedia['type']='image';
+ $fbmedia['src']=$attachment->url;
+ $fbmedia['href']=$attachment->url;
+ $fbattachment['media'][]=$fbmedia;
+/* Video doesn't seem to work. The notice never makes it to facebook, and no error is reported.
+ }else if(strncmp($attachment->mimetype,'video/',strlen('image/'))==0 || $attachment->mimetype="application/ogg"){
+ $fbmedia['type']='video';
+ $fbmedia['video_src']=$attachment->url;
+ // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
+ // says that preview_img is required... but we have no value to put in it
+ // $fbmedia['preview_img']=$attachment->url;
+ if($attachment->title){
+ $fbmedia['video_title']=$attachment->title;
+ }
+ $fbmedia['video_type']=$attachment->mimetype;
+ $fbattachment['media'][]=$fbmedia;
+*/
+ }else if($attachment->mimetype=='audio/mpeg'){
+ $fbmedia['type']='mp3';
+ $fbmedia['src']=$attachment->url;
+ $fbattachment['media'][]=$fbmedia;
+ }else if($attachment->mimetype=='application/x-shockwave-flash'){
+ $fbmedia['type']='flash';
+ // http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
+ // says that imgsrc is required... but we have no value to put in it
+ // $fbmedia['imgsrc']='';
+ $fbmedia['swfsrc']=$attachment->url;
+ $fbattachment['media'][]=$fbmedia;
+ }else{
+ $fbattachment['name']=($attachment->title?$attachment->title:$attachment->url);
+ $fbattachment['href']=$attachment->url;
+ }
+ }
+ $facebook->api_client->stream_publish($status, $fbattachment, null, null, $fbuid);
+ }else{
+ $facebook->api_client->users_setStatus($status, $fbuid, false, true);
+ }
} catch(FacebookRestClientException $e) {
common_log(LOG_ERR, $e->getMessage());
common_log(LOG_ERR,
@@ -150,7 +203,7 @@ function facebookBroadcastNotice($notice)
if ($code >= 200) {
// 200 The application does not have permission to operate on the passed in uid parameter.
- // 250 Updating status requires the extended permission status_update.
+ // 250 Updating status requires the extended permission status_update or publish_stream.
// see: http://wiki.developers.facebook.com/index.php/Users.setStatus#Example_Return_XML
remove_facebook_app($flink);
--
cgit v1.2.3-54-g00ecf
From 8b65883f9ddf1cb1b7bdec323722da351fa0cb69 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 17:28:38 -0700
Subject: cache frequently-used subscriber, subscription, notice and fave count
values
---
classes/Notice.php | 2 +
classes/Profile.php | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++
classes/User.php | 2 +
lib/command.php | 15 ++----
lib/profileaction.php | 21 +++------
lib/subs.php | 13 +++--
lib/twitterapi.php | 20 ++------
7 files changed, 157 insertions(+), 44 deletions(-)
diff --git a/classes/Notice.php b/classes/Notice.php
index e975cab93..75044cf63 100644
--- a/classes/Notice.php
+++ b/classes/Notice.php
@@ -356,6 +356,8 @@ class Notice extends Memcached_DataObject
$this->blowTagCache($blowLast);
$this->blowGroupCache($blowLast);
$this->blowConversationCache($blowLast);
+ $profile = Profile::staticGet($this->profile_id);
+ $profile->blowNoticeCount();
}
function blowConversationCache($blowLast=false)
diff --git a/classes/Profile.php b/classes/Profile.php
index a0ed6b3ca..224b61bd2 100644
--- a/classes/Profile.php
+++ b/classes/Profile.php
@@ -337,4 +337,132 @@ class Profile extends Memcached_DataObject
return $profile;
}
+
+ function subscriptionCount()
+ {
+ $c = common_memcache();
+
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:subscription_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $sub = new Subscription();
+ $sub->subscriber = $this->id;
+
+ $cnt = (int) $sub->count('distinct subscribed');
+
+ $cnt = ($cnt > 0) ? $cnt - 1 : $cnt;
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:subscription_count:'.$this->id), $cnt);
+ }
+
+ common_debug("subscriptionCount == $cnt");
+ return $cnt;
+ }
+
+ function subscriberCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:subscriber_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $sub = new Subscription();
+ $sub->subscribed = $this->id;
+
+ $cnt = (int) $sub->count('distinct subscriber');
+
+ $cnt = ($cnt > 0) ? $cnt - 1 : $cnt;
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:subscriber_count:'.$this->id), $cnt);
+ }
+
+ common_debug("subscriberCount == $cnt");
+ return $cnt;
+ }
+
+ function faveCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:fave_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $faves = new Fave();
+ $faves->user_id = $this->id;
+ $cnt = (int) $faves->count('distinct notice_id');
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:fave_count:'.$this->id), $cnt);
+ }
+
+ common_debug("faveCount == $cnt");
+ return $cnt;
+ }
+
+ function noticeCount()
+ {
+ $c = common_memcache();
+
+ if (!empty($c)) {
+ $cnt = $c->get(common_cache_key('profile:notice_count:'.$this->id));
+ if (is_integer($cnt)) {
+ return (int) $cnt;
+ }
+ }
+
+ $notices = new Notice();
+ $notices->profile_id = $this->id;
+ $cnt = (int) $notices->count('distinct id');
+
+ if (!empty($c)) {
+ $c->set(common_cache_key('profile:notice_count:'.$this->id), $cnt);
+ }
+
+ common_debug("noticeCount == $cnt");
+ return $cnt;
+ }
+
+ function blowSubscriberCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:subscriber_count:'.$this->id));
+ }
+ }
+
+ function blowSubscriptionCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:subscription_count:'.$this->id));
+ }
+ }
+
+ function blowFaveCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:fave_count:'.$this->id));
+ }
+ }
+
+ function blowNoticeCount()
+ {
+ $c = common_memcache();
+ if (!empty($c)) {
+ $c->delete(common_cache_key('profile:notice_count:'.$this->id));
+ }
+ }
}
diff --git a/classes/User.php b/classes/User.php
index 04b38a0d2..6c1f149e4 100644
--- a/classes/User.php
+++ b/classes/User.php
@@ -494,6 +494,8 @@ class User extends Memcached_DataObject
$cache->delete(common_cache_key('fave:ids_by_user_own:'.$this->id));
$cache->delete(common_cache_key('fave:ids_by_user_own:'.$this->id.';last'));
}
+ $profile = $this->getProfile();
+ $profile->blowFaveCount();
}
function getSelfTags()
diff --git a/lib/command.php b/lib/command.php
index 564661382..4e2280bc8 100644
--- a/lib/command.php
+++ b/lib/command.php
@@ -97,18 +97,11 @@ class StatsCommand extends Command
{
function execute($channel)
{
+ $profile = $this->user->getProfile();
- $subs = new Subscription();
- $subs->subscriber = $this->user->id;
- $subs_count = (int) $subs->count() - 1;
-
- $subbed = new Subscription();
- $subbed->subscribed = $this->user->id;
- $subbed_count = (int) $subbed->count() - 1;
-
- $notices = new Notice();
- $notices->profile_id = $this->user->id;
- $notice_count = (int) $notices->count();
+ $subs_count = $profile->subscriptionCount();
+ $subbed_count = $profile->subscriberCount();
+ $notice_count = $profile->noticeCount();
$channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n".
"Subscribers: %2\$s\n".
diff --git a/lib/profileaction.php b/lib/profileaction.php
index eeb5dbe48..9e9c79c78 100644
--- a/lib/profileaction.php
+++ b/lib/profileaction.php
@@ -163,18 +163,9 @@ class ProfileAction extends OwnerDesignAction
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();
+ $subs_count = $this->profile->subscriptionCount();
+ $subbed_count = $this->profile->subscriberCount();
+ $notice_count = $this->profile->noticeCount();
$this->elementStart('div', array('id' => 'entity_statistics',
'class' => 'section'));
@@ -199,7 +190,7 @@ class ProfileAction extends OwnerDesignAction
array('nickname' => $this->profile->nickname))),
_('Subscriptions'));
$this->elementEnd('dt');
- $this->element('dd', null, (is_int($subs_count)) ? $subs_count : '0');
+ $this->element('dd', null, $subs_count);
$this->elementEnd('dl');
$this->elementStart('dl', 'entity_subscribers');
@@ -208,12 +199,12 @@ class ProfileAction extends OwnerDesignAction
array('nickname' => $this->profile->nickname))),
_('Subscribers'));
$this->elementEnd('dt');
- $this->element('dd', 'subscribers', (is_int($subbed_count)) ? $subbed_count : '0');
+ $this->element('dd', 'subscribers', $subbed_count);
$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->element('dd', null, $notice_count);
$this->elementEnd('dl');
$this->elementEnd('div');
diff --git a/lib/subs.php b/lib/subs.php
index 3bd67b39c..e76023752 100644
--- a/lib/subs.php
+++ b/lib/subs.php
@@ -44,7 +44,6 @@ function subs_subscribe_user($user, $other_nickname)
function subs_subscribe_to($user, $other)
{
-
if ($user->isSubscribed($other)) {
return _('Already subscribed!.');
}
@@ -60,12 +59,16 @@ function subs_subscribe_to($user, $other)
subs_notify($other, $user);
- $cache = common_memcache();
+ $cache = common_memcache();
if ($cache) {
$cache->delete(common_cache_key('user:notices_with_friends:' . $user->id));
}
+ $profile = $user->getProfile();
+
+ $profile->blowSubscriptionsCount();
+ $other->blowSubscribersCount();
if ($other->autosubscribe && !$other->isSubscribed($user) && !$user->hasBlocked($other)) {
if (!$other->subscribeTo($user)) {
@@ -117,7 +120,6 @@ function subs_unsubscribe_user($user, $other_nickname)
function subs_unsubscribe_to($user, $other)
{
-
if (!$user->isSubscribed($other))
return _('Not subscribed!.');
@@ -139,6 +141,11 @@ function subs_unsubscribe_to($user, $other)
$cache->delete(common_cache_key('user:notices_with_friends:' . $user->id));
}
+ $profile = $user->getProfile();
+
+ $profile->blowSubscriptionsCount();
+ $other->blowSubscribersCount();
+
return true;
}
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index 8f902cbca..f48513e67 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -89,7 +89,7 @@ class TwitterapiAction extends Action
$twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null;
$twitter_user['protected'] = false; # not supported by Laconica yet
- $twitter_user['followers_count'] = $this->count_subscriptions($profile);
+ $twitter_user['followers_count'] = $profile->subscriberCount();
// To be supported soon...
$twitter_user['profile_background_color'] = '';
@@ -98,17 +98,11 @@ class TwitterapiAction extends Action
$twitter_user['profile_sidebar_fill_color'] = '';
$twitter_user['profile_sidebar_border_color'] = '';
- $subbed = DB_DataObject::factory('subscription');
- $subbed->subscriber = $profile->id;
- $subbed_count = (int) $subbed->count() - 1;
- $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0;
+ $twitter_user['friends_count'] = $profile->subscriptionCount();
$twitter_user['created_at'] = $this->date_twitter($profile->created);
- $faves = DB_DataObject::factory('fave');
- $faves->user_id = $user->id;
- $faves_count = (int) $faves->count();
- $twitter_user['favourites_count'] = $faves_count; // British spelling!
+ $twitter_user['favourites_count'] = $profile->faveCount(); // British spelling!
// Need to pull up the user for some of this
$user = User::staticGet($profile->id);
@@ -129,11 +123,7 @@ class TwitterapiAction extends Action
$twitter_user['profile_background_image_url'] = '';
$twitter_user['profile_background_tile'] = false;
- $notices = DB_DataObject::factory('notice');
- $notices->profile_id = $profile->id;
- $notice_count = (int) $notices->count();
-
- $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0;
+ $twitter_user['statuses_count'] = $profile->noticeCount();
// Is the requesting user following this user?
$twitter_user['following'] = false;
@@ -396,7 +386,7 @@ class TwitterapiAction extends Action
$enclosure = $entry['enclosures'][0];
$this->element('enclosure', array('url'=>$enclosure['url'],'type'=>$enclosure['mimetype'],'length'=>$enclosure['size']), null);
}
-
+
$this->elementEnd('item');
}
--
cgit v1.2.3-54-g00ecf
From f527b8a8d7cf38e21c0ceb8d54cfae2d679e1564 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 17:40:11 -0700
Subject: wrong order for span and a in profilesection
---
lib/profilesection.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/profilesection.php b/lib/profilesection.php
index 8ed290e03..9ff243fb5 100644
--- a/lib/profilesection.php
+++ b/lib/profilesection.php
@@ -94,8 +94,8 @@ class ProfileSection extends Section
$profile->fullname :
$profile->nickname));
$this->out->element('span', 'fn nickname', $profile->nickname);
- $this->out->elementEnd('span');
$this->out->elementEnd('a');
+ $this->out->elementEnd('span');
$this->out->elementEnd('td');
if ($profile->value) {
$this->out->element('td', 'value', $profile->value);
--
cgit v1.2.3-54-g00ecf
From 15f6309deacf64e6b408d45a4eb19852d36f9f72 Mon Sep 17 00:00:00 2001
From: Evan Prodromou
Date: Thu, 9 Jul 2009 23:12:53 -0700
Subject: add a little syntactical sugar for adding plugins
---
lib/common.php | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/lib/common.php b/lib/common.php
index 832667d81..c47702779 100644
--- a/lib/common.php
+++ b/lib/common.php
@@ -282,6 +282,39 @@ if (function_exists('date_default_timezone_set')) {
date_default_timezone_set('UTC');
}
+function addPlugin($name, $attrs = null)
+{
+ $name = ucfirst($name);
+ $pluginclass = "{$name}Plugin";
+
+ if (!class_exists($pluginclass)) {
+
+ $files = array("local/plugins/{$pluginclass}.php",
+ "local/plugins/{$name}/{$pluginclass}.php",
+ "local/{$pluginclass}.php",
+ "local/{$name}/{$pluginclass}.php",
+ "plugins/{$pluginclass}.php",
+ "plugins/{$name}/{$pluginclass}.php");
+
+ foreach ($files as $file) {
+ $fullpath = INSTALLDIR.'/'.$file;
+ if (@file_exists($fullpath)) {
+ include_once($fullpath);
+ break;
+ }
+ }
+ }
+
+ $inst = new $pluginclass();
+
+ if (!empty($attrs)) {
+ foreach ($attrs as $aname => $avalue) {
+ $inst->$aname = $avalue;
+ }
+ }
+ return $inst;
+}
+
// From most general to most specific:
// server-wide, then vhost-wide, then for a path,
// finally for a dir (usually only need one of the last two).
--
cgit v1.2.3-54-g00ecf
From 08d50655f3a220b1fe970b0917a6ecbcae019b04 Mon Sep 17 00:00:00 2001
From: Craig Andrews
Date: Fri, 10 Jul 2009 17:00:27 -0400
Subject: added group status api, located at
/api/statuses/group_timeline/ID.rss
http://laconi.ca/trac/ticket/1702
---
actions/showgroup.php | 23 +++++++++++++++---
actions/twitapistatuses.php | 58 +++++++++++++++++++++++++++++++++++++++++++++
lib/router.php | 2 +-
lib/twitterapi.php | 28 ++++++++++++++++++++++
4 files changed, 107 insertions(+), 4 deletions(-)
diff --git a/actions/showgroup.php b/actions/showgroup.php
index ce11d574e..f803840ff 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -317,8 +317,25 @@ class ShowgroupAction extends GroupDesignAction
common_local_url('grouprss',
array('nickname' => $this->group->nickname));
- return array(new Feed(Feed::RSS1, $url, sprintf(_('Notice feed for %s group'),
- $this->group->nickname)));
+ return array(new Feed(Feed::RSS1,
+ common_local_url('grouprss',
+ array('nickname' => $this->group->nickname)),
+ sprintf(_('Notice feed for %s group (RSS 1.0)'),
+ $this->group->nickname)),
+ new Feed(Feed::RSS2,
+ common_local_url('api',
+ array('apiaction' => 'statuses',
+ 'method' => 'group_timeline',
+ 'argument' => $this->group->nickname.'.rss')),
+ sprintf(_('Notice feed for %s group (RSS 2.0)'),
+ $this->group->nickname)),
+ new Feed(Feed::ATOM,
+ common_local_url('api',
+ array('apiaction' => 'statuses',
+ 'method' => 'group_timeline',
+ 'argument' => $this->group->nickname.'.atom')),
+ sprintf(_('Notice feed for %s group (Atom)'),
+ $this->group->nickname)));
}
/**
@@ -466,4 +483,4 @@ class GroupAdminSection extends ProfileSection
{
return null;
}
-}
\ No newline at end of file
+}
diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php
index c9943698d..ec5d378f0 100644
--- a/actions/twitapistatuses.php
+++ b/actions/twitapistatuses.php
@@ -136,6 +136,64 @@ class TwitapistatusesAction extends TwitterapiAction
}
+ function group_timeline($args, $apidata)
+ {
+ parent::handle($args);
+
+ $this->auth_user = $apidata['user'];
+ $group = $this->get_group($apidata['api_arg'], $apidata);
+
+ if (empty($group)) {
+ $this->clientError('Not Found', 404, $apidata['content-type']);
+ return;
+ }
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s timeline"), $group->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:GroupTimeline:".$group->id;
+ $link = common_local_url('showstream',
+ array('nickname' => $group->nickname));
+ $subtitle = sprintf(_('Updates from %1$s on %2$s!'),
+ $group->nickname, $sitename);
+
+ $page = (int)$this->arg('page', 1);
+ $count = (int)$this->arg('count', 20);
+ $max_id = (int)$this->arg('max_id', 0);
+ $since_id = (int)$this->arg('since_id', 0);
+ $since = $this->arg('since');
+
+ $notice = $group->getNotices(($page-1)*$count,
+ $count, $since_id, $max_id, $since);
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->show_xml_timeline($notice);
+ break;
+ case 'rss':
+ $this->show_rss_timeline($notice, $title, $link,
+ $subtitle, $suplink);
+ break;
+ case 'atom':
+ if (isset($apidata['api_arg'])) {
+ $selfuri = common_root_url() .
+ 'api/statuses/group_timeline/' .
+ $apidata['api_arg'] . '.atom';
+ } else {
+ $selfuri = common_root_url() .
+ 'api/statuses/group_timeline.atom';
+ }
+ $this->show_atom_timeline($notice, $title, $id, $link,
+ $subtitle, $suplink, $selfuri);
+ break;
+ case 'json':
+ $this->show_json_timeline($notice);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ }
+ }
+
function user_timeline($args, $apidata)
{
parent::handle($args);
diff --git a/lib/router.php b/lib/router.php
index 75e72f932..bc063038f 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -266,7 +266,7 @@ class Router
$m->connect('api/statuses/:method/:argument',
array('action' => 'api',
'apiaction' => 'statuses'),
- array('method' => '(user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
+ array('method' => '(group_timeline|user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
// users
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index f48513e67..d2515070d 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -774,6 +774,34 @@ class TwitterapiAction extends Action
}
}
+ function get_group($id, $apidata=null)
+ {
+ if (empty($id)) {
+
+ if (is_numeric($this->arg('id'))) {
+ return User::staticGet($this->arg('id'));
+ } else if ($this->arg('id')) {
+ $nickname = common_canonical_nickname($this->arg('id'));
+ return User_group::staticGet('nickname', $nickname);
+ } else if ($this->arg('user_id')) {
+ // This is to ensure that a non-numeric user_id still
+ // overrides screen_name even if it doesn't get used
+ if (is_numeric($this->arg('user_id'))) {
+ return User_group::staticGet('id', $this->arg('user_id'));
+ }
+ } else if ($this->arg('screen_name')) {
+ $nickname = common_canonical_nickname($this->arg('screen_name'));
+ return User::staticGet('nickname', $nickname);
+ }
+
+ } else if (is_numeric($id)) {
+ return User_group::staticGet($id);
+ } else {
+ $nickname = common_canonical_nickname($id);
+ return User_group::staticGet('nickname', $nickname);
+ }
+ }
+
function get_profile($id)
{
if (is_numeric($id)) {
--
cgit v1.2.3-54-g00ecf
From 111aee9dc033256189a34800a7a6e11fa87aa041 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 14:44:50 -0700
Subject: Fix conflict from merge with 0.7.x; remove conflict markers
---
README | 5 -----
1 file changed, 5 deletions(-)
diff --git a/README b/README
index 40e526355..d2673a6d3 100644
--- a/README
+++ b/README
@@ -936,8 +936,6 @@ 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.
@@ -953,15 +951,12 @@ sslserver: use an alternate server name for SSL URLs, like
shorturllength: Length of URL at which URLs in a message exceeding 140
characters will be sent to the user's chosen
shortening service.
-<<<<<<< HEAD:README
design: a default design (colors and background) for the site.
Sub-items are: backgroundcolor, contentcolor, sidebarcolor,
textcolor, linkcolor, backgroundimage, disposition.
dupelimit: minimum time allowed for one person to say the same thing
twice. Default 60s. Anything lower is considered a user
or UI error.
-=======
->>>>>>> 0.7.x:README
db
--
--
cgit v1.2.3-54-g00ecf
From 36d2c66eee9ddc56acca5f9250521c7f96dfc92f Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 14:46:19 -0700
Subject: Add Craig Andrews to the credits list
---
README | 1 +
1 file changed, 1 insertion(+)
diff --git a/README b/README
index d2673a6d3..2c92a75da 100644
--- a/README
+++ b/README
@@ -1528,6 +1528,7 @@ if anyone's been overlooked in error.
* Brenda Wallace
* Jeffery To
* Federico Marani
+* Craig Andrews
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,
--
cgit v1.2.3-54-g00ecf
From 544a14d290cc6c08950b2d4a6faf324704e90c6c Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 17:56:01 -0700
Subject: Move groups timeline API method into groups API action
---
actions/twitapigroups.php | 114 ++++++++++++++++++++++++++++++++++++++++++++
actions/twitapistatuses.php | 58 ----------------------
lib/router.php | 7 ++-
3 files changed, 120 insertions(+), 59 deletions(-)
create mode 100644 actions/twitapigroups.php
diff --git a/actions/twitapigroups.php b/actions/twitapigroups.php
new file mode 100644
index 000000000..c8aae173f
--- /dev/null
+++ b/actions/twitapigroups.php
@@ -0,0 +1,114 @@
+.
+ *
+ * @category Twitter
+ * @package Laconica
+ * @author Craig Andrews
+ * @author Zach Copley
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+if (!defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/twitterapi.php';
+
+/**
+ * Group-specific API methods
+ *
+ * This class handles Laconica group API methods.
+ *
+ * @category Twitter
+ * @package Laconica
+ * @author Craig Andrews
+ * @author Zach Copley
+ * @copyright 2009 Control Yourself, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://laconi.ca/
+ */
+
+ class TwitapigroupsAction extends TwitterapiAction
+ {
+
+ function timeline($args, $apidata)
+ {
+ parent::handle($args);
+
+ common_debug("in groups api action");
+
+ $this->auth_user = $apidata['user'];
+ $group = $this->get_group($apidata['api_arg'], $apidata);
+
+ if (empty($group)) {
+ $this->clientError('Not Found', 404, $apidata['content-type']);
+ return;
+ }
+
+ $sitename = common_config('site', 'name');
+ $title = sprintf(_("%s timeline"), $group->nickname);
+ $taguribase = common_config('integration', 'taguri');
+ $id = "tag:$taguribase:GroupTimeline:".$group->id;
+ $link = common_local_url('showstream',
+ array('nickname' => $group->nickname));
+ $subtitle = sprintf(_('Updates from %1$s on %2$s!'),
+ $group->nickname, $sitename);
+
+ $page = (int)$this->arg('page', 1);
+ $count = (int)$this->arg('count', 20);
+ $max_id = (int)$this->arg('max_id', 0);
+ $since_id = (int)$this->arg('since_id', 0);
+ $since = $this->arg('since');
+
+ $notice = $group->getNotices(($page-1)*$count,
+ $count, $since_id, $max_id, $since);
+
+ switch($apidata['content-type']) {
+ case 'xml':
+ $this->show_xml_timeline($notice);
+ break;
+ case 'rss':
+ $this->show_rss_timeline($notice, $title, $link,
+ $subtitle, $suplink);
+ break;
+ case 'atom':
+ if (isset($apidata['api_arg'])) {
+ $selfuri = common_root_url() .
+ 'api/statuses/group_timeline/' .
+ $apidata['api_arg'] . '.atom';
+ } else {
+ $selfuri = common_root_url() .
+ 'api/statuses/group_timeline.atom';
+ }
+ $this->show_atom_timeline($notice, $title, $id, $link,
+ $subtitle, $suplink, $selfuri);
+ break;
+ case 'json':
+ $this->show_json_timeline($notice);
+ break;
+ default:
+ $this->clientError(_('API method not found!'), $code = 404);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php
index ec5d378f0..c9943698d 100644
--- a/actions/twitapistatuses.php
+++ b/actions/twitapistatuses.php
@@ -136,64 +136,6 @@ class TwitapistatusesAction extends TwitterapiAction
}
- function group_timeline($args, $apidata)
- {
- parent::handle($args);
-
- $this->auth_user = $apidata['user'];
- $group = $this->get_group($apidata['api_arg'], $apidata);
-
- if (empty($group)) {
- $this->clientError('Not Found', 404, $apidata['content-type']);
- return;
- }
-
- $sitename = common_config('site', 'name');
- $title = sprintf(_("%s timeline"), $group->nickname);
- $taguribase = common_config('integration', 'taguri');
- $id = "tag:$taguribase:GroupTimeline:".$group->id;
- $link = common_local_url('showstream',
- array('nickname' => $group->nickname));
- $subtitle = sprintf(_('Updates from %1$s on %2$s!'),
- $group->nickname, $sitename);
-
- $page = (int)$this->arg('page', 1);
- $count = (int)$this->arg('count', 20);
- $max_id = (int)$this->arg('max_id', 0);
- $since_id = (int)$this->arg('since_id', 0);
- $since = $this->arg('since');
-
- $notice = $group->getNotices(($page-1)*$count,
- $count, $since_id, $max_id, $since);
-
- switch($apidata['content-type']) {
- case 'xml':
- $this->show_xml_timeline($notice);
- break;
- case 'rss':
- $this->show_rss_timeline($notice, $title, $link,
- $subtitle, $suplink);
- break;
- case 'atom':
- if (isset($apidata['api_arg'])) {
- $selfuri = common_root_url() .
- 'api/statuses/group_timeline/' .
- $apidata['api_arg'] . '.atom';
- } else {
- $selfuri = common_root_url() .
- 'api/statuses/group_timeline.atom';
- }
- $this->show_atom_timeline($notice, $title, $id, $link,
- $subtitle, $suplink, $selfuri);
- break;
- case 'json':
- $this->show_json_timeline($notice);
- break;
- default:
- $this->clientError(_('API method not found!'), $code = 404);
- }
- }
-
function user_timeline($args, $apidata)
{
parent::handle($args);
diff --git a/lib/router.php b/lib/router.php
index bc063038f..cd2143d13 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -266,7 +266,7 @@ class Router
$m->connect('api/statuses/:method/:argument',
array('action' => 'api',
'apiaction' => 'statuses'),
- array('method' => '(group_timeline|user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
+ array('method' => '(|user_timeline|friends_timeline|replies|mentions|show|destroy|friends|followers)'));
// users
@@ -394,6 +394,11 @@ class Router
array('action' => 'api',
'apiaction' => 'laconica'));
+ // Groups
+ $m->connect('api/laconica/groups/:method/:argument',
+ array('action' => 'api',
+ 'apiaction' => 'groups'));
+
// search
$m->connect('api/search.atom', array('action' => 'twitapisearchatom'));
$m->connect('api/search.json', array('action' => 'twitapisearchjson'));
--
cgit v1.2.3-54-g00ecf
From c13dd856c8c11f13129a45e25356678f5ae76971 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 18:08:10 -0700
Subject: Fix alternate link for groups API feed
---
actions/twitapigroups.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/actions/twitapigroups.php b/actions/twitapigroups.php
index c8aae173f..db15b2cd3 100644
--- a/actions/twitapigroups.php
+++ b/actions/twitapigroups.php
@@ -69,7 +69,7 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
$title = sprintf(_("%s timeline"), $group->nickname);
$taguribase = common_config('integration', 'taguri');
$id = "tag:$taguribase:GroupTimeline:".$group->id;
- $link = common_local_url('showstream',
+ $link = common_local_url('showgroup',
array('nickname' => $group->nickname));
$subtitle = sprintf(_('Updates from %1$s on %2$s!'),
$group->nickname, $sitename);
@@ -94,11 +94,11 @@ require_once INSTALLDIR.'/lib/twitterapi.php';
case 'atom':
if (isset($apidata['api_arg'])) {
$selfuri = common_root_url() .
- 'api/statuses/group_timeline/' .
+ 'api/statuses/groups/timeline/' .
$apidata['api_arg'] . '.atom';
} else {
$selfuri = common_root_url() .
- 'api/statuses/group_timeline.atom';
+ 'api/statuses/groups/timeline.atom';
}
$this->show_atom_timeline($notice, $title, $id, $link,
$subtitle, $suplink, $selfuri);
--
cgit v1.2.3-54-g00ecf
From 7308203065e595dee947702682620f64b6d8ea1f Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 18:11:54 -0700
Subject: Update showgroup action RSS 2.0 feed link
---
actions/showgroup.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/actions/showgroup.php b/actions/showgroup.php
index f803840ff..5d9ee26a2 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -324,8 +324,8 @@ class ShowgroupAction extends GroupDesignAction
$this->group->nickname)),
new Feed(Feed::RSS2,
common_local_url('api',
- array('apiaction' => 'statuses',
- 'method' => 'group_timeline',
+ array('apiaction' => 'groups',
+ 'method' => 'timeline',
'argument' => $this->group->nickname.'.rss')),
sprintf(_('Notice feed for %s group (RSS 2.0)'),
$this->group->nickname)),
--
cgit v1.2.3-54-g00ecf
From 6b0468358bd1148adfcf11a18cbb19ab4e80a799 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 18:15:18 -0700
Subject: Group timeline API method doesn't require auth
---
actions/api.php | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/actions/api.php b/actions/api.php
index 18c3b68d4..4a00b77e8 100644
--- a/actions/api.php
+++ b/actions/api.php
@@ -127,7 +127,8 @@ class ApiAction extends Action
'help/downtime_schedule',
'laconica/version',
'laconica/config',
- 'laconica/wadl');
+ 'laconica/wadl',
+ 'groups/timeline');
static $bareauth = array('statuses/user_timeline',
'statuses/friends_timeline',
--
cgit v1.2.3-54-g00ecf
From 0ac08c1fb3a930af420cb9c4252bc6f499ba1141 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 18:22:19 -0700
Subject: Make get_group() behave more like get_user()
---
lib/router.php | 4 ++++
lib/twitterapi.php | 14 +++++++-------
2 files changed, 11 insertions(+), 7 deletions(-)
diff --git a/lib/router.php b/lib/router.php
index cd2143d13..8104d7818 100644
--- a/lib/router.php
+++ b/lib/router.php
@@ -399,6 +399,10 @@ class Router
array('action' => 'api',
'apiaction' => 'groups'));
+ $m->connect('api/laconica/groups/:method',
+ array('action' => 'api',
+ 'apiaction' => 'groups'));
+
// search
$m->connect('api/search.atom', array('action' => 'twitapisearchatom'));
$m->connect('api/search.json', array('action' => 'twitapisearchjson'));
diff --git a/lib/twitterapi.php b/lib/twitterapi.php
index d2515070d..4f3a5c0b6 100644
--- a/lib/twitterapi.php
+++ b/lib/twitterapi.php
@@ -779,19 +779,19 @@ class TwitterapiAction extends Action
if (empty($id)) {
if (is_numeric($this->arg('id'))) {
- return User::staticGet($this->arg('id'));
+ return User_group::staticGet($this->arg('id'));
} else if ($this->arg('id')) {
$nickname = common_canonical_nickname($this->arg('id'));
return User_group::staticGet('nickname', $nickname);
- } else if ($this->arg('user_id')) {
+ } else if ($this->arg('group_id')) {
// This is to ensure that a non-numeric user_id still
// overrides screen_name even if it doesn't get used
- if (is_numeric($this->arg('user_id'))) {
- return User_group::staticGet('id', $this->arg('user_id'));
+ if (is_numeric($this->arg('group_id'))) {
+ return User_group::staticGet('id', $this->arg('group_id'));
}
- } else if ($this->arg('screen_name')) {
- $nickname = common_canonical_nickname($this->arg('screen_name'));
- return User::staticGet('nickname', $nickname);
+ } else if ($this->arg('group_name')) {
+ $nickname = common_canonical_nickname($this->arg('group_name'));
+ return User_group::staticGet('nickname', $nickname);
}
} else if (is_numeric($id)) {
--
cgit v1.2.3-54-g00ecf
From 7621e0e38467349a89f71e814941932fbacecfa1 Mon Sep 17 00:00:00 2001
From: Zach Copley
Date: Fri, 10 Jul 2009 20:13:12 -0700
Subject: Fix link for atom feed in showgroup action
---
actions/showgroup.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/actions/showgroup.php b/actions/showgroup.php
index 5d9ee26a2..32ec674a9 100644
--- a/actions/showgroup.php
+++ b/actions/showgroup.php
@@ -331,8 +331,8 @@ class ShowgroupAction extends GroupDesignAction
$this->group->nickname)),
new Feed(Feed::ATOM,
common_local_url('api',
- array('apiaction' => 'statuses',
- 'method' => 'group_timeline',
+ array('apiaction' => 'groups',
+ 'method' => 'timeline',
'argument' => $this->group->nickname.'.atom')),
sprintf(_('Notice feed for %s group (Atom)'),
$this->group->nickname)));
--
cgit v1.2.3-54-g00ecf