--- /dev/null
+This is GNU social, a free software, decentralized social network,
+based on StatusNet.
+
+Developers
+==========
+
+Matt Lee
+Rob Myers
+Sean Corbett
+Ian Denhardt
+Steve DuBois
+Mike Sheldon
+
+With help from
+==============
+
+Bradley M. Kuhn
+
+Special help from
+=================
+
+Craig Andrews
+
--- /dev/null
+Things to be done
+=================
+
+* Create a theme for GNU social
+
+* Create a set of plugins to give StatusNet a more social-network UI
+
+* Work on improvements for annoying things in StatusNet (ie. no
+ redirect to login page when you need to be logged in, etc)
+
+* Work on adding further Activities, such as sharing photos/video,
+ events, UI for managing relationships.
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@import url('http://s.libre.fm/combo.css');
+html {margin: 0; padding: 0;}
+body {width: 480px; margin: 70px auto; text-align: left; font-size: 110%; }
+
+img {border: 0;}
+
+p {text-align: left; font-weight: normal; line-height: 1.6em; color: #111;}
+
+li {line-height: 1.4em; margin-bottom: 1em;}
+
+ul {margin: 0; padding-left: 1em;}
+
+h1, h2, h3 {text-align: center;}
+
+#privacy {background-color: #ffb; padding: 10px; border: 2px solid orange; margin-bottom: 1em; }
+
+#signup {text-align: center;}
+
+#allset {background-color: yellow; padding: 5px;}
+
+</style>
+<title>daisycha.in — your social circle</title>
+</head>
+<body>
+<h1><a href="/"><img src="dclogo.png" alt="daisycha.in" height="58" /></a></h1>
+
+<p id="allset">You're all set... please go check your email and click the link we
+sent you.</p>
+
+<h2><img src="getinvolved.png" alt="Get involved:" /></h2>
+
+<ul>
+ <li><a href="list.html">Join our mailing list</a> for updates and news.</li>
+ <li><a href="http://social.shapado.com">Send us your feedback, ideas and suggestions</a>.</li>
+ <li><a href="http://gitorious.org/+socialites">Check out our software</a> and get <a href="http://lists.gnu.org/mailman/listinfo/social">on the mailing list for
+ developers and artists</a>.</li>
+</ul>
+
+
+<p><small>FOO300 — © 2010 <a href="http://foocorp.net/">Foo Communications, LLC</a></small></p>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@import url('http://s.libre.fm/combo.css');
+html {margin: 0; padding: 0;}
+body {width: 480px; margin: 70px auto; text-align: left; font-size: 110%; }
+
+img {border: 0;}
+
+p {text-align: left; font-weight: normal; line-height: 1.6em; color: #111;}
+
+li {line-height: 1.4em; margin-bottom: 1em;}
+
+ul {margin: 0; padding-left: 1em;}
+
+h1, h2, h3 {text-align: center;}
+
+#privacy {background-color: #ffb; padding: 10px; border: 2px solid orange; margin-bottom: 1em; }
+
+#signup {text-align: center;}
+
+</style>
+<title>daisycha.in — your social circle</title>
+</head>
+<body>
+<h1><a href="/"><img src="dclogo.png" alt="daisycha.in" height="58" /></a></h1>
+
+<p>This is daisychain, our first public unveiling of a project we call
+<b>social</b>. The idea behind <b>social</b> was to make it easy to
+connect with all the people in your life, but without giving up
+control of your relationships.</p>
+
+<p>If you're using Facebook, and one day you decide to stop, or
+another service comes along (Remember MySpace? Friendster? Orkut?)
+— any and all contacts you have cannot be exported. <b>All your
+friends go away, and you have to find people again</b>.</p>
+
+<p>We think this is a bad idea.</p>
+
+<p><b>Bad for you, and bad for society.</b></p>
+
+<h2><img src="idea.png" alt="The idea:" /></h2>
+
+<p>Start simple, start with status updates like Twitter and Facebook
+already allow, and start getting people to begin updating their
+profiles from something they <b>can</b> control:</p>
+
+<p>Once you're comfortable and on-board with this, let's take your
+ideas, suggestions and feedback, and build the social networking
+software that we all want, and can all use.</p>
+
+<h2><img src="offer.png" alt="What we offer:" /></h2>
+
+<ul>
+
+<li>Let's make that software available to everyone in the world, so
+instead of having one big company in California with all of our
+secrets, we can rely on friends and family, or even run our own
+personal networks.</li>
+
+<li>Let's build the escape rope in to all these networks, so people are
+always able to pick up and leave whenever they feel like it, leaving a
+forwarding address if they choose.</li>
+
+<li>Let's make changing your social network a little more like moving
+house and a little less like starting again without friends or
+contacts in a foreign city.</li>
+
+<h2><img src="youandus.png" alt="You and us:" /></h2>
+
+<p>Who are we? We're a ragtail group of artists and geeks working to
+bring this to you.</p>
+
+<p>You don't have to trust us with your personal information, and in
+fact, we'd rather you didn't.</p>
+
+<p>We'd like you to join us and be a part of a revolution in the way
+people share and socialize on the web.</p>
+
+<p>Let's make the World Wide Web into the Social Web.</p>
+
+<h2><img src="better.png" alt="Make it better:" /></h2>
+
+<p>Anyone reading this, regardless of your ability to program
+computers or make things look pretty can help make this software
+better.</p>
+
+<p>You can tell us what you like, what you hate, how things should be
+different, and what features you'd like to see next.</p>
+
+<p>We'll take the time to listen to you.</p>
+
+
+
+
+<p id="signup"><a href="signup.html"><img src="signup.png" alt="Sign up" /></a></p>
+
+<p><small>FOO300 — © 2010 <a href="http://foocorp.net/">Foo Communications, LLC</a></small></p>
+
+</body>
+</html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@import url('http://s.libre.fm/combo.css');
+html {margin: 0; padding: 0;}
+body {width: 480px; margin: 70px auto; text-align: left; font-size: 110%; }
+
+img {border: 0;}
+
+p {text-align: left; font-weight: normal; line-height: 1.6em; color: #111;}
+
+li {line-height: 1.4em; margin-bottom: 1em;}
+
+ul {margin: 0; padding-left: 1em;}
+
+h1, h2, h3 {text-align: center;}
+
+#privacy {background-color: #ffb; padding: 10px; border: 2px solid orange; margin-bottom: 1em; }
+
+#signup {text-align: center;}
+
+</style>
+<title>daisycha.in — your social circle</title>
+</head>
+<body>
+<h1><a href="/"><img src="dclogo.png" alt="daisycha.in" height="58" /></a></h1>
+
+<p>Get on our mailing list and keep up to date with news and updates with social and daisychain.</p>
+
+<form action="http://foocorp.us2.list-manage.com/subscribe/post?u=ae361e483eddafa57feb63bb0&id=7b50a5946b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank">
+ <fieldset>
+
+<div class="mc-field-group">
+<label for="mce-EMAIL">Email Address </label>
+<input type="text" value="" name="EMAIL" class="required email" id="mce-EMAIL"> <input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="btn"></div>
+ </fieldset>
+</form>
+
+<p id="signup"><a href="signup.html"><img src="signup.png" alt="Sign up" /></a></p>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@import url('http://s.libre.fm/combo.css');
+html {margin: 0; padding: 0;}
+body {width: 480px; margin: 70px auto; text-align: left; font-size: 110%; }
+
+img {border: 0;}
+
+p {text-align: left; font-weight: normal; line-height: 1.6em; color: #111;}
+
+li {line-height: 1.4em; margin-bottom: 1em;}
+
+ul {margin: 0; padding-left: 1em;}
+
+h1, h2, h3 {text-align: center;}
+
+#privacy {background-color: #ffb; padding: 10px; border: 2px solid orange; margin-bottom: 1em; }
+
+</style>
+<title>daisycha.in — your social circle</title>
+</head>
+<body>
+<h1><a href="/"><img src="dclogo.png" alt="daisycha.in" height="58" /></a></h1>
+
+<h2><img src="privacy.png" alt="The idea:" /></h2>
+
+<div id="privacy">
+
+<p>To us, your privacy is vital.</p>
+
+<p>As things currently stand, <b>anything you say on daisychain is
+available to everyone in the world</b>.</p>
+
+<p>Privacy and controls for sharing is something we take extremely
+seriously, but it's also something we cannot do by ourselves.</p>
+
+<p>We invite you to join us and help us define a privacy policy and
+the privacy controls needed to make people feel comfortable sharing on
+the social web.</p>
+
+<p>Finally, we ask that you always consider that anything you put onto
+this or any other website, could be shared outside of any privacy
+controls by anyone you share it with.</p>
+
+<p><b>Put simply: if someone can see it, that person can copy it (or take
+a screenshot) and share it with the world and nobody is ever going to
+be able fix that.</b></p>
+
+<p>So please, think twice about who you identify yourself as, and what
+you post.</p>
+
+<p>With that in mind, <a href="signup2.html">we invite you to sign up</a> and please, enjoy yourself.</p>
+
+</div>
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<style type="text/css">
+@import url('http://s.libre.fm/combo.css');
+html {margin: 0; padding: 0;}
+body {width: 480px; margin: 70px auto; text-align: left; font-size: 110%; }
+
+img {border: 0;}
+
+p {text-align: left; font-weight: normal; color: #111;}
+
+li {line-height: 1.4em; margin-bottom: 1em;}
+
+ul {margin: 0; padding-left: 1em;}
+
+h1, h2, h3 {text-align: center;}
+
+#privacy {background-color: #ffb; padding: 10px; border: 2px solid orange; margin-bottom: 1em; }
+
+#signup {text-align: center;}
+
+small {font-size: 12px; color: #222;}
+
+</style>
+<title>daisycha.in — your social circle</title>
+</head>
+<body>
+<h1><a href="/"><img src="dclogo.png" alt="daisycha.in" height="58" /></a></h1>
+
+<p>To sign up, please fill out this very simple form, or <a href="#">use your OpenID</a>:</p>
+
+<hr />
+
+<form action="">
+
+<p><b>Choose your daisychain profile address:</b></p>
+
+<p>http://<input type="text" size="18" id="url" name="url" />.daisycha.in</p>
+
+<p><small>Please don't choose an offensive word, or attempt to impersonate a brand or celebrity.</small></p>
+
+<hr />
+
+<p><b>Tell us about yourself:</b></p>
+
+<p><label for="email">Email address: <input name="email" id="email" type="text" size="30" maxlength="150" /></label></p>
+
+<p><small>Please consider using a temporary email address service such
+as <a href="http://mailinator.com">Mailinator</a>, or mail forwarding
+service such as <a href="http://sneakemail.com">Sneakemail</a>, so
+that we can't identify you.</small></p>
+
+<hr />
+
+<p><b>Pick a password, enter it twice:</b></p>
+
+<p><label for="pw1">Password: <input type="password" size="30" maxlength="150" name="pw1" id="pw1" /></label></p>
+
+<p><label for="pw2">Confirmed: <input type="password" size="30" maxlength="150" name="pw2" id="pw2" /></label></p>
+
+<hr />
+
+<p><b>Last thing, we need to give you a name:</b></p>
+
+<p><label for="nm">Name: <input type="text" size="30" maxlength="150" name="nm" id="nm" /></label></p>
+
+<p><small>This really doesn't need to be your real name.</small></p>
+
+<hr />
+
+<p><label for="privacy"><input type="checkbox" name="prv" id="prv"
+/> I've read and agree with the privacy policy. </label></p>
+
+<p><label for="terms"><input type="checkbox" name="terms" id="terms"
+/> I've read and agree with the terms and conditions. </label></p>
+
+<p><label for="bad"><input type="checkbox" name="bad" id="bad"
+/> I've read this form correctly and won't check this box. </label></p>
+
+<p><input type="submit" value="Sign up" /></p>
+
+</form>
+</body>
+</html>
+
<!-- http://creativecommons.org/licenses/by/3.0/ for details. -->
%%site.name%% is a
-[micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service
-based on the Free Software [StatusNet](http://status.net/) tool.
+social network based on the Free Software [GNU social](http://www.gnu.org/software/social/) tool.
If you [register](%%action.register%%) for an account,
you can post small (%%site.textlimit%% chars or less) text notices
These are some *Frequently Asked Questions* about this service, with
some answers.
-What is %%site.name%%?
+What is this site?
----------------------
-%%site.name%% is a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service.
-You can use it to write short notices about yourself, where you are,
-and what you're doing, and those notices will be sent to all your friends
-and fans.
+This is a social network, running the GNU social software.
-How is %%site.name%% different from Twitter, Jaiku, Pownce, Plurk, others?
---------------------------------------------------------------------------
+You can use it to make connections between friends, family and
+colleagues -- writing short notices about yourself, where you are, and
+what you're doing, and those notices will be sent to all your contacts.
-%%site.name%% is an [Open Network Service](http://opendefinition.org/ossd). Our main
-goal is to provide a fair and transparent service that preserves users' autonomy. In
-particular, all the software used for %%site.name%% is [Free Software](http://en.wikipedia.org/wiki/Free_Software), and all the data is available
-under the [%%license.title%%](%%license.url%%) license, making it Open Data.
-
-The software also implements the [OpenMicroBlogging](http://openmicroblogging.org/) protocol, meaning that you can have friends on other microblogging services
-that can receive your notices.
-
-The goal here is *autonomy* -- you deserve the right to manage your own on-line
-presence. If you don't like how %%site.name%% works, you can take your data and the source code and set up your own server (or move your account to another one).
-
-Where is feature X?
--------------------
-
-The software we run, [StatusNet](http://status.net/), is still in its early stages,
-and many features people expect from microblogging sites are not yet implemented. Some important ones that are expected "soon":
-
-* More [AJAX](http://en.wikipedia.org/wiki/AJAX)-y interface
-* Maps
-* Cross-post to Pownce, Jaiku, etc.
-* Pull messages from Twitter, Pownce, Jaiku, etc.
-* [Facebook](http://www.facebook.com/) integration
-* Image, video, audio notices
-
-There is [a list of bugs and features](http://status.net/bugs/) that you may find
-interesting. New ideas or complaints are very welcome.
+In the future, we'll be adding support for photo, video and file
+sharing, as well as events, better contact management and mobile
+devices.
// TRANS: Text between [] is a link description, text between () is the link itself.
// TRANS: Make sure there is no whitespace between "]" and "(".
// TRANS: "%%site.broughtby%%" is the value of the variable site.broughtby
- $instr = _('**%%site.name%%** is a microblogging service brought to you by [%%site.broughtby%%](%%site.broughtbyurl%%).');
+ $instr = _('**%%site.name%%** is a social network, courtesy of [%%site.broughtby%%](%%site.broughtbyurl%%).');
} else {
// TRANS: First sentence of the StatusNet site license. Used if 'broughtby' is not set.
- $instr = _('**%%site.name%%** is a microblogging service.');
+ $instr = _('**%%site.name%%** is a social network.');
}
$instr .= ' ';
// TRANS: Second sentence of the StatusNet site license. Mentions the StatusNet source code license.
// TRANS: Make sure there is no whitespace between "]" and "(".
// TRANS: Text between [] is a link description, text between () is the link itself.
// TRANS: %s is the version of StatusNet that is being used.
- $instr .= sprintf(_('It runs the [StatusNet](http://status.net/) microblogging software, version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION);
+ $instr .= sprintf(_('It runs on [GNU social](http://www.gnu.org/software/social/), version %s, available under the [GNU Affero General Public License](http://www.fsf.org/licensing/licenses/agpl-3.0.html).'), STATUSNET_VERSION);
$output = common_markup_to_html($instr);
$this->raw($output);
// do it
"\n"
"Thanks for your time, \n"
"%2$s\n"
-msgstr ""
-"Hola, %1$s.\n"
+msgstr "Hola, %1$s.\n"
"\n"
"Algú ha introduït aquesta adreça electrònica a %2$s.\n"
"\n"
--- /dev/null
+GNU Social -- DukiDuki Snail
+============================
+
+Duki Duki Snail is a classic PC game, released in Czechoslovakia in
+the 1980s, and later reborn in free software in the mid 1990s.
+
+It is our intention to create a free software version of DukiDuki
+Snail for GNU social in which players can share their high scores.
+
+The game is built like such:
+
+A maze is drawn:
+
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXX XXX XXXX
+XXXX XXX XXXX
+XXXX XXX XXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXX
+XXXX XXXX XXXX
+XXXX XXXX XXXX
+XXXX XXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXX XXX XXX XXXX XXXX
+XXXX XXX XXX XXX XXX XXXX XXXX
+XXXX XXX XXX XXX XXX XXXX XXXX
+XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXX XXXX XXXXXXXXXX
+XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXX XXXX XXXXXXXXXX
+XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXX XXXX XXXXXXXXXX
+XXXX XXX XXXX XXXX XXXX XXXX XXXX
+XXXX XXX XXXX XXXX XXXX XXXX XXXX
+XXXX XXX XXXX XXXX XXXX XXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXX XXXX XXXX XXXX
+XXXX XXX XXXX XXX XXX XXXX XXXX XXXX
+XXXX XXX XXXX XXX XXX XXXX XXXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXXXXXXXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXXXXXXXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXXXXXXXXX
+XXXX XXX XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXXXXXXXXX
+XXXX XXX XXXX XXX XXXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX XXXX
+XXXX XXX XXXX XXX XXXX XXXX
+XXXX XXX XXXX XXX XXXX XXXX
+XXXX XXX XXXX XXX XXXX XXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXXXXXXXX XXXX XXXXXXXXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXXXXXXXX XXXX XXXXXXXXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXXXXXXXX XXXX XXXXXXXXXX
+XXXX XXX XXXX XXXXXXXXXXXXXXXX XXXXXXXXXX XXXX XXXXXXXXXX
+XXXX XXX XXX XXX XXXX XXX XXXX
+XXXX XXX XXX XXX XXXX XXX XXXX
+XXXX XXX XXX XXX XXXX XXX XXXX
+XXXX XXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXX XXXX XXXX XXXX XXXX
+XXXX XXX XXXX XXXX XXXX XXXX
+XXXX XXX XXXX XXXX XXXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXX XXXX
+XXXX XXX XXXX XXX XXX XXX XXXX
+XXXX XXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXXXXXXXXX XXXXXXXXXX XXXXXXXXXX XXX XXXXXXXXXX XXXX
+XXXX XXX XXX XXXX XXXX XXX XXXX
+XXXX XXX XXX XXXX XXXX XXX XXXX
+XXXX XXX XXX XXXX XXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXX XXXX XXX XXXX
+XXXX XXX XXX XXXX XXX XXXX
+XXXXXXXXXX XXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXXXXXXXX XXXX XXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXX XXXX XXX XXXX
+XXXX XXXX XXXX XXX XXXX
+XXXX XXXX XXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXX XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXX
+XXXX XXX XXX XXXX XXXX XXXX XXX XXXX
+XXXX XXX XXX XXXX XXXX XXXX XXX XXXX
+XXXX XXX XXX XXXX XXXX XXXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXX XXXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXX XXXX XXX XXXX
+XXXX XXX XXXX XXX XXXX XXXXXXXXXX XXX XXXX XXX XXXX
+XXXX XXX XXXX XXXX XXX XXX XXX XXXX
+XXXX XXX XXXX XXXX XXX XXX XXX XXXX
+XXXX XXX XXXX XXXX XXX XXX XXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+XXXX XXXXXXXXXXXXXXXXXXXXXXX XXX XXXXXXXXXXXXXXXXXXXXXXX XXXX
+ XXXX XXX
+@_K XXXX XXX [ exit ]
+ XXXX XXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXX
+
+and you must guide your snail @_K through the maze in record time.
+
+This seems like an ideal thing to build using something like <canvas> too.
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+/* Photo sharing plugin */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class GNUsocialPhotosPlugin extends Plugin
+{
+
+ function onAutoload($cls)
+ {
+ $dir = dirname(__FILE__);
+
+ include_once $dir . '/lib/tempphoto.php';
+ include_once $dir . '/lib/photonav.php';
+ switch ($cls)
+ {
+ case 'PhotosAction':
+ include_once $dir . '/lib/photolib.php';
+ include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+ break;
+ case 'PhotouploadAction':
+ include_once $dir . '/lib/photolib.php';
+ include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+ break;
+ case 'PhotoAction':
+ include_once $dir . '/lib/photolib.php';
+ include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+ break;
+ case 'EditphotoAction':
+ include_once $dir . '/lib/photolib.php';
+ include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+ break;
+ default:
+ break;
+ }
+ include_once $dir . '/classes/gnusocialphoto.php';
+ include_once $dir . '/classes/gnusocialphotoalbum.php';
+ return true;
+ }
+
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+ $schema->ensureTable('GNUsocialPhoto',
+ array(new ColumnDef('id', 'int(11)', null, false, 'PRI', null, null, true),
+ new ColumnDef('notice_id', 'int(11)', null, false),
+ new ColumnDef('album_id', 'int(11)', null, false),
+ new ColumnDef('uri', 'varchar(512)', null, false),
+ new ColumnDef('thumb_uri', 'varchar(512)', null, false),
+ new ColumnDef('title', 'varchar(512)', null, false),
+ new ColumnDef('photo_description', 'text', null, false)));
+ $schema->ensureTable('GNUsocialPhotoAlbum',
+ array(new ColumnDef('album_id', 'int(11)', null, false, 'PRI', null, null, true),
+ new ColumnDef('profile_id', 'int(11)', null, false),
+ new ColumnDef('album_name', 'varchar(256)', null, false),
+ new ColumnDef('album_description', 'text', null, false)));
+
+ }
+
+ function onRouterInitialized($m)
+ {
+ $m->connect(':nickname/photos', array('action' => 'photos'));
+ $m->connect(':nickname/photos/:albumid', array('action' => 'photos'));
+ $m->connect('main/uploadphoto', array('action' => 'photoupload'));
+ $m->connect('photo/:photoid', array('action' => 'photo'));
+ $m->connect('editphoto/:photoid', array('action' => 'editphoto'));
+ return true;
+ }
+
+ function onStartNoticeDistribute($notice)
+ {
+ common_log(LOG_INFO, "event: StartNoticeDistribute");
+ if (GNUsocialPhotoTemp::$tmp) {
+ GNUsocialPhotoTemp::$tmp->notice_id = $notice->id;
+ $photo_id = GNUsocialPhotoTemp::$tmp->insert();
+ if (!$photo_id) {
+ common_log_db_error($photo, 'INSERT', __FILE__);
+ throw new ServerException(_m('Problem saving photo.'));
+ }
+ }
+ return true;
+ }
+
+ function onEndNoticeAsActivity($notice, &$activity)
+ {
+ common_log(LOG_INFO, 'photo plugin: EndNoticeAsActivity');
+ $photo = GNUsocialPhoto::staticGet('notice_id', $notice->id);
+ if(!$photo) {
+ common_log(LOG_INFO, 'not a photo.');
+ return true;
+ }
+
+ $activity->objects[0]->type = ActivityObject::PHOTO;
+ $activity->objects[0]->thumbnail = $photo->thumb_uri;
+ $activity->objects[0]->largerImage = $photo->uri;
+ return false;
+ }
+
+
+ function onStartHandleFeedEntry($activity)
+ {
+ common_log(LOG_INFO, 'photo plugin: onEndAtomPubNewActivity');
+ $oprofile = Ostatus_profile::ensureActorProfile($activity);
+ foreach ($activity->objects as $object) {
+ if($object->type == ActivityObject::PHOTO) {
+ $uri = $object->largerImage;
+ $thumb_uri = $object->thumbnail;
+ $profile_id = $oprofile->profile_id;
+ $source = 'unknown'; // TODO: put something better here.
+
+ common_log(LOG_INFO, 'uri : ' . $uri);
+ common_log(LOG_INFO, 'thumb_uri : ' . $thumb_uri);
+
+ // It's possible this is validated elsewhere, but I'm not sure and
+ // would rather be safe.
+ $uri = filter_var($uri, FILTER_SANITIZE_URL);
+ $thumb_uri = filter_var($thumb_uri, FILTER_SANITIZE_URL);
+ $uri = filter_var($uri, FILTER_VALIDATE_URL);
+ $thumb_uri = filter_var($thumb_uri, FILTER_VALIDATE_URL);
+
+ if(empty($thumb_uri)) {
+ // We need a thumbnail, so if we aren't given one, use the actual picture for now.
+ $thumb_uri = $uri;
+ }
+
+ if (!empty($uri) && !empty($thumb_uri)) {
+ GNUsocialPhoto::saveNew($profile_id, $thumb_uri, $uri, $source, false);
+ } else {
+ common_log(LOG_INFO, 'bad URI for photo');
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
+ function onStartShowNoticeItem($action)
+ {
+ $photo = GNUsocialPhoto::staticGet('notice_id', $action->notice->id);
+ if($photo) {
+ $action->out->elementStart('div', 'entry-title');
+ $action->showAuthor();
+ $action->out->elementStart('a', array('href' => $photo->getPageLink()));
+ $action->out->element('img', array('src' => $photo->thumb_uri,
+ 'width' => 256, 'height' => 192));
+ $action->out->elementEnd('a');
+ $action->out->elementEnd('div');
+ $action->showNoticeInfo();
+ $action->showNoticeOptions();
+ return false;
+ }
+ return true;
+ }
+
+ /* function onEndShowNoticeFormData($action)
+ {
+ $link = "/main/uploadphoto";
+ $action->out->element('label', array('for' => 'photofile'),_('Attach'));
+ $action->out->element('input', array('id' => 'photofile',
+ 'type' => 'file',
+ 'name' => 'photofile',
+ 'title' => _('Upload a photo')));
+ }
+ */
+ function onEndPersonalGroupNav($nav)
+ {
+
+ $nav->out->menuItem(common_local_url('photos',
+ array('nickname' => $nav->action->trimmed('nickname'))), _('Photos'),
+ _('Photo gallery'), $nav->action->trimmed('action') == 'photos', 'nav_photos');
+ }
+
+ function onEndShowStyles($action)
+ {
+ $action->cssLink('/plugins/GNUsocialPhotos/res/style.css');
+ }
+
+ function onEndShowScripts($action)
+ {
+ $action->script('plugins/GNUsocialPhotos/res/gnusocialphotos.js');
+ }
+}
+
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Sean Corbett <sean@gnu.org>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class EditphotoAction extends Action
+{
+ var $user = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $args = $this->returnToArgs();
+ $this->user = common_current_user();
+ $this->photoid = $args[1]['photoid'];
+ $this->photo = GNUsocialPhoto::staticGet('id', $this->photoid);
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $this->handlePost();
+ }
+ $this->showPage();
+ }
+
+ function title()
+ {
+ if ($this->photo->title)
+ return _m('Edit photo - ' . $this->photo->title);
+ else
+ return _m('Edit photo');
+ }
+
+ function showContent()
+ {
+
+ if ($this->photo->album_id == 0) {
+ $this->element('p', array(), _('This photo does not exist or was deleted.'));
+ return;
+ }
+
+ if ($this->user->profile_id != $this->photo->profile_id) {
+ $this->element('p', array(), _('You are not authorized to edit this photo.'));
+ return;
+ }
+
+ //showForm() data
+ if(!empty($this->msg)) {
+ $class = ($this->success) ? 'success' : 'error';
+ $this->element('p', array('class' => $class), $this->msg);
+ }
+
+ $this->element('img', array('src' => $this->photo->uri));
+ $this->elementStart('form', array('method' => 'post',
+ 'action' => '/editphoto/' . $this->photo->id));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->input('phototitle', _("Title"), $this->photo->title, _("The title of the photo. (Optional)"));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->textarea('photo_description', _("Description"), $this->photo->photo_description, _("A description of the photo. (Optional)"));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->dropdown('album', _("Album"), $this->albumList(), _("The album in which to place this photo"), false, $this->photo->album_id);
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->submit('update', _('Update'));
+ $this->elementEnd('form');
+ $this->element('br');
+ $this->elementStart('form', array('method' => 'post',
+ 'action' => '/editphoto/' . $this->photo->id));
+ $this->element('input', array('type' => 'submit',
+ 'name' => 'delete',
+ 'value' => _('Delete Photo'),
+ 'id' => 'delete',
+ 'class' => 'submit',
+ 'onclick' => 'return confirm(\'Are you sure you would like to delete this photo?\')'));
+ $this->elementEnd('form');
+
+ }
+
+ function handlePost()
+ {
+
+ common_log(LOG_INFO, 'handlPost()!');
+
+ if ($this->photo->album_id == 0) {
+ $this->element('p', array(), _('This photo does not exist or was deleted.'));
+ return;
+ }
+
+ if ($this->user->profile_id != $this->photo->profile_id) {
+ $this->element('p', array(), _('You are not authorized to edit this photo.'));
+ return;
+ }
+
+ if ($this->arg('update')) {
+ $this->updatePhoto();
+ }
+ if ($this->arg('delete')) {
+ $this->deletePhoto();
+ }
+ }
+
+ function showForm($msg, $success=false)
+ {
+ $this->msg = $msg;
+ $this->success = $success;
+
+// $this->showPage();
+ }
+
+ function albumList()
+ {
+ $cur = common_current_user();
+ $album = new GNUsocialPhotoAlbum();
+ $album->user_id = $cur->id;
+
+ $albumlist = array();
+ if (!$album->find()) {
+ GNUsocialPhotoAlbum::newAlbum($cur->id, 'Default');
+ }
+ while ($album->fetch()) {
+ $albumlist[$album->album_id] = $album->album_name;
+ }
+ return $albumlist;
+ }
+
+ function updatePhoto()
+ {
+ $cur = common_current_user();
+ $this->photo->title = $this->trimmed('phototitle');
+ $this->photo->photo_description = $this->trimmed('photo_description');
+
+ $profile_id = $cur->id;
+
+ $album = GNUsocialPhotoAlbum::staticGet('album_id', $this->trimmed('album'));
+ if ($album->profile_id != $profile_id) {
+ $this->showForm(_('Error: This is not your album!'));
+ return;
+ }
+ $this->photo->album_id = $album->album_id;
+ if ($this->photo->validate())
+ $this->photo->update();
+ else {
+ $this->showForm(_('Error: The photo data is not valid.'));
+ return;
+ }
+ common_redirect('/photo/' . $this->photo->id, '303');
+ $this->showForm(_('Success!'), true);
+
+ }
+
+ function deletePhoto()
+ {
+ //For redirection
+ $oldalbum = $this->album_id;
+
+ $notice = Notice::staticGet('id', $this->photo->notice_id);
+
+ $this->photo->delete();
+
+ if (Event::handle('StartDeleteOwnNotice', array($this->user, $notice))) {
+ $notice->delete();
+ Event::handle('EndDeleteOwnNotice', array($this->user, $notice));
+ }
+ $this->showForm(_('Success!'));
+ common_redirect('/' . $this->user->nickname . '/photos/' . $oldalbum, '303');
+ return;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Sean Corbett <sean@gnu.org>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+include_once INSTALLDIR . '/actions/conversation.php';
+include_once INSTALLDIR . '/classes/Notice.php';
+
+class PhotoAction extends Action
+{
+ var $user = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $args = $this->returnToArgs();
+ $this->photoid = $args[1]['photoid'];
+ $this->photo = GNUsocialPhoto::staticGet('id', $this->photoid);
+ $this->notice = Notice::staticGet('id', $this->photo->notice_id);
+
+ $this->user = Profile::staticGet('id', $this->notice->profile_id);
+
+ $notices = Notice::conversationStream((int)$this->notice->conversation, null, null);
+ $this->conversation = new ConversationTree($notices, $this);
+ return true;
+
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ function title()
+ {
+ if (empty($this->user)) {
+ return _m('No such user.');
+ } else if (empty($this->photo)) {
+ return _m('No such photo.');
+ } else if (!empty($this->photo->title)) {
+ return $this->photo->title;
+ } else {
+ return sprintf(_m("%s's Photo."), $this->user->nickname);
+ }
+ }
+
+ function showLocalNav()
+ {
+ $nav = new GNUsocialPhotoNav($this, $this->user->nickname);
+ $nav->show();
+ }
+
+ function showContent()
+ {
+ if(empty($this->user)) {
+ return;
+ }
+
+ $this->elementStart('a', array('href' => $this->photo->uri));
+ $this->element('img', array('src' => $this->photo->uri));
+ $this->elementEnd('a');
+
+ //Image "toolbar"
+ $cur = common_current_user();
+ if($this->photo->profile_id == $cur->profile_id) {
+ $this->elementStart('div', array('id' => 'image_toolbar'));
+ $this->element('a', array('href' => '/editphoto/' . $this->photo->id), 'Edit');
+ $this->elementEnd('div');
+ }
+
+ $this->element('p', array('class' => 'photodescription'), $this->photo->photo_description);
+ //This is a hack to hide the top-level comment
+ $this->element('style', array(), "#notice-{$this->photo->notice_id} div { display: none } #notice-{$this->photo->notice_id} ol li div { display: inline }");
+ $this->conversation->show();
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Sean Corbett <sean@gnu.org>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/personalgroupnav.php';
+
+class PhotosAction extends Action
+{
+ var $user = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $args = $this->returnToArgs();
+ $username = $args[1]['nickname'];
+ $this->albumid = $args[1]['albumid'];
+ if (common_valid_profile_tag($username) == 0) {
+ $this->user = null;
+ } else {
+ $this->user = Profile::staticGet('nickname', $username);
+ }
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ function title()
+ {
+ if (empty($this->user)) {
+ return _m('No such user.');
+ } else {
+ return sprintf(_m("%s's Photos."), $this->user->nickname);
+ }
+ }
+
+ function showLocalNav()
+ {
+ $nav = new PersonalGroupNav($this);
+ $nav->show();
+ }
+
+ function showResizeImagesBox()
+ {
+ $this->elementStart('select', array('onchange' => 'return scalePhotosToSize(this.value)'));
+ $this->element('option', array('value' => ''), "");
+ $this->element('option', array('value' => '60'), _("Thumbnail"));
+ $this->element('option', array('value' => '120'), _("Medium"));
+ $this->element('option', array('value' => '400'), _("Normal"));
+ $this->elementEnd('select');
+ }
+
+ function showAlbums()
+ {
+ $album = new GNUsocialPhotoAlbum();
+ $album->profile_id = $this->user->id;
+
+ $albums = array();
+ if (!$album->find()) {
+ GNUsocialPhotoAlbum::newAlbum($this->user->id, 'Default');
+ }
+
+ $this->elementStart('div', array('class' => 'galleryheader'));
+ //$this->element('a', array('href' => '#',
+ // 'onclick' => 'return increasePhotoSize()'), '+');
+ //$this->raw(' | ');
+ //$this->element('a', array('href' => '#',
+ // 'onclick' => 'return decreasePhotoSize()'), '-');
+
+ $this->showResizeImagesBox();
+ $this->elementEnd('div');
+
+
+
+ while ($album->fetch()) {
+ $this->elementStart('div', array('class' => 'photocontainer'));
+ $this->elementStart('a', array('href' => $album->getPageLink()));
+ $this->element('img', array('src' => $album->getThumbUri(),
+ 'class' => 'albumingallery'));
+ $this->elementEnd('a');
+ $this->element('h3', array(), $album->album_name);
+ $this->elementEnd('div');
+ }
+
+ }
+
+ function showAlbum($album_id)
+ {
+ $album = GNUSocialPhotoAlbum::staticGet('album_id', $album_id);
+ if (!$album) {
+ return;
+ }
+
+ $page = $_GET['pageid'];
+ if (!filter_var($page, FILTER_VALIDATE_INT)){
+ $page = 1;
+ }
+
+ $photos = GNUsocialPhoto::getGalleryPage($page, $album->album_id, 9);
+ $this->elementStart('div', array('class' => 'galleryheader'));
+ if ($page > 1) {
+ $this->element('a', array('href' => $album->getPageLink() . '?pageid=' . ($page-1)), 'Previous page');
+ $this->raw(' | ');
+ }
+ if (GNUsocialPhoto::getGalleryPage($page+1, $album->album_id, 9)) {
+ $this->element('a', array('href' => $album->getPageLink() . '?pageid=' . ($page+1) ), 'Next page');
+ $this->raw(' | ');
+ }
+
+ //$this->element('a', array('href' => '#',
+ // 'onclick' => 'return increasePhotoSize()'), '+');
+ //$this->raw(' | ');
+ //$this->element('a', array('href' => '#',
+ // 'onclick' => 'return decreasePhotoSize()'), '-');
+ //$this->raw(' | ');
+
+ $this->showResizeImagesBox();
+ $this->elementEnd('div');
+
+ foreach ($photos as $photo) {
+ $this->elementStart('a', array('href' => $photo->getPageLink()));
+ $this->elementStart('div', array('class' => 'photocontainer'));
+ $this->element('img', array('src' => $photo->thumb_uri,
+ 'class' => 'photoingallery'));
+ $this->element('div', array('class' => 'phototitle'), $photo->title);
+ $this->elementEnd('div');
+ $this->elementEnd('a');
+ }
+
+ }
+
+
+ function showContent()
+ {
+ if (!empty($this->albumid))
+ $this->showAlbum($this->albumid);
+ else
+ $this->showAlbums();
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Sean Corbett <sean@gnu.org>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class PhotouploadAction extends Action
+{
+ var $user = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->user = common_current_user();
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $this->handlePost();
+ }
+ $this->showPage();
+ }
+
+ function title()
+ {
+ return _m('Upload Photos');
+ }
+
+ function showContent()
+ {
+ //Upload a photo
+ if(empty($this->user)) {
+ $this->element('p', array(), 'You are not logged in.');
+ } else {
+ //showForm() data
+ if(!empty($this->msg)) {
+ $class = ($this->success) ? 'success' : 'error';
+ $this->element('p', array('class' => $class), $this->msg);
+ }
+
+ $this->elementStart('form', array('enctype' => 'multipart/form-data',
+ 'method' => 'post',
+ 'action' => common_local_url('photoupload')));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->element('input', array('name' => 'photofile',
+ 'type' => 'file',
+ 'id' => 'photofile'));
+ $this->elementEnd('li');
+ //$this->element('br');
+ $this->elementStart('li');
+ $this->input('phototitle', _("Title"), null, _("The title of the photo. (Optional)"));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->textarea('photo_description', _("Description"), null, _("A description of the photo. (Optional)"));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->dropdown('album', _("Album"), $this->albumList(), _("The album in which to place this photo"), false);
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->submit('upload', _('Upload'));
+ $this->elementEnd('form');
+ $this->element('br');
+
+ //Create a new album
+ $this->element('h3', array(), _("Create a new album"));
+ $this->elementStart('form', array('method' => 'post',
+ 'action' =>common_local_url('photoupload')));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->input('album_name', _("Title"), null, _("The title of the album."));
+ $this->elementEnd('li');
+ $this->elementStart('li');
+ $this->textarea('album_description', _("Description"), null, _("A description of the album. (Optional)"));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->submit('create', _('Create'));
+ $this->elementEnd('form');
+
+ //Delete an album
+ $this->element('h3', array(), _("Delete an album"));
+ $this->elementStart('form', array('method' => 'post',
+ 'action' =>common_local_url('photoupload')));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->dropdown('album', _("Album"), $this->albumList(), _("The album in which to place this photo"), false);
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->submit('deletealbum', _('Delete'));
+ $this->elementEnd('form');
+
+ }
+ }
+
+ function handlePost()
+ {
+
+ common_log(LOG_INFO, 'handlPost()!');
+ // Workaround for PHP returning empty $_POST and $_FILES when POST
+ // length > post_max_size in php.ini
+
+ if (empty($_FILES)
+ && empty($_POST)
+ && ($_SERVER['CONTENT_LENGTH'] > 0)
+ ) {
+ $msg = _('The server was unable to handle that much POST ' .
+ 'data (%s bytes) due to its current configuration.');
+
+ $this->showForm(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
+ return;
+ }
+
+ // CSRF protection
+
+/* $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ $this->showForm(_('There was a problem with your session token. '.
+ 'Try again, please.'));
+ return;
+ } */
+
+ if ($this->arg('upload')) {
+ $this->uploadPhoto();
+ }
+ if ($this->arg('create')) {
+ $this->createAlbum();
+ }
+ if ($this->arg('deletealbum')) {
+ $this->deleteAlbum();
+ }
+ }
+
+ function showForm($msg, $success=false)
+ {
+ $this->msg = $msg;
+ $this->success = $success;
+
+// $this->showPage();
+ }
+
+ function albumList()
+ {
+ $cur = common_current_user();
+ $album = new GNUsocialPhotoAlbum();
+ $album->user_id = $cur->id;
+
+ $albumlist = array();
+ if (!$album->find()) {
+ GNUsocialPhotoAlbum::newAlbum($cur->id, 'Default');
+ }
+ while ($album->fetch()) {
+ $albumlist[$album->album_id] = $album->album_name;
+ }
+ return $albumlist;
+ }
+
+ function uploadPhoto()
+ {
+ $cur = common_current_user();
+ if(empty($cur)) {
+ return;
+ }
+ try {
+ $imagefile = ImageFile::fromUpload('photofile');
+ } catch (Exception $e) {
+ $this->showForm($e->getMessage());
+ return;
+ }
+ if ($imagefile === null) {
+ $this->showForm(_('No file uploaded.'));
+ return;
+ }
+
+ $title = $this->trimmed('phototitle');
+ $photo_description = $this->trimmed('photo_description');
+
+ common_log(LOG_INFO, 'upload path : ' . $imagefile->filepath);
+
+ $filename = $cur->nickname . '-' . common_timestamp() . sha1_file($imagefile->filepath) . image_type_to_extension($imagefile->type);
+ move_uploaded_file($imagefile->filepath, INSTALLDIR . '/file/' . $filename);
+ photo_make_thumbnail($filename);
+ $uri = 'http://' . common_config('site', 'server') . '/file/' . $filename;
+ $thumb_uri = 'http://' . common_config('site', 'server') . '/file/thumb.' . $filename;
+ $profile_id = $cur->id;
+
+ $album = GNUsocialPhotoAlbum::staticGet('album_id', $this->trimmed('album'));
+ if ($album->profile_id != $profile_id) {
+ $this->showForm(_('Error: This is not your album!'));
+ return;
+ }
+ GNUsocialPhoto::saveNew($profile_id, $album->album_id, $thumb_uri, $uri, 'web', false, $title, $photo_description);
+ }
+
+ function createAlbum()
+ {
+ $cur = common_current_user();
+ if(empty($cur)) {
+ return;
+ }
+
+ $album_name = $this->trimmed('album_name');
+ $album_description = $this->trimmed('album_description');
+
+ GNUsocialPhotoAlbum::newAlbum($cur->id, $album_name, $album_description);
+ }
+
+ function deleteAlbum()
+ {
+ $cur = common_current_user();
+ if(empty($cur)) return;
+
+ $album_id = $this->trimmed('album');
+ $album = GNUsocialPhotoAlbum::staticGet('album_id', $album_id);
+ if (empty($album)) {
+ $this->showForm(_('This album does not exist or has been deleted.'));
+ return;
+ }
+ //Check if the album has any photos in it before deleting
+ $photos = GNUsocialPhoto::staticGet('album_id', $album_id);
+ if(empty($photos)) {
+ $album->delete();
+ $this->showForm(_('Album deleted'), true);
+ }
+ else {
+ $this->showForm(_('Cannot delete album when there are photos in it!'), false);
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+class GNUsocialPhoto extends Memcached_DataObject
+{
+ public $__table = 'GNUsocialPhoto';
+ public $id; // int(11)
+ public $notice_id; // int(11)
+ public $album_id; // int(11)
+ public $uri; // varchar(512)
+ public $thumb_uri; // varchar(512)
+ public $title; // varchar(512)
+ public $photo_description; // text
+
+
+ /**
+ *
+ * k key
+ * v value
+ */
+ function staticGet($k,$v=NULL)
+ {
+ return Memcached_DataObject::staticGet('GNUsocialPhoto',$k,$v);
+ }
+
+/* function delete()
+ {
+ if(!unlink(INSTALLDIR . $this->thumb_uri)) {
+ return false;
+ }
+ if(!unlink(INSTALLDIR . $this->path)) {
+ return false;
+ }
+ return parent::delete();
+ } */
+
+
+ /*
+ * TODO: Foriegn key on album_id.
+ */
+ function table()
+ {
+ return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'notice_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'album_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'thumb_uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'title' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'photo_description' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL);
+ }
+
+ function keys()
+ {
+ return array_keys($this->keyTypes());
+ }
+
+ function keyTypes()
+ {
+ return array('notice_id' => 'K');
+ }
+
+ function sequenceKey()
+ {
+ return array(false, false, false);
+ }
+
+ function saveNew($profile_id, $album_id, $thumb_uri, $uri, $source, $insert_now, $title = null, $photo_description = null)
+ {
+ $photo = new GNUsocialPhoto();
+ $photo->thumb_uri = $thumb_uri;
+ $photo->uri = $uri;
+ $photo->album_id = $album_id;
+ if(!empty($title)) $photo->title = $title;
+ if(!empty($photo_description)) $photo->photo_description = (string)$photo_description;
+
+ if($insert_now) {
+ $notice = Notice::saveNew($profile_id, $uri, $source);
+ $photo->notice_id = $notice->id;
+ $photo_id = $photo->insert();
+ if (!$photo_id) {
+ common_log_db_error($photo, 'INSERT', __FILE__);
+ throw new ServerException(_m('Problem Saving Photo.'));
+ }
+ } else {
+ GNUsocialPhotoTemp::$tmp = $photo;
+ Notice::saveNew($profile_id, $uri, $source);
+ }
+ }
+
+ function getPageLink()
+ {
+ return '/photo/' . $this->id;
+ }
+
+ /*
+ * TODO: -Sanitize input
+ * @param int page_id The desired page of the gallery to show.
+ * @param int album_id The id of the album to get photos from.
+ * @param int gallery_size The number of thumbnails to show per page in the gallery.
+ * @return array Array of GNUsocialPhotos for this gallery page.
+ */
+ static function getGalleryPage($page_id, $album_id, $gallery_size)
+ {
+ $page_offset = ($page_id-1) * $gallery_size;
+ $sql = 'SELECT * FROM GNUsocialPhoto WHERE album_id = ' . $album_id .
+ ' ORDER BY notice_id LIMIT ' . $page_offset . ',' . $gallery_size;
+ $photo = new GNUsocialPhoto();
+ $photo->query($sql);
+ $photos = array();
+
+ while ($photo->fetch()) {
+ $photos[] = clone($photo);
+ }
+
+ return $photos;
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Sean Corbett <sean@gnu.org>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+class GNUsocialPhotoAlbum extends Memcached_DataObject
+{
+ public $__table = 'GNUsocialPhotoAlbum';
+ public $album_id; // int(11) -- Unique identifier for the album
+ public $profile_id; // int(11) -- Profile ID for the owner of the album
+ public $album_name; // varchar(256) -- Title for this album
+ public $album_description; // text -- A description of the album
+
+
+ function staticGet($k,$v=NULL)
+ {
+ return Memcached_DataObject::staticGet('GNUsocialPhotoAlbum',$k,$v);
+ }
+
+
+ /* TODO: Primary key on both album_id, profile_id / foriegn key on profile_id */
+ function table()
+ {
+ return array('album_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'album_name' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'album_description' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL);
+ }
+
+ function keys()
+ {
+ return array_keys($this->keyTypes());
+ }
+
+
+ /* Using album_id as the primary key for now.. */
+ function keyTypes()
+ {
+ return array('album_id' => 'K');
+ }
+
+ function sequenceKey()
+ {
+ return array('album_id', true, false);
+ }
+
+ function getPageLink()
+ {
+ $profile = Profile::StaticGet('id', $this->profile_id);
+ return '/' . $profile->nickname . '/photos/' . $this->album_id;
+ }
+
+ function getThumbUri()
+ {
+ $photo = GNUsocialPhoto::staticGet('album_id', $this->album_id);
+ if (empty($photo))
+ return '/theme/default/default-avatar-profile.png'; //For now...
+ return $photo->thumb_uri;
+ }
+
+ static function newAlbum($profile_id, $album_name, $album_description)
+ {
+ //TODO: Should use foreign key instead...
+ if (!Profile::staticGet('id', $profile_id)){
+ //Is this a bit extreme?
+ throw new ServerException(_m('No such user exists with id ' . $profile_id . ', couldn\'t create album.'));
+ }
+
+ $album = new GNUsocialPhotoAlbum();
+ $album->profile_id = $profile_id;
+ $album->album_name = $album_name;
+ $album->album_description = $album_description;
+
+ $album->album_id = $album->insert();
+ if (!$album->album_id){
+ common_log_db_error($album, 'INSERT', __FILE__);
+ throw new ServerException(_m('Error creating new album.'));
+ }
+ common_log(LOG_INFO, 'album_id : ' . $album->album_id);
+ return $album;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+
+function photo_make_thumbnail($filename)
+{
+ $height_dest = 192;
+ $width_dest = 256;
+
+ $size_src = getimagesize(INSTALLDIR . '/file/' . $filename);
+ $image_type = $size_src[2];
+
+ switch($image_type) {
+ case IMAGETYPE_JPEG:
+ $image_src = imagecreatefromjpeg(INSTALLDIR . '/file/' . $filename);
+ break;
+ case IMAGETYPE_PNG:
+ $image_src = imagecreatefrompng(INSTALLDIR . '/file/' . $filename);
+ break;
+ case IMAGETYPE_GIF:
+ $image_src = imagecreatefromgif(INSTALLDIR . '/file/' . $filename);
+ break;
+ default:
+ return false;
+ }
+
+ $width_src = $size_src[0];
+ $height_src = $size_src[1];
+
+ $ratio_src = (float) $width_src / (float) $height_src;
+ $ratio_dest = (float) $width_dest / (float) $height_dest;
+
+ if ($ratio_src > $ratio_dest) {
+ $height_crop = $height_src;
+ $width_crop = (int)($height_crop * $ratio_dest);
+ $x_crop = ($width_src - $width_crop) / 2;
+ } else {
+ $width_crop = $width_src;
+ $height_crop = (int)($width_crop / $ratio_dest);
+ $x_crop = 0;
+ }
+
+ $image_dest = imagecreatetruecolor($width_dest, $height_dest);
+
+ imagecopyresampled($image_dest, $image_src, 0, 0, $x_crop, 0, $width_dest, $height_dest, $width_crop, $height_crop);
+ switch ($image_type) {
+ case IMAGETYPE_JPEG:
+ imagejpeg($image_dest, INSTALLDIR . '/file/' . 'thumb.' . $filename, 100);
+ break;
+ case IMAGETYPE_PNG:
+ imagepng($image_dest, INSTALLDIR . '/file/thumb.' . $filename);
+ break;
+ case IMAGETYPE_GIF:
+ imagegif($image_dest, INSTALLDIR . '/file/thumb.' . $filename);
+ break;
+ }
+
+ imagedestroy($image_src);
+ imagedestroy($image_dest);
+
+ return true;
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')) {
+ exit(1);
+}
+
+class GNUsocialPhotoNav extends Widget {
+ var $action = null;
+
+ function __construct($action = null, $nickname = null)
+ {
+ parent::__construct($action);
+ $this->action = $action;
+ $this->nickname = $nickname;
+ }
+
+ function show()
+ {
+ if (empty($this->nickname))
+ $this->nickname = $this->action->trimmed('nickname');
+
+ $this->out->elementStart('ul', array('class' => 'nav'));
+
+ $this->out->menuItem(common_local_url('showstream', array('nickname' => $this->nickname)), _('Profile'));
+
+ $this->out->menuItem(common_local_url('photos', array('nickname' => $this->nickname)),
+ _('Photos'));
+
+ $user = common_current_user();
+ if (!empty($user)) {
+ $this->out->menuItem(common_local_url('photoupload', array()),
+ _('Upload Photos'));
+ }
+
+ $this->out->elementEnd('ul');
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+// XXX: This entire file is an ugly hack and needs to be replaced. It is essentially a global variable
+// used to store information about a photo we want to insert in onStartNoticeDistribute(), which we
+// can't actually pass to that function.
+class GNUsocialPhotoTemp {
+ public static $tmp = null;
+}
--- /dev/null
+function increasePhotoSize() {
+ $('.photoingallery, .albumingallery').each(function(index) {
+ this.height *= 1.1;
+ this.width *= 1.1;
+ });
+ return false;
+}
+
+function decreasePhotoSize() {
+ $('.photoingallery, .albumingallery').each(function(index) {
+ this.height /= 1.1;
+ this.width /= 1.1;
+ });
+ return false;
+}
+
+function scalePhotosToSize(size) {
+ $('.photoingallery, .albumingallery').each(function(index) {
+ if(this.height > this.width) {
+ this.width = this.width*size/this.height;
+ this.height = size;
+ }
+ else {
+ this.height = this.height*size/this.width;
+ this.width = size;
+ }
+ });
+ return false;
+}
\ No newline at end of file
--- /dev/null
+.photocontainer, .albumcontainer {
+ display: block;
+ background-color: yellow;
+ float: left;
+ padding: 20px;
+ margin: 15px;
+}
+
+.photodescription {
+ display: block;
+ background-color: #dddddd;
+ padding: 20px;
+ margin: 15px;
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class GNUsocialProfileExtensionsPlugin extends Plugin
+{
+
+ function onAutoload($cls)
+ {
+ $dir = dirname(__FILE__);
+
+ switch ($cls)
+ {
+ case 'BioAction':
+ case 'NewresponseAction':
+ include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+ break;
+ case 'ProfilefieldsAdminPanelAction':
+ include_once $dir . '/actions/' . strtolower(mb_substr($cls, 0, -16)) . '.php';
+ break;
+ default:
+ break;
+ }
+ include_once $dir . '/classes/GNUsocialProfileExtensionField.php';
+ include_once $dir . '/classes/GNUsocialProfileExtensionResponse.php';
+ include_once $dir . '/lib/profiletools.php';
+ include_once $dir . '/lib/noticetree.php';
+ return true;
+ }
+
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+ $schema->ensureTable('GNUsocialProfileExtensionField',
+ array(new ColumnDef('id', 'int(11)', null, false, 'PRI', null, null, true),
+ new ColumnDef('systemname', 'varchar(64)', null, false),
+ new ColumnDef('title', 'varchar(256)', null, false),
+ new ColumnDef('description', 'text', null, false),
+ new ColumnDef('type', 'varchar(256)', null, false)));
+ $schema->ensureTable('GNUsocialProfileExtensionResponse',
+ array(new ColumnDef('id', 'int(11)', null, false, 'PRI', null, null, true),
+ new ColumnDef('extension_id', 'int(11)', null, false),
+ new ColumnDef('profile_id', 'int(11)', null, false),
+ new ColumnDef('value', 'text', null, false)));
+
+ }
+
+ function onRouterInitialized($m)
+ {
+ $m->connect(':nickname/bio', array('action' => 'bio'));
+ $m->connect('admin/profilefields', array('action' => 'profilefieldsAdminPanel'));
+ $m->connect('notice/respond', array('action' => 'newresponse'));
+ return true;
+ }
+
+ function onEndProfileFormData($action)
+ {
+ $fields = GNUsocialProfileExtensionField::allFields();
+ $user = common_current_user();
+ $profile = $user->getProfile();
+ gnusocial_profile_merge($profile);
+ foreach ($fields as $field) {
+ $action->elementStart('li');
+ $fieldname = $field->systemname;
+ if ($field->type == 'str') {
+ $action->input($fieldname, $field->title,
+ ($action->arg($fieldname)) ? $action->arg($fieldname) : $profile->$fieldname,
+ $field->description);
+ }
+ else if ($field->type == 'text') {
+ $action->textarea($fieldname, $field->title,
+ ($action->arg($fieldname)) ? $action->arg($fieldname) : $profile->$fieldname,
+ $field->description);
+ }
+ $action->elementEnd('li');
+ }
+ }
+
+ function onEndProfileSaveForm($action)
+ {
+ $fields = GNUsocialProfileExtensionField::allFields();
+ $user = common_current_user();
+ $profile = $user->getProfile();
+ foreach ($fields as $field) {
+ $val = $action->trimmed($field->systemname);
+
+ $response = new GNUsocialProfileExtensionResponse();
+ $response->profile_id = $profile->id;
+ $response->extension_id = $field->id;
+
+ if ($response->find()) {
+ $response->fetch();
+ $response->value = $val;
+ if ($response->validate()) {
+ if (empty($val))
+ $response->delete();
+ else
+ $response->update();
+ }
+ }
+ else {
+ $response->value = $val;
+ $response->insert();
+ }
+ }
+ }
+
+ function onEndShowStyles($action)
+ {
+ $action->cssLink('/plugins/GNUsocialProfileExtensions/res/style.css');
+ }
+
+ function onEndShowScripts($action)
+ {
+ $action->script('plugins/GNUsocialProfileExtensions/js/profile.js');
+ }
+
+ function onEndAdminPanelNav($nav)
+ {
+ if (AdminPanelAction::canAdmin('profilefields')) {
+
+ $action_name = $nav->action->trimmed('action');
+
+ $nav->out->menuItem(
+ '/admin/profilefields',
+ _m('Profile Fields'),
+ _m('Custom profile fields'),
+ $action_name == 'profilefieldsadminpanel',
+ 'nav_profilefields_admin_panel'
+ );
+ }
+
+ return true;
+ }
+
+ function onStartPersonalGroupNav($nav)
+ {
+ $nav->out->menuItem(common_local_url('bio',
+ array('nickname' => $nav->action->trimmed('nickname'))), _('Bio'),
+ _('The user\'s extended profile'), $nav->action->trimmed('action') == 'bio', 'nav_bio');
+ }
+
+ //Why the heck is this shoved into this plugin!?!? It deserves its own!
+ function onShowStreamNoticeList($notice, $action, &$pnl)
+ {
+ //TODO: This function is called after the notices in $notice are superfluously retrieved in showstream.php
+ $newnotice = new Notice();
+ $newnotice->profile_id = $action->user->id;
+ $newnotice->orderBy('modified DESC');
+ $newnotice->whereAdd('reply_to IS NULL');
+ $newnotice->limit(($action->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
+ $newnotice->find();
+
+ $pnl = new NoticeTree($newnotice, $action);
+ return false;
+ }
+
+}
+
--- /dev/null
+GNU Social Profile Extensions
+=============================
+
+Allows administrators to define additional profile fields for the
+users of a GNU Social installation.
+
+
+Installation
+------------
+
+To install, copy this directory into your plugins directory and add
+the following lines to your config.php file:
+
+addPlugin('GNUsocialProfileExtensions');
+$config['admin']['panels'][] = 'profilefields';
+
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/lib/personalgroupnav.php';
+require_once INSTALLDIR . '/classes/Profile.php';
+require_once INSTALLDIR . '/lib/profilelist.php';
+
+class BioAction extends Action
+{
+ var $user = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+
+ $args = $this->returnToArgs();
+ $this->profile = Profile::staticGet('nickname', $args[1]['nickname']);
+ //die(print_r($this->profile));
+ gnusocial_profile_merge($this->profile);
+ $this->avatar = $this->profile->getAvatar(96);
+
+ return true;
+
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ function title()
+ {
+ return sprintf(_m("%s's Bio."), $this->profile->nickname);
+ }
+
+ function showLocalNav()
+ {
+ $nav = new PersonalGroupNav($this);
+ $nav->show();
+ }
+
+ function showContent()
+ {
+ if(empty($this->profile)) {
+ return;
+ }
+
+ $profilelistitem = new ProfileListItem($this->profile, $this);
+ $profilelistitem->show();
+ $this->elementStart('ul');
+ $fields = GNUsocialProfileExtensionField::allFields();
+ foreach ($fields as $field) {
+ $fieldname = $field->systemname;
+ if (!empty($this->profile->$fieldname)) {
+ $this->elementStart('li', array('class' => 'biolistitem'));
+ $this->elementStart('div', array('class' => 'biolistitemcontainer'));
+ if ($field->type == 'text') {
+ $this->element('h3', array(), $field->title);
+ $this->element('p', array('class' => 'biovalue'), $this->profile->$fieldname);
+ }
+ else {
+ $this->element('span', array('class' => 'biotitle'), $field->title);
+ $this->text(' ');
+ $this->element('span', array('class' => 'biovalue'), $this->profile->$fieldname);
+ }
+ $this->elementEnd('div');
+ $this->elementEnd('li');
+ }
+ }
+ $this->elementEnd('ul');
+ }
+
+}
+
+
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+require_once INSTALLDIR . '/actions/newnotice.php';
+
+class NewresponseAction extends NewnoticeAction
+{
+ /**
+ * Same as the parent, but not including the @-whoever in replies
+ *
+ * @return void
+ */
+
+ function showNoticeForm()
+ {
+ $content = $this->trimmed('status_textarea');
+ if (!$content) {
+ $replyto = $this->trimmed('replyto');
+ $inreplyto = $this->trimmed('inreplyto');
+ } else {
+ // @fixme most of these bits above aren't being passed on above
+ $inreplyto = null;
+ }
+
+ $notice_form = new NoticeForm($this, '', $content, null, $inreplyto);
+ $notice_form->show();
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/lib/adminpanelaction.php';
+
+class ProfilefieldsAdminPanelAction extends AdminPanelAction
+{
+
+ function title()
+ {
+ return _('Profile fields');
+ }
+
+ function getInstructions()
+ {
+ return _('GNU Social custom profile fields');
+ }
+
+ function showForm()
+ {
+ $form = new ProfilefieldsAdminForm($this);
+ $form->show();
+ return;
+ }
+
+ function saveSettings()
+ {
+ $field = GNUsocialProfileExtensionField::staticGet('id', $this->trimmed('id'));
+ if (!$field)
+ $field = new GNUsocialProfileExtensionField();
+ $field->title = $this->trimmed('title');
+ $field->description = $this->trimmed('description');
+ $field->type = $this->trimmed('type');
+ $field->systemname = $this->trimmed('systemname');
+ if (!gnusocial_field_systemname_validate($field->systemname)) {
+ $this->clientError(_('Internal system name must be unique and consist of only alphanumeric characters!'));
+ return false;
+ }
+ if ($field->id) {
+ if ($field->validate())
+ $field->update();
+ else {
+ $this->clientError(_('There was an error with the field data.'));
+ return false;
+ }
+ }
+ else {
+ $field->insert();
+ }
+
+ return;
+ }
+
+}
+
+class ProfilefieldsAdminForm extends AdminForm
+{
+
+ function id()
+ {
+ return 'form_profilefields_admin_panel';
+ }
+
+ function formClass()
+ {
+ return 'form_settings';
+ }
+
+ function action()
+ {
+ return '/admin/profilefields';
+ }
+
+ function formData()
+ {
+ $title = null;
+ $description = null;
+ $type = null;
+ $systemname = null;
+ $id = null;
+ $fieldsettitle = _("New Profile Field");
+ //Edit a field
+ if ($this->out->trimmed('edit')) {
+ $field = GNUsocialProfileExtensionField::staticGet('id', $this->out->trimmed('edit'));
+ $title = $field->title;
+ $description = $field->description;
+ $type = $field->type;
+ $systemname = $field->systemname;
+ $this->out->hidden('id', $field->id, 'id');
+ $fieldsettitle = _("Edit Profile Field");
+ }
+ //Don't show the list of all fields when editing one
+ else {
+ $this->out->elementStart('fieldset');
+ $this->out->element('legend', null, _('Existing Custom Profile Fields'));
+ $this->out->elementStart('ul', 'form_data');
+ $fields = GNUsocialProfileExtensionField::allFields();
+ foreach ($fields as $field) {
+ $this->li();
+ $content =
+ $this->out->elementStart('div');
+ $this->out->element('a', array('href' => '/admin/profilefields?edit=' . $field->id),
+ $field->title);
+ $this->out->text(' (' . $field->type . '): ' . $field->description);
+ $this->out->elementEnd('div');
+ $this->unli();
+ }
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ //New fields
+ $this->out->elementStart('fieldset');
+ $this->out->element('legend', null, $fieldsettitle);
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('title', _('Title'), $title,
+ _('The title of the field'));
+ $this->unli();
+ $this->li();
+ $this->out->input('systemname', _('Internal name'), $systemname,
+ _('The alphanumeric name used internally for this field. Also the key used in OStatus user info. (optional)'));
+ $this->unli();
+ $this->li();
+ $this->out->input('description', _('Description'), $description,
+ _('An optional more detailed description of the field'));
+ $this->unli();
+ $this->li();
+ $this->out->dropdown('type', _('Type'), array('text' => _("Text"),
+ 'str' => _("String")),
+ _('The type of the datafield'), false, $type);
+ $this->unli();
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ /**
+ * Action elements
+ *
+ * @return void
+ */
+
+ function formActions()
+ {
+ $this->out->submit('submit', _('Save'), 'submit', null, _('Save new field'));
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+class GNUsocialProfileExtensionField extends Memcached_DataObject
+{
+ public $__table = 'GNUsocialProfileExtensionField';
+ public $id; // int(11)
+ public $systemname; // varchar(64)
+ public $title; // varchar(256)
+ public $description; // text
+ public $type; // varchar(256)
+
+ /**
+ *
+ * k key
+ * v value
+ */
+ function staticGet($k,$v=NULL)
+ {
+ return Memcached_DataObject::staticGet('GNUsocialProfileExtensionField',$k,$v);
+ }
+
+
+ function table()
+ {
+ return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'systemname' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'title' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'description' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'type' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL);
+ }
+
+ function keys()
+ {
+ return array_keys($this->keyTypes());
+ }
+
+ function keyTypes()
+ {
+ return array('id' => 'K');
+ }
+
+ function sequenceKey()
+ {
+ return array(false, false, false);
+ }
+
+ static function newField($title, $description=null, $type='str', $systemname=null)
+ {
+ $field = new GNUsocialProfileExtensionField();
+ $field->title = $title;
+ $field->description = $description;
+ $field->type = $type;
+ if (empty($systemname))
+ $field->systemname = 'field' + $field->id;
+ else
+ $field->systemname = $systemname;
+
+ $field->id = $field->insert();
+ if (!$field->id){
+ common_log_db_error($field, 'INSERT', __FILE__);
+ throw new ServerException(_m('Error creating new field.'));
+ }
+ return $field;
+ }
+
+ static function allFields()
+ {
+ $field = new GNUsocialProfileExtensionField();
+ $fields = array();
+ if ($field->find()) {
+ while($field->fetch()) {
+ $fields[] = clone($field);
+ }
+ }
+ return $fields;
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+class GNUsocialProfileExtensionResponse extends Memcached_DataObject
+{
+ public $__table = 'GNUsocialProfileExtensionResponse';
+ public $id; // int(11)
+ public $extension_id; // int(11)
+ public $profile_id; // int(11)
+ public $value; // text
+
+ /**
+ *
+ * k key
+ * v value
+ */
+ function staticGet($k,$v=NULL)
+ {
+ return Memcached_DataObject::staticGet('GNUsocialProfileExtensionResponse',$k,$v);
+ }
+
+
+ function table()
+ {
+ return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'extension_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'value' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL);
+ }
+
+ function keys()
+ {
+ return array_keys($this->keyTypes());
+ }
+
+ function keyTypes()
+ {
+ return array('id' => 'K');
+ }
+
+ function sequenceKey()
+ {
+ return array(false, false, false);
+ }
+
+ static function newResponse($extension_id, $profile_id, $value)
+ {
+
+ $response = new GNUsocialProfileExtensionResponse();
+ $response->extension_id = $extension_id;
+ $response->profile_id = $profile_id;
+ $response->value = $value;
+
+ $response->id = $response->insert();
+ if (!$response->id){
+ common_log_db_error($response, 'INSERT', __FILE__);
+ throw new ServerException(_m('Error creating new response.'));
+ }
+ return $response;
+ }
+
+ static function findResponsesByProfile($id)
+ {
+ $extf = 'GNUsocialProfileExtensionField';
+ $extr = 'GNUsocialProfileExtensionResponse';
+ $sql = "SELECT $extr.*, $extf.title, $extf.description, $extf.type, $extf.systemname FROM $extr JOIN $extf ON $extr.extension_id=$extf.id WHERE $extr.profile_id = $id";
+ $response = new GNUsocialProfileExtensionResponse();
+ $response->query($sql);
+ $responses = array();
+
+ while ($response->fetch()) {
+ $responses[] = clone($response);
+ }
+
+ return $responses;
+ }
+
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
+
+class GNUsocialPhoto extends Memcached_DataObject
+{
+ public $__table = 'GNUsocialPhoto';
+ public $id; // int(11)
+ public $_id; // int(11)
+ public $album_id; // int(11)
+ public $uri; // varchar(512)
+ public $thumb_uri; // varchar(512)
+ public $title; // varchar(512)
+ public $photo_description; // text
+
+
+ /**
+ *
+ * k key
+ * v value
+ */
+ function staticGet($k,$v=NULL)
+ {
+ return Memcached_DataObject::staticGet('GNUsocialPhoto',$k,$v);
+ }
+
+/* function delete()
+ {
+ if(!unlink(INSTALLDIR . $this->thumb_uri)) {
+ return false;
+ }
+ if(!unlink(INSTALLDIR . $this->path)) {
+ return false;
+ }
+ return parent::delete();
+ } */
+
+
+ /*
+ * TODO: Foriegn key on album_id.
+ */
+ function table()
+ {
+ return array('id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'notice_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'album_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
+ 'uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'thumb_uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'title' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
+ 'photo_description' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL);
+ }
+
+ function keys()
+ {
+ return array_keys($this->keyTypes());
+ }
+
+ function keyTypes()
+ {
+ return array('notice_id' => 'K');
+ }
+
+ function sequenceKey()
+ {
+ return array(false, false, false);
+ }
+
+ function saveNew($profile_id, $album_id, $thumb_uri, $uri, $source, $insert_now, $title = null, $photo_description = null)
+ {
+ $photo = new GNUsocialPhoto();
+ $photo->thumb_uri = $thumb_uri;
+ $photo->uri = $uri;
+ $photo->album_id = $album_id;
+ if(!empty($title)) $photo->title = $title;
+ if(!empty($photo_description)) $photo->photo_description = (string)$photo_description;
+
+ if($insert_now) {
+ $notice = Notice::saveNew($profile_id, $uri, $source);
+ $photo->notice_id = $notice->id;
+ $photo_id = $photo->insert();
+ if (!$photo_id) {
+ common_log_db_error($photo, 'INSERT', __FILE__);
+ throw new ServerException(_m('Problem Saving Photo.'));
+ }
+ } else {
+ GNUsocialPhotoTemp::$tmp = $photo;
+ Notice::saveNew($profile_id, $uri, $source);
+ }
+ }
+
+ function getPageLink()
+ {
+ return '/photo/' . $this->id;
+ }
+
+ /*
+ * TODO: -Sanitize input
+ * @param int page_id The desired page of the gallery to show.
+ * @param int album_id The id of the album to get photos from.
+ * @param int gallery_size The number of thumbnails to show per page in the gallery.
+ * @return array Array of GNUsocialPhotos for this gallery page.
+ */
+ static function getGalleryPage($page_id, $album_id, $gallery_size)
+ {
+ $page_offset = ($page_id-1) * $gallery_size;
+ $sql = 'SELECT * FROM GNUsocialPhoto WHERE album_id = ' . $album_id .
+ ' ORDER BY notice_id LIMIT ' . $page_offset . ',' . $gallery_size;
+ $photo = new GNUsocialPhoto();
+ $photo->query($sql);
+ $photos = array();
+
+ while ($photo->fetch()) {
+ $photos[] = clone($photo);
+ }
+
+ return $photos;
+ }
+}
--- /dev/null
+SN.U.NoticeReplySet = function(nick,id) {
+ $('div.replyform').hide();
+ $('div#form'+id).show();
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+ //functions to sort replies
+class NoticeTree extends NoticeList
+{
+ function show()
+ {
+ $this->out->elementStart('div', array('id' =>'notices_primary'));
+ // TRANS: Header on conversation page. Hidden by default (h2).
+ $this->out->element('h2', null, _('Notices'));
+ $this->out->elementStart('ol', array('class' => 'notices xoxo'));
+
+ $cnt = 0;
+
+ while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
+ if (!empty($this->notice->reply_to))
+ continue;
+
+ $cnt++;
+
+ if ($cnt > NOTICES_PER_PAGE) {
+ break;
+ }
+
+ try {
+ $this->showNoticePlus($this->newListItem($this->notice));
+ } catch (Exception $e) {
+ // we log exceptions and continue
+ print "ERROR!" . $e->getMessage();
+ common_log(LOG_ERR, $e->getMessage());
+ continue;
+ }
+ }
+
+ $this->out->elementEnd('ol');
+ $this->out->elementEnd('div');
+
+ return $cnt;
+ }
+
+ function _cmpDate($a, $b) { return strcmp($a->notice->modified, $b->notice->modified); }
+ function _cmpFav($a, $b) { return (int)$a->faves < (int)$b->faves; }
+
+ function showNoticePlus($item)
+ {
+ $replies = new Notice();
+ $replies->reply_to = $item->notice->id;
+
+ // We take responsibility for doing the li
+
+ $this->out->elementStart('li', array('class' => 'hentry notice',
+ 'id' => 'notice-' . $item->notice->id));
+
+ $item->show();
+
+ if ($replies->find()) {
+ $this->out->elementStart('ol', array('class' => 'notices'));
+
+ $replieslist = array();
+ while ($replies->fetch()) {
+ $replieslist[] = $this->newListItem(clone($replies));
+ }
+
+ //Sorting based on url argument
+ if($_GET['sort'] == 'faves')
+ usort($replieslist, array($this, '_cmpFav'));
+ else
+ usort($replieslist, array($this, '_cmpDate'));
+
+
+ foreach($replieslist as $reply) {
+ $this->showNoticePlus($reply);
+ }
+
+ $this->out->elementEnd('ol');
+ }
+
+ $this->out->elementEnd('li');
+ }
+
+ function newListItem($notice)
+ {
+ return new NoticeTreeItem($notice, $this->out);
+ }
+}
+
+class NoticeTreeItem extends NoticeListItem
+{
+ function __construct($notice, $out=null)
+ {
+ parent::__construct($notice, $out);
+ //TODO: Rewrite this
+ //Showing number of favorites
+ $fave = new Fave();
+ $fave->notice_id = $this->notice->id;
+ $cnt = 0;
+ if ($fave->find()) {
+ while ($fave->fetch())
+ $cnt++;
+ }
+ $this->faves = $cnt;
+ }
+
+ function showStart()
+ {
+ return;
+ }
+
+ function showEnd()
+ {
+ if ($this->faves > 0) {
+ $this->out->text(_m("Favorited by $this->faves user"));
+ if ($this->faves > 1) $this->out->text("s"); //there has to be a better way to do this...
+ }
+
+ //Show response form
+ $this->out->elementStart('div', array('id' => 'form' . $this->notice->id, 'class' => 'replyform'));
+ $noticeform = new ReplyForm($this->out, null, null, null, $this->notice->id);
+ $noticeform->show();
+ $this->out->elementEnd('div');
+ return;
+ }
+
+ function showContext()
+ {
+ return;
+ }
+
+ //Just changing the link...
+ function showReplyLink()
+ {
+ if (common_logged_in()) {
+ $this->out->text(' ');
+ //Why doesn't common_local_url work here?
+ $reply_url = '/notice/respond?replyto=' . $this->profile->nickname . '&inreplyto=' . $this->notice->id;
+ $this->out->elementStart('a', array('href' => $reply_url,
+ 'class' => 'notice_reply',
+ 'title' => _('Reply to this notice')));
+ $this->out->text(_('Reply'));
+ $this->out->text(' ');
+ $this->out->element('span', 'notice_id', $this->notice->id);
+ $this->out->elementEnd('a');
+ }
+ }
+
+}
+
+class ReplyForm extends NoticeForm
+{
+ //Changing the text. We have to either repeat ids or get hacky. I vote repeat ids.
+ function formData()
+ {
+ if (Event::handle('StartShowNoticeFormData', array($this))) {
+ // XXX: vary by defined max size
+ $this->out->element('textarea', array('id' => 'notice_data-text',
+ 'cols' => 35,
+ 'rows' => 4,
+ 'name' => 'status_textarea'),
+ ($this->content) ? $this->content : '');
+
+ $contentLimit = Notice::maxContent();
+
+ if ($contentLimit > 0) {
+ $this->out->elementStart('dl', 'form_note');
+ $this->out->element('dt', null, _('Available characters'));
+ $this->out->element('dd', array('id' => 'notice_text-count'),
+ $contentLimit);
+ $this->out->elementEnd('dl');
+ }
+
+ if (common_config('attachments', 'uploads')) {
+ $this->out->element('label', array('for' => 'notice_data-attach'),_('Attach'));
+ $this->out->element('input', array('id' => 'notice_data-attach',
+ 'type' => 'file',
+ 'name' => 'attach',
+ 'title' => _('Attach a file')));
+ $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
+ }
+ if ($this->action) {
+ $this->out->hidden('notice_return-to', $this->action, 'returnto');
+ }
+ $this->out->hidden('notice_in-reply-to', $this->inreplyto, 'inreplyto');
+
+ if ($this->user->shareLocation()) {
+ $this->out->hidden('notice_data-lat', empty($this->lat) ? (empty($this->profile->lat) ? null : $this->profile->lat) : $this->lat, 'lat');
+ $this->out->hidden('notice_data-lon', empty($this->lon) ? (empty($this->profile->lon) ? null : $this->profile->lon) : $this->lon, 'lon');
+ $this->out->hidden('notice_data-location_id', empty($this->location_id) ? (empty($this->profile->location_id) ? null : $this->profile->location_id) : $this->location_id, 'location_id');
+ $this->out->hidden('notice_data-location_ns', empty($this->location_ns) ? (empty($this->profile->location_ns) ? null : $this->profile->location_ns) : $this->location_ns, 'location_ns');
+
+ $this->out->elementStart('div', array('id' => 'notice_data-geo_wrap',
+ 'title' => common_local_url('geocode')));
+ $this->out->checkbox('notice_data-geo', _('Share my location'), true);
+ $this->out->elementEnd('div');
+ $this->out->inlineScript(' var NoticeDataGeo_text = {'.
+ 'ShareDisable: ' .json_encode(_('Do not share my location')).','.
+ 'ErrorTimeout: ' .json_encode(_('Sorry, retrieving your geo location is taking longer than expected, please try again later')).
+ '}');
+ }
+
+ Event::handle('EndShowNoticeFormData', array($this));
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Max Shinn <trombonechamp@gmail.com>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+function gnusocial_profile_merge(&$profile)
+{
+ $responses = GNUsocialProfileExtensionResponse::findResponsesByProfile($profile->id);
+ $profile->customfields = array();
+ foreach ($responses as $response) {
+ $title = $response->systemname;
+ $profile->$title = $response->value;
+ $profile->customfields[] = $title;
+ }
+}
+
+function gnusocial_field_systemname_validate($systemname)
+{
+ $fields = GNUsocialProfileExtensionField::allFields();
+ foreach ($fields as $field)
+ if ($field->systemname == $systemname)
+ return false;
+ return ctype_alphanum($systemname);
+}
\ No newline at end of file
--- /dev/null
+.biotitle {
+ font-weight: bold;
+}
+.biovalue {
+ font-style: italic;
+}
+#showstream ol.notices ol.notices {
+ background-image: url(/plugins/GNUsocialProfileExtensions/res/bgstripe.gif);
+ background-repeat: repeat-y;
+ background-position: left top;
+ padding-left: 15px;
+ color: #333333;
+}
+#showstream ol.notices ol.notices ol.notices {
+ padding-left: 5px;
+}
+div.replyform {
+ display: none;
+ padding-left: 15px;
+}
+.replyform .form_notice {
+ width: 75%;
+}
\ No newline at end of file
--- /dev/null
+<?php
+/**
+ * Plugin to render GNU social
+ *
+ * Captures rendered parts from the output buffer, passes them through a template file: tpl/social.php
+ * Adds an API method at index.php/template/update which lets you overwrite the template file
+ * Requires username/password and a single POST parameter called "template"
+ * The method is disabled unless the user is #1, the first user of the system
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Brian Hendrickson <brian@megapump.com>
+ * @author Matt Lee <mattl@cnuk.org>
+ * @copyright 2009 Megapump, Inc.
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://megapump.com/
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+define('TEMPLATEPLUGIN_VERSION', '0.1');
+
+class TemplatePlugin extends Plugin {
+
+ var $blocks = array();
+
+ function __construct() {
+ parent::__construct();
+ }
+
+ // capture the RouterInitialized event
+ // and connect a new API method
+ // for updating the template
+ function onRouterInitialized( $m ) {
+ $m->connect( 'template/update', array(
+ 'action' => 'template',
+ ));
+ }
+
+ // <%styles%>
+ // <%scripts%>
+ // <%search%>
+ // <%feeds%>
+ // <%description%>
+ // <%head%>
+ function onStartShowHead( $act ) {
+ $this->clear_xmlWriter($act);
+ $act->extraHead();
+ $this->blocks['head'] = $act->xw->flush();
+ $act->showStylesheets();
+ $this->blocks['styles'] = $act->xw->flush();
+ $act->showScripts();
+ $this->blocks['scripts'] = $act->xw->flush();
+ $act->showFeeds();
+ $this->blocks['feeds'] = $act->xw->flush();
+ $act->showOpenSearch();
+ $this->blocks['search'] = $act->xw->flush();
+ $act->showDescription();
+ $this->blocks['description'] = $act->xw->flush();
+ return false;
+ }
+
+ // <%bodytext%>
+ function onStartShowContentBlock( $act ) {
+ $this->clear_xmlWriter($act);
+ return true;
+ }
+ function onEndShowContentBlock( $act ) {
+ $this->blocks['bodytext'] = $act->xw->flush();
+ }
+
+ // <%localnav%>
+ function onStartShowLocalNavBlock( $act ) {
+ $this->clear_xmlWriter($act);
+ return true;
+ }
+ function onEndShowLocalNavBlock( $act ) {
+ $this->blocks['localnav'] = $act->xw->flush();
+ }
+
+ // <%export%>
+ function onStartShowExportData( $act ) {
+ $this->clear_xmlWriter($act);
+ return true;
+ }
+ function onEndShowExportData( $act ) {
+ $this->blocks['export'] = $act->xw->flush();
+ }
+
+ // <%subscriptions%>
+ // <%subscribers%>
+ // <%groups%>
+ // <%statistics%>
+ // <%cloud%>
+ // <%groupmembers%>
+ // <%groupstatistics%>
+ // <%groupcloud%>
+ // <%popular%>
+ // <%groupsbyposts%>
+ // <%featuredusers%>
+ // <%groupsbymembers%>
+ function onStartShowSections( $act ) {
+ global $action;
+ $this->clear_xmlWriter($act);
+ switch ($action) {
+ case "showstream":
+ $act->showSubscriptions();
+ $this->blocks['subscriptions'] = $act->xw->flush();
+ $act->showSubscribers();
+ $this->blocks['subscribers'] = $act->xw->flush();
+ $act->showGroups();
+ $this->blocks['groups'] = $act->xw->flush();
+ $act->showStatistics();
+ $this->blocks['statistics'] = $act->xw->flush();
+ $cloud = new PersonalTagCloudSection($act, $act->user);
+ $cloud->show();
+ $this->blocks['cloud'] = $act->xw->flush();
+ break;
+ case "showgroup":
+ $act->showMembers();
+ $this->blocks['groupmembers'] = $act->xw->flush();
+ $act->showStatistics();
+ $this->blocks['groupstatistics'] = $act->xw->flush();
+ $cloud = new GroupTagCloudSection($act, $act->group);
+ $cloud->show();
+ $this->blocks['groupcloud'] = $act->xw->flush();
+ break;
+ case "public":
+ $pop = new PopularNoticeSection($act);
+ $pop->show();
+ $this->blocks['popular'] = $act->xw->flush();
+ $gbp = new GroupsByPostsSection($act);
+ $gbp->show();
+ $this->blocks['groupsbyposts'] = $act->xw->flush();
+ $feat = new FeaturedUsersSection($act);
+ $feat->show();
+ $this->blocks['featuredusers'] = $act->xw->flush();
+ break;
+ case "groups":
+ $gbp = new GroupsByPostsSection($act);
+ $gbp->show();
+ $this->blocks['groupsbyposts'] = $act->xw->flush();
+ $gbm = new GroupsByMembersSection($act);
+ $gbm->show();
+ $this->blocks['groupsbymembers'] = $act->xw->flush();
+ break;
+ }
+ return false;
+ }
+
+ // <%logo%>
+ // <%nav%>
+ // <%notice%>
+ // <%noticeform%>
+ function onStartShowHeader( $act ) {
+ $this->clear_xmlWriter($act);
+ $act->showLogo();
+ $this->blocks['logo'] = $act->xw->flush();
+ $act->showPrimaryNav();
+ $this->blocks['nav'] = $act->xw->flush();
+ $act->showSiteNotice();
+ $this->blocks['notice'] = $act->xw->flush();
+ if (common_logged_in()) {
+ $act->showNoticeForm();
+ } else {
+ $act->showAnonymousMessage();
+ }
+ $this->blocks['noticeform'] = $act->xw->flush();
+ return false;
+ }
+
+ // <%secondarynav%>
+ // <%licenses%>
+ function onStartShowFooter( $act ) {
+ $this->clear_xmlWriter($act);
+ $act->showSecondaryNav();
+ $this->blocks['secondarynav'] = $act->xw->flush();
+ $act->showLicenses();
+ $this->blocks['licenses'] = $act->xw->flush();
+ return false;
+ }
+
+ // capture the EndHTML event
+ // and include the template
+ function onEndEndHTML($act) {
+
+ global $action, $tags;
+
+ // set the action and title values
+ $vars = array(
+ 'action'=>$action,
+ 'title'=>$act->title(). " - ". common_config('site', 'name')
+ );
+
+ // use the PHP template
+ // unless statusnet config:
+ // $config['template']['mode'] = 'html';
+ if (!(common_config('template', 'mode') == 'html')) {
+ $tpl_file = $this->templateFolder() . '/social.php';
+ $tags = array_merge($vars,$this->blocks);
+ include $tpl_file;
+ return;
+ }
+
+ $tpl_file = $this->templateFolder() . '/index.html';
+
+ // read the static template
+ $output = file_get_contents( $tpl_file );
+
+ $tags = array();
+
+ // get a list of the <%tags%> in the template
+ $pattern='/<%([a-z]+)%>/';
+
+ if ( 1 <= preg_match_all( $pattern, $output, $found ))
+ $tags[] = $found;
+
+ // for each found tag, set its value from the rendered blocks
+ foreach( $tags[0][1] as $pos=>$tag ) {
+ if (isset($this->blocks[$tag]))
+ $vars[$tag] = $this->blocks[$tag];
+
+ // didn't find a block for the tag
+ elseif (!isset($vars[$tag]))
+ $vars[$tag] = '';
+ }
+
+ // replace the tags in the template
+ foreach( $vars as $key=>$val )
+ $output = str_replace( '<%'.$key.'%>', $val, $output );
+
+ echo $output;
+
+ return true;
+
+ }
+ function templateFolder() {
+ return 'tpl';
+ }
+
+ // catching the StartShowHTML event to halt the rendering
+ function onStartShowHTML( $act ) {
+ $this->clear_xmlWriter($act);
+ return true;
+ }
+
+ // clear the xmlWriter
+ function clear_xmlWriter( $act ) {
+ $act->xw->openMemory();
+ $act->xw->setIndent(true);
+ }
+
+}
+
+/**
+ * Action for updating the template remotely
+ *
+ * "template/update" -- a POST method that requires a single
+ * parameter "template", containing the new template code
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Brian Hendrickson <brian@megapump.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://megapump.com/
+ *
+ */
+
+class TemplateAction extends Action
+{
+
+ function prepare($args) {
+ parent::prepare($args);
+ return true;
+ }
+
+ function handle($args) {
+
+ parent::handle($args);
+
+ if (!isset($_SERVER['PHP_AUTH_USER'])) {
+
+ // not authenticated, show login form
+ header('WWW-Authenticate: Basic realm="StatusNet API"');
+
+ // cancelled the browser login form
+ $this->clientError(_('Authentication error!'), $code = 401);
+
+ } else {
+
+ $nick = $_SERVER['PHP_AUTH_USER'];
+ $pass = $_SERVER['PHP_AUTH_PW'];
+
+ // check username and password
+ $user = common_check_user($nick,$pass);
+
+ if ($user) {
+
+ // verify that user is admin
+ if (!($user->id == 1))
+ $this->clientError(_('Only User #1 can update the template.'), $code = 401);
+
+ // open the old template
+ $tpl_file = $this->templateFolder() . '/index.html';
+ $fp = fopen( $tpl_file, 'w+' );
+
+ // overwrite with the new template
+ fwrite($fp, $this->arg('template'));
+ fclose($fp);
+
+ header('HTTP/1.1 200 OK');
+ header('Content-type: text/plain');
+ print "Template Updated!";
+
+ } else {
+
+ // bad username and password
+ $this->clientError(_('Authentication error!'), $code = 401);
+
+ }
+
+ }
+ }
+ function onPluginVersion(&$versions)
+ {
+ $versions[] = array('name' => 'Template',
+ 'version' => TEMPLATEPLUGIN_VERSION,
+ 'author' => 'Brian Hendrickson',
+ 'homepage' => 'http://status.net/wiki/Plugin:Template',
+ 'rawdescription' =>
+ _m('Use an HTML template for Web output.'));
+ return true;
+ }
+
+}
+
+/**
+ * Function for retrieving a statusnet display section
+ *
+ * requires one parameter, the name of the section
+ * section names are listed in the comments of the TemplatePlugin class
+ *
+ * @category Plugin
+ * @package StatusNet
+ * @author Brian Hendrickson <brian@megapump.com>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link http://megapump.com/
+ *
+ */
+
+function section($tagname) {
+ global $tags;
+ if (isset($tags[$tagname]))
+ return $tags[$tagname];
+}
+
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class GNUsocialVideoPlugin extends MicroAppPlugin
+{
+
+ function onCheckSchema()
+ {
+ $schema = Schema::get();
+
+ $schema->ensureTable('video', Video::schemaDef());
+
+ return true;
+ }
+
+ function onAutoload($cls)
+ {
+ $dir = dirname(__FILE__);
+ switch($cls)
+ {
+ case 'PostvideoAction':
+ include_once $dir . '/actions/postvideo.php';
+ break;
+ case 'Video':
+ include_once $dir . '/Video.php';
+ break;
+ case 'VideoForm':
+ include_once $dir . '/videoform.php';
+ break;
+ case 'ShowvideoAction':
+ include_once $dir . '/showvideo.php';
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ function onRouterInitialized($m)
+ {
+ $m->connect('main/postvideo', array('action' => 'postvideo'));
+ $m->connect('showvideo/:id', array('action' => 'showvideo'));
+ return true;
+ }
+
+ function entryForm($out)
+ {
+ return new VideoForm($out);
+ }
+
+ function appTitle()
+ {
+ return _('video');
+ }
+
+ function tag()
+ {
+ return 'GNUsocialVideo';
+ }
+
+ function types()
+ {
+ return array(Video::OBJECT_TYPE);
+ }
+
+ function saveNoticeFromActivity($activity, $actor, $options=array())
+ {
+ if(count($activity->objects) != 1) {
+ throw new Exception('Too many activity objects.');
+ }
+
+ $videoObj = $activity->objects[0];
+
+ if ($videoObj->type != Video::OBJECT_TYPE) {
+ throw new Exception('Wrong type for object.');
+ }
+
+ // For now we read straight from the xml tree, no other way to get this information.
+ // When there's a better API for this, we should change to it.
+ $uri = ActivityUtils::getLink($activity->entry, 'enclosure');
+
+ $options['object_type'] = Video::OBJECT_TYPE;
+
+ Video::saveNew($actor, $uri, $options);
+
+ }
+
+ function activityObjectFromNotice($notice)
+ {
+ $object = new ActivityObject();
+ $object->id = $notice->uri;
+ $object->type = Video::OBJECT_TYPE;
+ $object->title = $notice->content;
+ $object->summary = $notice->content;
+ $object->link = $notice->bestUrl();
+
+ $vid = Video::getByNotice($notice);
+
+ if ($vid) {
+ $object->extra[] = array('link', array('rel' => 'enclosure', 'href' => $vid->url), array());
+ }
+
+ return $object;
+
+ }
+
+ function showNotice($notice, $out)
+ {
+ $vid = Video::getByNotice($notice);
+ if ($vid) {
+ $out->element('video', array('src' => $vid->url,
+ 'width' => '100%',
+ 'controls' => 'controls'));
+ }
+ }
+
+ function deleteRelated($notice)
+ {
+ $vid = Video::getByNotice($notice);
+ if ($vid) {
+ $vid->delete();
+ }
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+/**
+ * Data class for videos.
+ */
+
+class Video extends Managed_DataObject
+{
+ const OBJECT_TYPE = 'http://activitystrea.ms/schema/1.0/video';
+
+ public $__table = 'video'; // table name
+ public $id; // char (36) // UUID
+ public $uri; // varchar (255) // This is the corresponding notice's uri.
+ public $url; // varchar (255)
+ public $profile_id; // int
+
+ public function staticGet($k, $v=null)
+ {
+ return Memcached_DataObject::staticGet('Video', $k, $v);
+ }
+
+ public function getByNotice($notice)
+ {
+ return self::staticGet('uri', $notice->uri);
+ }
+
+ public function getNotice()
+ {
+ return Notice::staticGet('uri', $this->uri);
+ }
+
+ public static function schemaDef()
+ {
+ return array(
+ 'description' => 'A video clip',
+ 'fields' => array(
+ 'id' => array('type' => 'char',
+ 'length' => 36,
+ 'not null' => true,
+ 'description' => 'UUID'),
+ 'uri' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'url' => array('type' => 'varchar',
+ 'length' => 255,
+ 'not null' => true),
+ 'profile_id' => array('type' => 'int', 'not null' => true),
+ ),
+ 'primary key' => array('id'),
+ 'foreign keys' => array('video_profile_id__key' => array('profile' => array('profile_id' => 'id'))),
+ );
+ }
+
+ function saveNew($profile, $url, $options=array())
+ {
+ $vid = new Video();
+
+ $vid->id = UUID::gen();
+ $vid->profile_id = $profile->id;
+ $vid->url = $url;
+
+
+ $options['object_type'] = Video::OBJECT_TYPE;
+
+ if (!array_key_exists('uri', $options)) {
+ $options['uri'] = common_local_url('showvideo', array('id' => $vid->id));
+ }
+
+ if (!array_key_exists('rendered', $options)) {
+ $options['rendered'] = sprintf("<video src=\"%s\">Sorry, your browser doesn't support the video tag.</video>", $url);
+ }
+
+ $vid->uri = $options['uri'];
+
+ $vid->insert();
+
+ return Notice::saveNew($profile->id,
+ '',
+ 'web',
+ $options);
+
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Widget
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2010 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if (!defined('STATUSNET')) {
+ exit(1);
+}
+
+class PostvideoAction extends Action {
+ var $user = null;
+ var $url = null;
+
+ function prepare($args)
+ {
+ parent::prepare($args);
+ $this->user = common_current_user();
+
+ if(empty($this->user)){
+ throw new ClientException(_('Must be logged in to post a video'),
+ 403);
+ }
+
+ if($this->isPost()){
+ $this->checkSessionToken();
+ }
+
+ $this->url = filter_var($this->trimmed('url'), FILTER_SANITIZE_URL);
+ $this->url = filter_var($this->url, FILTER_VALIDATE_URL);
+
+ return true;
+ }
+
+ function handle($args)
+ {
+ parent::handle($args);
+
+ if ($this->isPost()) {
+ $this->handlePost($args);
+ } else {
+ $this->showPage();
+ }
+ }
+
+ function handlePost($args)
+ {
+ if (empty($this->url)) {
+ throw new ClientException(_('Bad URL.'));
+ }
+
+ $profile = $this->user->getProfile();
+
+ $vid = Video::saveNew($profile, $this->url, array());
+
+ common_redirect($vid->uri, 303);
+ }
+
+ function showContent()
+ {
+ $form = new VideoForm();
+ $form->show();
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+class ShowvideoAction extends ShownoticeAction
+{
+ protected $id = null;
+ protected $vid = null;
+
+ function prepare($args)
+ {
+ OwnerDesignAction::prepare($args);
+ $this->id = $this->trimmed('id');
+ $this->vid = Video::staticGet('id', $this->id);
+
+ if (empty($this->vid)) {
+ throw new ClientException(_('No such video.'), 404);
+ }
+
+ $this->notice = $this->vid->getNotice();
+
+ if (empty($this->notice)) {
+ throw new ClientException(_('No such video'), 404);
+ }
+
+ $this->user = User::staticGet('id', $this->vid->profile_id);
+
+ if (empty($this->user)) {
+ throw new ClientException(_('No such user.'), 404);
+ }
+
+ $this->profile = $this->user->getProfile();
+
+ if (empty($this->profile)) {
+ throw new ServerException(_('User without a profile.'));
+ }
+
+ return true;
+ }
+}
--- /dev/null
+<?php
+/**
+ * GNU Social
+ * Copyright (C) 2010, Free Software Foundation, Inc.
+ *
+ * PHP version 5
+ *
+ * LICENCE:
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package GNU Social
+ * @author Ian Denhardt <ian@zenhack.net>
+ * @copyright 2011 Free Software Foundation, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
+ */
+
+if(!defined('STATUSNET')){
+ exit(1);
+}
+
+class VideoForm extends Form
+{
+ function id()
+ {
+ return "form_new_video";
+ }
+
+ function action()
+ {
+ return common_local_url('postvideo');
+ }
+
+ function formData()
+ {
+ $this->out->elementStart('fieldset', array('id' => 'new_video_data'));
+ $this->out->elementStart('ul', 'form_data');
+
+ $this->li();
+ $this->out->input('url', _('URL'), null, _('URL of the video'));
+ $this->unli();
+
+ $this->out->elementEnd('ul');
+ $this->out->elementEnd('fieldset');
+ }
+
+ function formActions()
+ {
+ $this->out->submit('submit', _m('BUTTON', 'Save'));
+ }
+}
function showContent()
{
+
if ($this->group) {
// TRANS: Form legend. %s is a group name.
$header = sprintf(_m('Join group %s'), $this->group);
* [Yahoo!](http://openid.yahoo.com/) : If you have an account with Yahoo!, you can log in to this site by entering your Yahoo!-provided OpenID in the box above. Yahoo! OpenID URLs have the form *https://me.yahoo.com/yourusername*.
* [AOL](http://dev.aol.com/aol-and-63-million-openids) : If you have an account with [AOL](http://www.aol.com/), like an [AIM](http://www.aim.com/) account, you can log in to %%site.name%% by entering your AOL-provided OpenID in the box above. AOL OpenID URLs have the form *http://openid.aol.com/yourusername*. Your username should be all lowercase, no spaces.
* [Blogger](http://bloggerindraft.blogspot.com/2008/01/new-feature-blogger-as-openid-provider.html), [Wordpress.com](http://faq.wordpress.com/2007/03/06/what-is-openid/), [LiveJournal](http://www.livejournal.com/openid/about.bml), [Vox](http://bradfitz.vox.com/library/post/openid-for-vox.html) : If you have a blog on any of these services, enter your blog URL in the box above. For example, *http://yourusername.blogspot.com/*, *http://yourusername.wordpress.com/*, *http://yourusername.livejournal.com/*, or *http://yourusername.vox.com/*.
+
+Additionally, once you have an account on %%site.name%%, you can use your profile's URL (https://%%site.server%%/yourusername) as an OpenID elsewhere as well.
--- /dev/null
+Initial simple way to Webfinger enable your domain -- needs PHP.
+================================================================
+
+Step 1
+======
+
+First, put the folders 'xrd' and 'dot-well-known' on your website, so
+they load at:
+
+ http://yourname.com/xrd/
+
+ and
+
+ http://yourname.com/.well-known/
+
+ (Remember the . at the beginning of this one)
+
+Step 2
+======
+
+Next, edit xrd/index.php and enter a secret in this line:
+
+$s = "";
+
+This can be anything you like...
+
+$s = "johnny-five";
+
+or
+
+$s = "12345";
+
+It really doesn't matter too much.
+
+Step 3
+======
+
+For each user on your site, and this might only be you...
+
+Make a copy of the example@example.com.xml file so that it's called...
+
+ yoursecretusername@domain.com.xml
+
+ So, if your secret is 'johnny5' and your name is ben and your
+ domain is titanictoycorp.biz, your file should be called
+ johnny5ben@titanictoycorp.biz.xml
+
+Finally, edit the file to point at your account on your social
+site. If you are the only user, then you probably don't need to worry
+about user/1 as this will be you. For multi user sites, the user ID is
+on the profile page.
+
+Finally
+=======
+
+Using this method, though fiddly, you can now be @user@domain without
+the need for any prefixes for subdomains, etc.
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0" xmlns:hm="http://host-meta.net/xrd/1.0"><hm:Host>example.com</hm:Host><Link rel="lrdd" template="http://example.com/xrd?uri={uri}"><Title>Resource Descriptor</Title></Link></XRD>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
+ <Subject>acct:example@example.com</Subject>
+ <Alias>acct:example@social.example.com</Alias>
+ <Alias>http://social.example.com/user/1</Alias>
+ <Link rel="http://webfinger.net/rel/profile-page" type="text/html" href="http://social.example.com/user/1"/>
+ <Link rel="http://schemas.google.com/g/2010#updates-from" type="application/atom+xml" href="http://social.example.com/api/statuses/user_timeline/1.atom"/>
+ <Link rel="http://microformats.org/profile/hcard" type="text/html" href="http://social.example.com/hcard"/>
+ <Link rel="http://gmpg.org/xfn/11" type="text/html" href="http://social.example.com/user/1"/>
+ <Link rel="describedby" type="application/rdf+xml" href="http://social.example.com/foaf"/>
+ <Link rel="http://salmon-protocol.org/ns/salmon-replies" href="http://social.example.com/main/salmon/user/1"/>
+ <Link rel="http://salmon-protocol.org/ns/salmon-mention" href="http://social.example.com/main/salmon/user/1"/>
+ <Link rel="http://ostatus.org/schema/1.0/subscribe" template="http://social.example.com/main/ostatussub?profile={uri}"/>
+</XRD>
--- /dev/null
+<?php
+
+/*
+ * GNU social
+ * Copyright (C) 2010, Free Software Foundation, Inc
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+$s = "";
+
+/* this should be a secret */
+
+$u = $_GET['uri'];
+
+$u = substr($u, 5);
+
+$f = $s . $u . ".xml";
+
+if (file_exists($f)) {
+ $fh = fopen($f, 'r');
+ $c = fread($fh, filesize($f));
+ fclose($fh);
+ header('Content-type: text/xml');
+ echo $c;
+}
+
+
+?>
\ No newline at end of file
--- /dev/null
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.7.0
+*/
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.7.0
+*/
+body{margin:10px;}h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong,dt{font-weight:bold;}optgroup{font-weight:normal;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;}em{font-style:italic;}del{text-decoration:line-through;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}sup{vertical-align:super;}sub{vertical-align:sub;}p,fieldset,table,pre{margin-bottom:1em;}button,input[type="checkbox"],input[type="radio"],input[type="reset"],input[type="submit"]{padding:1px;}
\ No newline at end of file
--- /dev/null
+#hd { background-color: orange !important; }
+
+#bd { background-color: red !important; }
+
+#ft { background-color: lime !important; }
+
+#yui-main { background-color: yellow !important; }
\ No newline at end of file
--- /dev/null
+/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.7.0
+*/
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var,optgroup{font-style:inherit;font-weight:inherit;}del,ins{text-decoration:none;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym{border:0;font-variant:normal;}sup{vertical-align:baseline;}sub{vertical-align:baseline;}legend{color:#000;}input,button,textarea,select,optgroup,option{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;}input,button,textarea,select{*font-size:100%;}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}select,input,button,textarea,button{font:99% arial,helvetica,clean,sans-serif;}table{font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}body{text-align:center;}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em;}#doc2{width:73.076em;*width:71.25em;}#doc3{margin:auto 10px;width:auto;}#doc4{width:74.923em;*width:73.05em;}.yui-b{position:relative;}.yui-b{_position:static;}#yui-main .yui-b{position:static;}#yui-main,.yui-g .yui-u .yui-g{width:100%;}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em;}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em;}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em;}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em;}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em;}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em;}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em;}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em;}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em;}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em;}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em;}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em;}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em;}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em;}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0;}#yui-main .yui-b{float:none;width:auto;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right;}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left;}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%;}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%;}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%;}.yui-gc div.first,.yui-gd .yui-u{width:66%;}.yui-gd div.first{width:32%;}.yui-ge div.first,.yui-gf .yui-u{width:74.2%;}.yui-ge .yui-u,.yui-gf div.first{width:24%;}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0;}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0;}.yui-g .yui-g .yui-u{width:48.1%;}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%;}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%;}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%;}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0;}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%;}.yui-g .yui-gb .yui-u{_margin-left:1.0%;}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%;}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%;}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0;}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0;}.yui-gb .yui-gb .yui-u{_margin-left:.7%;}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0;}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0;}.yui-gb .yui-gd div.first{width:32%;}.yui-g .yui-gd div.first{_width:29.9%;}.yui-ge .yui-g{width:24%;}.yui-gf .yui-g{width:74.2%;}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left;}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%;}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%;}.yui-ge div.first .yui-gd .yui-u{width:65%;}.yui-ge div.first .yui-gd div.first{width:32%;}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:".";display:block;height:0;clear:both;visibility:hidden;}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1;}/*
+Copyright (c) 2009, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.7.0
+*/
+body{margin:10px;}h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong,dt{font-weight:bold;}optgroup{font-weight:normal;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;}em{font-style:italic;}del{text-decoration:line-through;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{border:1px solid #000;padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}sup{vertical-align:super;}sub{vertical-align:sub;}p,fieldset,table,pre{margin-bottom:1em;}button,input[type="checkbox"],input[type="radio"],input[type="reset"],input[type="submit"]{padding:1px;}
\ No newline at end of file
--- /dev/null
+/*
+
+GNU social alpha CSS
+
+Enable this line to debug:
+
+@import url('./debug.css');
+
+*/
+
+/** theme: GNU social (portions from StatusNet base CSS)
+ *
+ * @package GNU social
+ * @author Matt Lee <mattl@cnuk.org>
+ * @copyright 2010 Free Software Foundation, Inc
+ * @copyright 2009-2010 StatusNet, Inc.
+ * @license http://creativecommons.org/licenses/by/3.0/ Creative Commons Attribution 3.0 Unported
+ */
+
+/* stuff we want to hide..... */
+
+legend, #anon_notice, #notices_primary h2, #site_nav_local_views dt, #ft dt, .entity_profile dt, .entity_profile h2, .entity_actions h2, .entity_nickname, .entities .nickname, .anon_notice, .entity_profile, .entity_subscribers { display: none !important; }
+
+#hd a{ color: white !important; }
+
+.entities li { display: inline; list-style: none !important; }
+
+.entity_profile dd { margin-bottom: 1em; }
+
+.notice { background-color: #eee; margin-bottom: 1em; border-top: 1px solid #ddd; padding: 0.4em; }
+
+.entity_fn { font-size: 130%; }
+
+dl, dd { margin: 0 !important; padding: 0 !important;}
+
+#yui-main { margin-bottom: 0 !important; padding-bottom: 0 !important;}
+
+.notices { margin: 0; padding: 0; }
+.notices li { list-style: none; }
+
+#ft { padding-top: 12px;}
+
+#custom-doc { width:76.23em;*width:74.39em;min-width:991px; margin:auto; text-align:left; }
+
+#yui-main { background-color: white; position: relative; }
+
+#sidebar *, #right-nav * { background: none !important; border: none !important; }
+
+ html, body{padding: 0; margin: 0;}
+
+ body {background-image: url(/theme/gnusocial/images/bg.png) !important; background-repeat: repeat-x !important; background-color: white;}
+
+ #hd h1 {margin: 0; line-height: 57px; font-size: 14px; font-weight: bold;}
+
+ #hd h1 a{color: #111; text-decoration: none;}
+
+ #hd dt {display: none;}
+
+ #hd ul {padding: 0; margin: 0; line-height: 48px; position: absolute; top: 0; right: 10px; }
+
+ #hd li {display: inline; list-style: none; margin-left: 12px;}
+
+ #hd {height: 40px; position: relative;}
+
+
+ form {margin: 0 auto; width: 70%;}
+
+ table {width: 100%;}
+
+ tr, td{border: 0;}
+
+ .update-text{ font-size: 12px; font-weight: bold;}
+
+ .update-icon{ text-align: center;}
+
+ #stream li{list-style: none; position: relative; margin-top: 12px; }
+
+ #stream dl {position: absolute; top: 0; left: 50px;}
+
+ #stream dd {color: #333; font-size: 80%; padding: 0; margin: 0; margin-top: 6px;}
+
+
+ #social { padding-left: 10px;}
+
+ #sidebar ul{margin: 0; padding: 0;}
+
+ #sidebar li {list-style: none;}
+
+ #sidebar li a{display: block; width: 180px; padding: 4px;}
+
+ #sidebar li a:hover {background-color: #ececec;}
+
+ .selected {background-color: cyan; width: 180px;}
+
+ #right-nav {background-color: #ececec;}
+
+ #right-nav div {padding: 10px;}
+
+ .form_notice { position: relative; top: 0; left: 0; }
+
+
+
+form label.submit {
+display:none;
+}
+
+.form_settings {
+clear:both;
+}
+
+.form_settings fieldset {
+margin-bottom:29px;
+}
+.form_settings input.remove {
+margin-left:11px;
+}
+.form_settings .form_data li {
+width:100%;
+float:left;
+}
+.form_settings .form_data label {
+float:left;
+}
+.form_settings .form_data textarea,
+.form_settings .form_data select,
+.form_settings .form_data input {
+margin-left:11px;
+float:left;
+}
+.form_settings .form_data textarea {
+width:325px;
+}
+
+.form_settings .form_data input.submit {
+margin-left:0;
+}
+
+.form_settings label {
+margin-top:2px;
+width:143px;
+}
+
+.form_actions label {
+display:none;
+}
+.form_guide {
+font-style:italic;
+}
+
+.form_settings #settings_autosubscribe label {
+display:inline;
+font-weight:bold;
+}
+
+#form_settings_profile legend,
+#form_login legend,
+#form_register legend,
+#form_password legend,
+#form_settings_avatar legend,
+#newgroup legend,
+#editgroup legend,
+#form_tag_user legend,
+#form_remote_subscribe legend,
+#form_openid_login legend,
+#form_search legend,
+#form_invite legend,
+#form_notice_delete legend,
+#form_password_recover legend,
+#form_password_change legend {
+display:none;
+}
+
+.form_settings .form_data p.form_guide {
+clear:both;
+margin-left:155px;
+margin-bottom:0;
+}
+
+.form_settings p {
+margin-bottom:11px;
+}
+
+.form_settings input.checkbox {
+margin-top:0;
+margin-left:0;
+}
+.form_settings label.checkbox {
+font-weight:normal;
+margin-top:0;
+margin-right:0;
+margin-left:11px;
+float:left;
+width:90%;
+}
+
+
+#form_login p.form_guide,
+#form_register #settings_rememberme p.form_guide,
+#form_openid_login #settings_rememberme p.form_guide,
+#settings_twitter_remove p.form_guide,
+#form_search ul.form_data #q {
+margin-left:0;
+}
+
+.form_settings .form_note {
+border-radius:4px;
+-moz-border-radius:4px;
+-webkit-border-radius:4px;
+padding:0 7px;
+}
+
+
+.form_settings input.form_action-primary {
+padding:0;
+}
+.form_settings input.form_action-secondary {
+margin-left:29px;
+}
+
+#form_search .submit {
+margin-left:11px;
+}
+caption {
+font-weight:bold;
+}
+legend {
+font-weight:bold;
+font-size:1.3em;
+}
+input, textarea, select, option {
+padding:4px;
+font-family:sans-serif;
+font-size:1em;
+}
+input, textarea, select {
+border-width:2px;
+border-style: solid;
+border-radius:4px;
+-moz-border-radius:4px;
+-webkit-border-radius:4px;
+}
+
+input.submit {
+font-weight:bold;
+cursor:pointer;
+}
+textarea {
+overflow:auto;
+}
+option {
+padding-bottom:0;
+}
+fieldset {
+padding:0;
+border:0;
+}
+form ul li {
+list-style-type:none;
+margin:0 0 18px 0;
+}
+form label {
+font-weight:bold;
+}
+input.checkbox {
+position:relative;
+top:2px;
+left:0;
+border:0;
+}
+
+.error,
+.success {
+padding:4px 7px;
+border-radius:4px;
+-moz-border-radius:4px;
+-webkit-border-radius:4px;
+margin-bottom:18px;
+}
+
+/* #all .notice, #public .notice { padding-bottom: 12px;} */
+
+/* #all .notice .entry-title, #public .notice .entry-title { position: relative;} */
+
+/* #all .notice .entry-title .entry-content, #public .notice .entry-title .entry-content { position: absolute; top: 25px; left: 55px; } */
+
+/* #all .notice .entry-content .timestamp, #public .notice .entry-content .timestamp { color: #666; margin-left: 55px; font-size: 80%; text-decoration: none !important; } */
+
+.notices div.entry-content { font-size: 80%; }
+
+.notices div.entry-content a, .notices div.entry-content abbr{ font-color: #666 !important; text-decoration: none !important; }
+
+abbr { border: 0px !important; }
+
+#all .entry-title .author .nickname, #public .entry-title .author .nickname { position: absolute; top: 0; left: 55px; font-weight: bold; }
+
+#showstream #i { position: absolute; top: 0; left: 0; background-color: white; z-index: 100; width: 185px; }
+
+
+.notice-options, .form_favor .submit, .form_repeat .submit { background-color: white; border: 0; display: none !important; }
+
+#form_notice { margin-top: 10px;}
+
+
+/* tagcloud */
+.tag-cloud {
+list-style-type:none;
+text-align:center;
+}
+.aside .tag-cloud {
+font-size:0.8em;
+word-wrap:break-word;
+}
+.tag-cloud li {
+display:inline;
+margin-right:7px;
+line-height:1.25;
+}
+
+.tag-cloud li:before {
+content:'\0009';
+}
+
+.aside .tag-cloud li {
+line-height:1.5;
+}
+.tag-cloud li a {
+text-decoration:none;
+}
+#tagcloud.section dt {
+text-transform:uppercase;
+font-weight:bold;
+}
+.tag-cloud-1 {
+font-size:1em;
+}
+.tag-cloud-2 {
+font-size:1.25em;
+}
+.tag-cloud-3 {
+font-size:1.75em;
+}
+.tag-cloud-4 {
+font-size:2em;
+}
+.tag-cloud-5 {
+font-size:2.25em;
+}
+.tag-cloud-6 {
+font-size:2.75em;
+}
+.tag-cloud-7 {
+font-size:3.25em;
+}
+
+
+
+
+.entity_subscriptions ul:before { content: 'Fan of...'; }
+
+#feedback-button-of-doom { position: fixed; top: 350px; left: 0; }
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+ <head>
+ <title>Public timeline - Lorraine Lee — GNU social</title>
+
+
+ <link rel="stylesheet" href="/theme/gnusocial/combo.css" type="text/css">
+ <style type="text/css">
+ #custom-doc { width:76.23em;*width:74.39em;min-width:991px; margin:auto; text-align:left; }
+
+ html, body{padding: 0; margin: 0;}
+
+ body {background-image: url(/theme/gnusocial/bg.png); background-repeat: repeat-x;}
+
+ #hd h1 {margin: 0; line-height: 48px; font-size: 30px; font-weight: bold;}
+
+ #hd h1 a{color: #111; text-decoration: none;}
+
+ #hd dt {display: none;}
+
+ #hd ul {padding: 0; margin: 0; line-height: 48px; position: absolute; top: 0; right: 10px; }
+
+ #hd li {display: inline; list-style: none; margin-left: 12px;}
+
+ #hd {height: 48px; position: relative;}
+
+ #bd {margin-top: 12px;}
+
+ #ft {font-size: 10px; text-align: right; margin-top: 12px}
+
+ form {margin: 0 auto; width: 70%;}
+
+ table {width: 100%;}
+
+ tr, td{border: 0;}
+
+ .update-text{ font-size: 12px; font-weight: bold;}
+
+ .update-icon{ text-align: center;}
+
+ #stream li{list-style: none; position: relative; margin-top: 12px; }
+
+ #stream dl {position: absolute; top: 0; left: 50px;}
+
+ #stream dd {color: #333; font-size: 80%; padding: 0; margin: 0; margin-top: 6px;}
+
+
+ #social {border-left: 1px solid #999; border-right: 1px solid #999; padding-left: 10px;}
+
+ #sidebar ul{margin: 0; padding: 0;}
+
+ #sidebar li {list-style: none;}
+
+ #sidebar li a{display: block; width: 180px; padding: 4px;}
+
+ #sidebar li a:hover {background-color: #ececec;}
+
+ .selected {background-color: cyan; width: 180px;}
+
+ #right-nav {background-color: #ececec;}
+
+ #right-nav div {padding: 10px;}
+
+ </style>
+
+
+ </head>
+ <body id="public">
+<div id="custom-doc" class="yui-t2">
+ <div id="hd">
+ <h1>GNU social</h1>
+
+ <dl id="site_nav_global_primary">
+ <dt>Primary site navigation</dt>
+ <dd>
+ <ul class="nav">
+ <li id="nav_login">
+ <a href="http://lorrainelee.co.uk/main/login" title="Login to the site">Login</a>
+</li>
+ <li id="nav_help">
+ <a href="http://lorrainelee.co.uk/doc/help" title="Help me!">Help</a>
+</li>
+ <li id="nav_search">
+ <a href="http://lorrainelee.co.uk/search/people" title="Search for people or text">Search</a>
+</li>
+</ul>
+</dd>
+</dl>
+ </div>
+ <div id="bd">
+
+ <div id="yui-main">
+
+ <div class="yui-b">
+
+ <div class="yui-gc">
+
+ <div class="yui-u first">
+
+ <dl id="site_notice" class="system_notice">
+ <dt>Site notice</dt>
+ <dd>Powered by <a href="http://www.gnu.org/software/social/">GNU social</a></dd>
+</dl>
+ <div id="anon_notice"><p>This is Lorraine Lee, a <a href="http://en.wikipedia.org/wiki/Micro-blogging">micro-blogging</a> service based on the Free Software <a href="http://status.net/">StatusNet</a> tool.</p>
+</div>
+ <div id="content">
+ <h1>Public timeline</h1>
+ <div id="content_inner">
+ <div id="notices_primary">
+ <h2>Notices</h2>
+ <ol class="notices xoxo">
+ <li class="hentry notice" id="notice-5">
+ <div class="entry-title">
+ <span class="vcard author">
+ <a href="http://lorrainelee.co.uk/lorraine" class="url" title="Lorraine Lee (lorraine)">
+ <img src="http://lorrainelee.co.uk/avatar/3-48-20100722212232.jpeg" class="avatar photo" width="48" height="48" alt="Lorraine Lee"/>
+ <span class="nickname fn">lorraine</span></a>
+</span>
+ <p class="entry-content">im going to brush my teeth</p>
+</div>
+ <div class="entry-content">
+ <a rel="bookmark" class="timestamp" href="http://lorrainelee.co.uk/notice/5">
+ <abbr class="published" title="2010-07-22T21:41:40+00:00">about 5 hours ago</abbr>
+</a>
+ <span class="source">from <span class="device">web</span>
+</span>
+ <span class="location">at <a href="http://www.geonames.org/2651292" rel="external"><abbr class="geo" title="50.7500000;-3.7500000">County of Devon, England, United Kingdom of Great Britain and Northern Ireland</abbr></a></span>
+</div>
+</li>
+ <li class="hentry notice" id="notice-2">
+ <div class="entry-title">
+ <span class="vcard author">
+ <a href="http://lorrainelee.co.uk/lorraine" class="url" title="Lorraine Lee (lorraine)">
+ <img src="http://lorrainelee.co.uk/avatar/3-48-20100722212232.jpeg" class="avatar photo" width="48" height="48" alt="Lorraine Lee"/>
+ <span class="nickname fn">lorraine</span></a>
+</span>
+ <p class="entry-content">nothing im fine thank you</p>
+</div>
+ <div class="entry-content">
+ <a rel="bookmark" class="timestamp" href="http://lorrainelee.co.uk/notice/2">
+ <abbr class="published" title="2010-07-22T21:38:18+00:00">about 5 hours ago</abbr>
+</a>
+ <span class="source">from <span class="device">web</span>
+</span>
+ <span class="location">at <a href="http://www.geonames.org/2651292" rel="external"><abbr class="geo" title="50.7500000;-3.7500000">County of Devon, England, United Kingdom of Great Britain and Northern Ireland</abbr></a></span>
+ <a href="http://lorrainelee.co.uk/conversation/2#notice-2" class="response">in context</a>
+</div>
+</li>
+</ol>
+</div>
+</div>
+</div>
+
+ </div>
+
+
+ <div class="yui-u" id="right-nav">
+
+
+
+
+
+ <div id="aside_primary" class="aside">
+ <div id="featured_users" class="section">
+ <h2>Featured users</h2>
+</div>
+ </div>
+
+
+ </div>
+</div>
+ </div>
+</div>
+
+ <div class="yui-b" id="sidebar">
+ <dl id="site_nav_local_views">
+ <dt>Local views</dt>
+ <dd>
+ <ul class="nav">
+ <li class="current" id="nav_timeline_public">
+ <a href="http://lorrainelee.co.uk/" title="Public timeline">Public</a>
+</li>
+ <li id="nav_groups">
+ <a href="http://lorrainelee.co.uk/group" title="User groups">Groups</a>
+</li>
+ <li id="nav_recent-tags">
+ <a href="http://lorrainelee.co.uk/tags" title="Recent tags">Recent tags</a>
+</li>
+ <li id="nav_timeline_favorited">
+ <a href="http://lorrainelee.co.uk/favorited" title="Popular notices">Popular</a>
+</li>
+</ul>
+</dd>
+</dl>
+ </div>
+
+ </div>
+ <div id="ft">
+
+ <dl id="licenses">
+ <dt id="site_statusnet_license">StatusNet software licence</dt>
+ <dd><p><strong>Lorraine Lee</strong> is a microblogging service brought to you by <a href="http://www.gnu.org/s/social/">GNU social</a>. It runs the <a href="http://status.net/">StatusNet</a> microblogging software, version 0.9.3, available under the <a href="http://www.fsf.org/licensing/licenses/agpl-3.0.html">GNU Affero General Public Licence</a>.</p>
+</dd>
+ <dt id="site_content_license">Site content license</dt>
+ <dd id="site_content_license_cc">
+ <p>
+ <img id="license_cc" src="http://i.creativecommons.org/l/by/3.0/80x15.png" alt="Creative Commons Attribution 3.0" width="80" height="15"/>
+ All Lorraine Lee content and data are available under the <a class="license" rel="external license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a> licence.</p>
+</dd>
+</dl>
+ </div>
+ </div>
+ </body>
+ </html>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title><?php echo section('title'); ?> — GNU social</title>
+
+
+ <link rel="stylesheet" href="/theme/gnusocial/css/combo.css" type="text/css">
+ <link rel="stylesheet" href="/theme/gnusocial/css/social.css" type="text/css">
+ <?php echo section('scripts'); ?>
+ <?php echo section('search'); ?>
+ <?php echo section('feeds'); ?>
+ <?php echo section('description'); ?>
+ <?php echo section('head'); ?>
+ </head>
+ <body id="<?php echo section('action'); ?>">
+
+ <div id="feedback-button-of-doom"><a href="http://social.foocorp.net/shapado.html"><img src="/theme/gnusocial/images/fback.png" title="Send us your ideas and suggestions" alt="Feedback" /></a></div>
+
+
+ <div id="doc2" class="yui-t6">
+ <div id="hd">
+ <h1><a href="/">GNU social</a></h1>
+ <?php echo section('nav'); ?>
+ </div>
+ <div id="bd">
+ <div id="yui-main">
+ <div class="yui-b" id="social">
+ <div class="yui-g">
+ <?php echo section('noticeform'); ?>
+ <?php echo section('bodytext'); ?>
+ </div>
+</div>
+</div>
+
+
+ <div class="yui-b" id="right-nav">
+ <div id="aside_primary" class="aside">
+ <?php echo section('subscriptions'); ?>
+ <?php echo section('subscribers'); ?>
+ <?php echo section('groups'); ?>
+ <?php echo section('cloud'); ?>
+ <?php echo section('popular'); ?>
+ <?php echo section('localnav'); ?>
+ </div>
+ </div>
+ <div id="ft">
+ <p>This is <a href="http://www.gnu.org/software/social">GNU social</a> — licensed under the <a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License</a> version 3.0 or later. <a href="http://gitorious.org/+socialites/statusnet/gnu-social">Get the code</a>.</p>
+ </div>
+ </div>
+ </body>
+</html>