EndShowStyles: End showing Style links; good place to add custom styles
- $action: the current action
- StartShowLaconicaStyles: Showing Laconica Style links
+ StartShowStatusNetStyles: Showing StatusNet Style links
- $action: the current action
- EndShowLaconicaStyles: End showing Laconica tyle links; good place to add handheld or JavaScript dependent styles
+ EndShowStatusNetStyles: End showing StatusNet Style links; good place to add handheld or JavaScript dependant styles
+ - $action: the current action
+
+ StartShowLaconicaStyles: backwards compatibility; deprecated
+ - $action: the current action
+
+ EndShowLaconicaStyles: backwards compatibility; deprecated
- $action: the current action
-StartShowUAStyles: Showing custom UA Style links
+StartShowUAStyles: Showing custom User-Agent style links
- $action: the current action
-EndShowUAStyles: End showing custom UA Style links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
+EndShowUAStyles: End showing custom User-Agent links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles
- $action: the current action
StartShowScripts: Showing JavaScript links
require_once INSTALLDIR.'/lib/omb.php';
/**
- * Access token class.
+ * Access token class
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class AccesstokenAction extends Action
{
<?php
-/*
+/**
+ * Handler for remote subscription finish callback
+ *
+ * PHP version 5
+ *
+ * @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
++ * @link http://status.net/
+ *
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ **/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
+require_once INSTALLDIR.'/lib/omb.php';
+/**
+ * Handler for remote subscription finish callback
+ *
+ * When a remote user subscribes a local user, a redirect to this action is
+ * issued after the remote user authorized his service to subscribe.
+ *
+ * @category Action
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Robin Millette <millette@controlyourself.ca>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://laconi.ca/
+ */
class FinishremotesubscribeAction extends Action
{
<?php
-/*
+/**
+ * Handle postnotice action
+ *
+ * PHP version 5
+ *
+ * @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
++ * @link http://status.net/
+ *
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+/**
+ * Handler for postnotice action
+ *
+ * @category Action
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
++ * @link http://status.net/
+ */
class PostnoticeAction extends Action
{
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
+ {
+ parent::prepare($argarray);
+ try {
+ $this->checkNotice();
+ } catch (Exception $e) {
+ $this->clientError($e->getMessage());
+ return false;
+ }
+ return true;
+ }
+
function handle($args)
{
parent::handle($args);
$this->clientError(_('Invalid notice content'), 400);
return false;
}
- $notice_uri = $req->get_parameter('omb_notice');
- if (!Validate::uri($notice_uri) &&
- !common_valid_tag($notice_uri)) {
- $this->clientError(_('Invalid notice uri'), 400);
- return false;
- }
- $notice_url = $req->get_parameter('omb_notice_url');
- if ($notice_url && !common_valid_http_url($notice_url)) {
- $this->clientError(_('Invalid notice url'), 400);
- return false;
+ $license = $_POST['omb_notice_license'];
+ $site_license = common_config('license', 'url');
+ if ($license && !common_compatible_license($license, $site_license)) {
+ throw new Exception(sprintf(_('Notice license ‘%s’ is not ' .
+ 'compatible with site license ‘%s’.'),
+ $license, $site_license));
}
- $notice = Notice::staticGet('uri', $notice_uri);
- if (!$notice) {
- $notice = Notice::saveNew($remote_profile->id, $content, 'omb', false, null, $notice_uri);
- if (is_string($notice)) {
- common_server_serror($notice, 500);
- return false;
- }
- common_broadcast_notice($notice, true);
- }
- return true;
}
}
- ?>
++?>
function showAnonymousMessage()
{
if (! (common_config('site','closed') || common_config('site','inviteonly'))) {
- $m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
- '[Join now](%%action.register%%) to share notices about yourself with friends, family, and colleagues! ([Read more](%%doc.help%%))');
- $m = sprintf(_('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
- '[Join now](%%%%action.%s%%%%) to share notices about yourself with friends, family, and colleagues! ' .
- '([Read more](%%%%doc.help%%%%))'),
- (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
++ $m = _('This is %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
++ 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
++ '[Join now](%%%%action.register%%%%) to share notices about yourself with friends, family, and colleagues! ' .
++ '([Read more](%%%%doc.help%%%%))');
} else {
$m = _('This is %%site.name%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool.');
+ 'based on the Free Software [StatusNet](http://status.net/) tool.');
}
$this->elementStart('div', array('id' => 'anon_notice'));
$this->raw(common_markup_to_html($m));
<?php
-/*
+/**
+ * Handler for remote subscription
+ *
+ * PHP version 5
+ *
+ * @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
++ * @link http://status.net/
+ *
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
+ **/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_consumer.php';
+require_once INSTALLDIR.'/extlib/libomb/profile.php';
+
+/**
+ * Handler for remote subscription
+ *
+ * @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
++ * @link http://status.net/
+ */
class RemotesubscribeAction extends Action
{
{
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
+ 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' .
'short messages about their life and interests. '.
- '[Join now](%%%%action.%s%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
- $this->group->nickname,
- (!common_config('site','openidonly')) ? 'register' : 'openidlogin');
+ '[Join now](%%%%action.register%%%%) to become part of this group and many more! ([Read more](%%%%doc.help%%%%))'),
+ $this->group->nickname);
} else {
$m = sprintf(_('**%s** is a user group on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. Its members share ' .
+ 'based on the Free Software [StatusNet](http://status.net/) tool. Its members share ' .
'short messages about their life and interests. '),
$this->group->nickname);
}
{
if (!(common_config('site','closed') || common_config('site','inviteonly'))) {
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. ' .
+ 'based on the Free Software [StatusNet](http://status.net/) tool. ' .
- '[Join now](%%%%action.%s%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
- $this->user->nickname,
- (!common_config('site','openidonly')) ? 'register' : 'openidlogin',
- $this->user->nickname);
+ '[Join now](%%%%action.register%%%%) to follow **%s**\'s notices and many more! ([Read more](%%%%doc.help%%%%))'),
+ $this->user->nickname, $this->user->nickname);
} else {
$m = sprintf(_('**%s** has an account on %%%%site.name%%%%, a [micro-blogging](http://en.wikipedia.org/wiki/Micro-blogging) service ' .
- 'based on the Free Software [Laconica](http://laconi.ca/) tool. '),
+ 'based on the Free Software [StatusNet](http://status.net/) tool. '),
$this->user->nickname, $this->user->nickname);
}
$this->elementStart('div', array('id' => 'anon_notice'));
<?php
-/*
+/**
+ * Handle an updateprofile action
+ *
+ * PHP version 5
+ *
+ * @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
++ * @link http://status.net/
+ *
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+/**
+ * Handle an updateprofile action
+ *
+ * @category Action
+ * @package Laconica
+ * @author Evan Prodromou <evan@controlyourself.ca>
+ * @author Robin Millette <millette@controlyourself.ca>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
+ * @link http://laconi.ca/
+ */
class UpdateprofileAction extends Action
{
-
- function handle($args)
- {
- parent::handle($args);
- try {
- common_remove_magic_from_request();
- $req = OAuthRequest::from_request('POST', common_local_url('updateprofile'));
- # Note: server-to-server function!
- $server = omb_oauth_server();
- list($consumer, $token) = $server->verify_request($req);
- if ($this->update_profile($req, $consumer, $token)) {
- header('HTTP/1.1 200 OK');
- header('Content-type: text/plain');
- print "omb_version=".OMB_VERSION_01;
- }
- } catch (OAuthException $e) {
- $this->serverError($e->getMessage());
- return;
- }
- }
- function update_profile($req, $consumer, $token)
+ /**
+ * For initializing members of the class.
+ *
+ * @param array $argarray misc. arguments
+ *
+ * @return boolean true
+ */
+ function prepare($argarray)
{
$version = $req->get_parameter('omb_version');
if ($version != OMB_VERSION_01) {
<?php
-/*
+/**
+ * Let the user authorize a remote subscription request
+ *
+ * PHP version 5
+ *
+ * @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
++ * @link http://status.net/
+ *
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+ * StatusNet - the distributed open-source microblogging tool
+ * Copyright (C) 2008, 2009, StatusNet, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+require_once INSTALLDIR.'/extlib/libomb/profile.php';
define('TIMESTAMP_THRESHOLD', 300);
class UserauthorizationAction extends Action
}
if (!in_array($size[2], array(IMAGETYPE_GIF, IMAGETYPE_JPEG,
IMAGETYPE_PNG))) {
- throw new OAuthException("Wrong image type for '$avatar'");
+ throw new Exception(sprintf(_('Wrong image type for avatar URL '.
+ '‘%s’.'), $avatar));
}
}
- $callback = $_GET['oauth_callback'];
- if ($callback && !common_valid_http_url($callback)) {
- throw new OAuthException("Invalid callback URL '$callback'");
- }
- if ($callback && $callback == common_local_url('finishremotesubscribe')) {
- throw new OAuthException("Callback URL '$callback' is for local site.");
- }
}
--}
++}
}
require_once INSTALLDIR.'/lib/omb.php';
+require_once INSTALLDIR.'/extlib/libomb/service_provider.php';
+require_once INSTALLDIR.'/extlib/libomb/xrds_mapper.php';
/**
- * XRDS for OpenID
+ * XRDS for OpenMicroBlogging
*
* @category Action
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+ * @package StatusNet
+ * @author Evan Prodromou <evan@status.net>
+ * @author Robin Millette <millette@status.net>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * @link http://laconi.ca/
+ * @link http://status.net/
*/
class XrdsAction extends Action
{
- [status_network]
+
+ [avatar]
+ profile_id = 129
+ original = 17
+ width = 129
+ height = 129
+ mediatype = 130
+ filename = 2
+ url = 2
+ created = 142
+ modified = 384
+
+ [avatar__keys]
+ profile_id = K
+ width = K
+ height = K
+ url = U
+
++[config]
++section = 130
++setting = 130
++value = 2
++
++[config__keys]
++section = K
++setting = K
++
+ [confirm_address]
+ code = 130
+ user_id = 129
+ address = 130
+ address_extra = 130
+ address_type = 130
+ claimed = 14
+ sent = 14
+ modified = 384
+
+ [confirm_address__keys]
+ code = K
+
+ [consumer]
+ consumer_key = 130
+ seed = 130
+ created = 142
+ modified = 384
+
+ [consumer__keys]
+ consumer_key = K
+
++[deleted_notice]
++id = 129
++profile_id = 129
++uri = 2
++created = 142
++deleted = 142
++
++[deleted_notice__keys]
++id = K
++uri = U
++
+ [design]
+ id = 129
+ backgroundcolor = 1
+ contentcolor = 1
+ sidebarcolor = 1
+ textcolor = 1
+ linkcolor = 1
+ backgroundimage = 2
+ disposition = 17
+
+ [design__keys]
+ id = N
+
+ [fave]
+ notice_id = 129
+ user_id = 129
+ modified = 384
+
+ [fave__keys]
+ notice_id = K
+ user_id = K
+
+ [file]
+ id = 129
+ url = 2
+ mimetype = 2
+ size = 1
+ title = 2
+ date = 1
+ protected = 1
+ filename = 2
+ modified = 384
+
+ [file__keys]
+ id = N
+
+ [file_oembed]
+ file_id = 129
+ version = 2
+ type = 2
+ provider = 2
+ provider_url = 2
+ width = 1
+ height = 1
+ html = 34
+ title = 2
+ author_name = 2
+ author_url = 2
+ url = 2
+ modified = 384
+
+ [file_oembed__keys]
+ file_id = K
+
+ [file_redirection]
+ url = 130
+ file_id = 1
+ redirections = 1
+ httpcode = 1
+ modified = 384
+
+ [file_redirection__keys]
+ url = K
+
+ [file_thumbnail]
+ file_id = 129
+ url = 2
+ width = 1
+ height = 1
+ modified = 384
+
+ [file_thumbnail__keys]
+ file_id = K
+ url = U
+
+ [file_to_post]
+ file_id = 129
+ post_id = 129
+ modified = 384
+
+ [file_to_post__keys]
+ file_id = K
+ post_id = K
+
+ [foreign_link]
+ user_id = 129
+ foreign_id = 129
+ service = 129
+ credentials = 2
+ noticesync = 145
+ friendsync = 145
+ profilesync = 145
+ last_noticesync = 14
+ last_friendsync = 14
+ created = 142
+ modified = 384
+
+ [foreign_link__keys]
+ user_id = K
+ foreign_id = K
+ service = K
+
+ [foreign_service]
+ id = 129
+ name = 130
+ description = 2
+ created = 142
+ modified = 384
+
+ [foreign_service__keys]
+ id = K
+ name = U
+
+ [foreign_subscription]
+ service = 129
+ subscriber = 129
+ subscribed = 129
+ created = 142
+
+ [foreign_subscription__keys]
+ service = K
+ subscriber = K
+ subscribed = K
+
+ [foreign_user]
+ id = 129
+ service = 129
+ uri = 130
+ nickname = 2
+ created = 142
+ modified = 384
+
+ [foreign_user__keys]
+ id = K
+ service = K
+ uri = U
+
+ [group_alias]
+ alias = 130
+ group_id = 129
+ modified = 384
+
+ [group_alias__keys]
+ alias = K
+
+ [group_block]
+ group_id = 129
+ blocked = 129
+ blocker = 129
+ modified = 384
+
+ [group_block__keys]
+ group_id = K
+ blocked = K
+
+ [group_inbox]
+ group_id = 129
+ notice_id = 129
+ created = 142
+
+ [group_inbox__keys]
+ group_id = K
+ notice_id = K
+
+ [group_member]
+ group_id = 129
+ profile_id = 129
+ is_admin = 17
+ created = 142
+ modified = 384
+
+ [group_member__keys]
+ group_id = K
+ profile_id = K
+
+ [invitation]
+ code = 130
+ user_id = 129
+ address = 130
+ address_type = 130
+ created = 142
+
+ [invitation__keys]
+ code = K
+
+ [message]
+ id = 129
+ uri = 2
+ from_profile = 129
+ to_profile = 129
-content = 2
++content = 34
+ rendered = 34
+ url = 2
+ created = 142
+ modified = 384
+ source = 2
+
+ [message__keys]
+ id = N
+
+ [nonce]
+ consumer_key = 130
+ tok = 2
+ nonce = 130
+ ts = 142
+ created = 142
+ modified = 384
+
+ [nonce__keys]
+ consumer_key = K
+ nonce = K
+ ts = K
+
+ [notice]
+ id = 129
+ profile_id = 129
+ uri = 2
-content = 2
++content = 34
+ rendered = 34
+ url = 2
+ created = 142
+ modified = 384
+ reply_to = 1
+ is_local = 17
+ source = 2
+ conversation = 1
+
+ [notice__keys]
+ id = N
+
+ [notice_inbox]
+ user_id = 129
+ notice_id = 129
+ created = 142
+ source = 17
+
+ [notice_inbox__keys]
+ user_id = K
+ notice_id = K
+
+ [notice_source]
+ code = 130
+ name = 130
+ url = 130
+ created = 142
+ modified = 384
+
+ [notice_source__keys]
+ code = K
+
+ [notice_tag]
+ tag = 130
+ notice_id = 129
+ created = 142
+
+ [notice_tag__keys]
+ tag = K
+ notice_id = K
+
+ [profile]
+ id = 129
nickname = 130
- hostname = 2
- pathname = 2
- dbhost = 2
- dbuser = 2
- dbpass = 2
- dbname = 2
- sitename = 2
- theme = 2
- logo = 2
- created = 142
- modified = 384
-
- [status_network__keys]
- nickname = K
- hostname = U
- pathname = U
+ fullname = 2
+ profileurl = 2
+ homepage = 2
-bio = 2
++bio = 34
+ location = 2
+ created = 142
+ modified = 384
+
+ [profile__keys]
+ id = N
+
+ [profile_block]
+ blocker = 129
+ blocked = 129
+ modified = 384
+
+ [profile_block__keys]
+ blocker = K
+ blocked = K
+
+ [profile_tag]
+ tagger = 129
+ tagged = 129
+ tag = 130
+ modified = 384
+
+ [profile_tag__keys]
+ tagger = K
+ tagged = K
+ tag = K
+
+ [queue_item]
+ notice_id = 129
+ transport = 130
+ created = 142
+ claimed = 14
+
+ [queue_item__keys]
+ notice_id = K
+ transport = K
+
+ [related_group]
+ group_id = 129
+ related_group_id = 129
+ created = 142
+
+ [related_group__keys]
+ group_id = K
+ related_group_id = K
+
+ [remember_me]
+ code = 130
+ user_id = 129
+ modified = 384
+
+ [remember_me__keys]
+ code = K
+
+ [remote_profile]
+ id = 129
+ uri = 2
+ postnoticeurl = 2
+ updateprofileurl = 2
+ created = 142
+ modified = 384
+
+ [remote_profile__keys]
+ id = K
+ uri = U
+
+ [reply]
+ notice_id = 129
+ profile_id = 129
+ modified = 384
+ replied_id = 1
+
+ [reply__keys]
+ notice_id = K
+ profile_id = K
+
+ [session]
+ id = 130
+ session_data = 34
+ created = 142
+ modified = 384
+
+ [session__keys]
+ id = K
+
+ [sms_carrier]
+ id = 129
+ name = 2
+ email_pattern = 130
+ created = 142
+ modified = 384
+
+ [sms_carrier__keys]
+ id = K
+ name = U
+
+ [subscription]
+ subscriber = 129
+ subscribed = 129
+ jabber = 17
+ sms = 17
+ token = 2
+ secret = 2
+ created = 142
+ modified = 384
+
+ [subscription__keys]
+ subscriber = K
+ subscribed = K
+
+ [token]
+ consumer_key = 130
+ tok = 130
+ secret = 130
+ type = 145
+ state = 17
+ created = 142
+ modified = 384
+
+ [token__keys]
+ consumer_key = K
+ tok = K
+
+ [user]
+ id = 129
+ nickname = 2
+ password = 2
+ email = 2
+ incomingemail = 2
+ emailnotifysub = 17
+ emailnotifyfav = 17
+ emailnotifynudge = 17
+ emailnotifymsg = 17
+ emailnotifyattn = 17
+ emailmicroid = 17
+ language = 2
+ timezone = 2
+ emailpost = 17
+ jabber = 2
+ jabbernotify = 17
+ jabberreplies = 17
+ jabbermicroid = 17
+ updatefrompresence = 17
+ sms = 2
+ carrier = 1
+ smsnotify = 17
+ smsreplies = 17
+ smsemail = 2
+ uri = 2
+ autosubscribe = 17
+ urlshorteningservice = 2
+ inboxed = 17
+ design_id = 1
+ viewdesigns = 17
+ created = 142
+ modified = 384
+
+ [user__keys]
+ id = K
+ nickname = U
+ email = U
+ incomingemail = U
+ jabber = U
+ sms = U
+ uri = U
+
+ [user_group]
+ id = 129
+ nickname = 2
+ fullname = 2
+ homepage = 2
-description = 2
++description = 34
+ location = 2
+ original_logo = 2
+ homepage_logo = 2
+ stream_logo = 2
+ mini_logo = 2
+ design_id = 1
+ created = 142
+ modified = 384
+
+ [user_group__keys]
+ id = N
+
+ [user_openid]
+ canonical = 130
+ display = 130
+ user_id = 129
+ created = 142
+ modified = 384
+
+ [user_openid__keys]
+ canonical = K
+ display = U
--- /dev/null
- bio varchar(140) comment 'descriptive biography',
+ /* local and remote users have profiles */
+
+ create table profile (
+ id integer auto_increment primary key comment 'unique identifier',
+ nickname varchar(64) not null comment 'nickname or username',
+ fullname varchar(255) comment 'display name',
+ profileurl varchar(255) comment 'URL, cached so we dont regenerate',
+ homepage varchar(255) comment 'identifying URL',
- content varchar(140) comment 'update content',
++ bio text comment 'descriptive biography',
+ location varchar(255) comment 'physical location',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ index profile_nickname_idx (nickname),
+ FULLTEXT(nickname, fullname, location, bio, homepage)
+ ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ create table avatar (
+ profile_id integer not null comment 'foreign key to profile table' references profile (id),
+ original boolean default false comment 'uploaded by user or generated?',
+ width integer not null comment 'image width',
+ height integer not null comment 'image height',
+ mediatype varchar(32) not null comment 'file type',
+ filename varchar(255) null comment 'local filename, if local',
+ url varchar(255) unique key comment 'avatar location',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (profile_id, width, height),
+ index avatar_profile_id_idx (profile_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table sms_carrier (
+ id integer primary key comment 'primary key for SMS carrier',
+ name varchar(64) unique key comment 'name of the carrier',
+ email_pattern varchar(255) not null comment 'sprintf pattern for making an email address from a phone number',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ /* local users */
+
+ create table user (
+
+ id integer primary key comment 'foreign key to profile table' references profile (id),
+ nickname varchar(64) unique key comment 'nickname or username, duped in profile',
+ password varchar(255) comment 'salted password, can be null for OpenID users',
+ email varchar(255) unique key comment 'email address for password recovery etc.',
+ incomingemail varchar(255) unique key comment 'email address for post-by-email',
+ emailnotifysub tinyint default 1 comment 'Notify by email of subscriptions',
+ emailnotifyfav tinyint default 1 comment 'Notify by email of favorites',
+ emailnotifynudge tinyint default 1 comment 'Notify by email of nudges',
+ emailnotifymsg tinyint default 1 comment 'Notify by email of direct messages',
+ emailnotifyattn tinyint default 1 comment 'Notify by email of @-replies',
+ emailmicroid tinyint default 1 comment 'whether to publish email microid',
+ language varchar(50) comment 'preferred language',
+ timezone varchar(50) comment 'timezone',
+ emailpost tinyint default 1 comment 'Post by email',
+ jabber varchar(255) unique key comment 'jabber ID for notices',
+ jabbernotify tinyint default 0 comment 'whether to send notices to jabber',
+ jabberreplies tinyint default 0 comment 'whether to send notices to jabber on replies',
+ jabbermicroid tinyint default 1 comment 'whether to publish xmpp microid',
+ updatefrompresence tinyint default 0 comment 'whether to record updates from Jabber presence notices',
+ sms varchar(64) unique key comment 'sms phone number',
+ carrier integer comment 'foreign key to sms_carrier' references sms_carrier (id),
+ smsnotify tinyint default 0 comment 'whether to send notices to SMS',
+ smsreplies tinyint default 0 comment 'whether to send notices to SMS on replies',
+ smsemail varchar(255) comment 'built from sms and carrier',
+ uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
+ autosubscribe tinyint default 0 comment 'automatically subscribe to users who subscribe to us',
+ urlshorteningservice varchar(50) default 'ur1.ca' comment 'service to use for auto-shortening URLs',
+ inboxed tinyint default 0 comment 'has an inbox been created for this user?',
+ design_id integer comment 'id of a design' references design(id),
+ viewdesigns tinyint default 1 comment 'whether to view user-provided designs',
+
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ index user_smsemail_idx (smsemail)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ /* remote people */
+
+ create table remote_profile (
+ id integer primary key comment 'foreign key to profile table' references profile (id),
+ uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
+ postnoticeurl varchar(255) comment 'URL we use for posting notices',
+ updateprofileurl varchar(255) comment 'URL we use for updates to this profile',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table subscription (
+ subscriber integer not null comment 'profile listening',
+ subscribed integer not null comment 'profile being listened to',
+ jabber tinyint default 1 comment 'deliver jabber messages',
+ sms tinyint default 1 comment 'deliver sms messages',
+ token varchar(255) comment 'authorization token',
+ secret varchar(255) comment 'token secret',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (subscriber, subscribed),
+ index subscription_subscriber_idx (subscriber),
+ index subscription_subscribed_idx (subscribed),
+ index subscription_token_idx (token)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table notice (
+ id integer auto_increment primary key comment 'unique identifier',
+ profile_id integer not null comment 'who made the update' references profile (id),
+ uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
- content varchar(140) comment 'message content',
++ content text comment 'update content',
+ rendered text comment 'HTML version of the content',
+ url varchar(255) comment 'URL of any attachment (image, video, bookmark, whatever)',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+ reply_to integer comment 'notice replied to (usually a guess)' references notice (id),
+ is_local tinyint default 0 comment 'notice was generated by a user',
+ source varchar(32) comment 'source of comment, like "web", "im", or "clientname"',
+ conversation integer comment 'id of root notice in this conversation' references notice (id),
+
+ index notice_profile_id_idx (profile_id),
+ index notice_conversation_idx (conversation),
+ index notice_created_idx (created),
+ index notice_replyto_idx (reply_to),
+ FULLTEXT(content)
+ ) ENGINE=MyISAM CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ create table notice_source (
+ code varchar(32) primary key not null comment 'source code',
+ name varchar(255) not null comment 'name of the source',
+ url varchar(255) not null comment 'url to link to',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table reply (
+ notice_id integer not null comment 'notice that is the reply' references notice (id),
+ profile_id integer not null comment 'profile replied to' references profile (id),
+ modified timestamp not null comment 'date this record was modified',
+ replied_id integer comment 'notice replied to (not used, see notice.reply_to)',
+
+ constraint primary key (notice_id, profile_id),
+ index reply_notice_id_idx (notice_id),
+ index reply_profile_id_idx (profile_id),
+ index reply_replied_id_idx (replied_id)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table fave (
+ notice_id integer not null comment 'notice that is the favorite' references notice (id),
+ user_id integer not null comment 'user who likes this notice' references user (id),
+ modified timestamp not null comment 'date this record was modified',
+
+ constraint primary key (notice_id, user_id),
+ index fave_notice_id_idx (notice_id),
+ index fave_user_id_idx (user_id),
+ index fave_modified_idx (modified)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ /* tables for OAuth */
+
+ create table consumer (
+ consumer_key varchar(255) primary key comment 'unique identifier, root URL',
+ seed char(32) not null comment 'seed for new tokens by this consumer',
+
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table token (
+ consumer_key varchar(255) not null comment 'unique identifier, root URL' references consumer (consumer_key),
+ tok char(32) not null comment 'identifying value',
+ secret char(32) not null comment 'secret value',
+ type tinyint not null default 0 comment 'request or access',
+ state tinyint default 0 comment 'for requests, 0 = initial, 1 = authorized, 2 = used',
+
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (consumer_key, tok)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table nonce (
+ consumer_key varchar(255) not null comment 'unique identifier, root URL',
+ tok char(32) null comment 'buggy old value, ignored',
+ nonce char(32) not null comment 'nonce',
+ ts datetime not null comment 'timestamp sent',
+
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (consumer_key, ts, nonce)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ /* One-to-many relationship of user to openid_url */
+
+ create table user_openid (
+ canonical varchar(255) primary key comment 'Canonical true URL',
+ display varchar(255) not null unique key comment 'URL for viewing, may be different from canonical',
+ user_id integer not null comment 'user owning this URL' references user (id),
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ index user_openid_user_id_idx (user_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ /* These are used by JanRain OpenID library */
+
+ create table oid_associations (
+ server_url BLOB,
+ handle VARCHAR(255) character set latin1,
+ secret BLOB,
+ issued INTEGER,
+ lifetime INTEGER,
+ assoc_type VARCHAR(64),
+ PRIMARY KEY (server_url(255), handle)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table oid_nonces (
+ server_url VARCHAR(2047),
+ timestamp INTEGER,
+ salt CHAR(40),
+ UNIQUE (server_url(255), timestamp, salt)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table confirm_address (
+ code varchar(32) not null primary key comment 'good random code',
+ user_id integer not null comment 'user who requested confirmation' references user (id),
+ address varchar(255) not null comment 'address (email, Jabber, SMS, etc.)',
+ address_extra varchar(255) not null comment 'carrier ID, for SMS',
+ address_type varchar(8) not null comment 'address type ("email", "jabber", "sms")',
+ claimed datetime comment 'date this was claimed for queueing',
+ sent datetime comment 'date this was sent for queueing',
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table remember_me (
+ code varchar(32) not null primary key comment 'good random code',
+ user_id integer not null comment 'user who is logged in' references user (id),
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table queue_item (
+
+ notice_id integer not null comment 'notice queued' references notice (id),
+ transport varchar(8) not null comment 'queue for what? "email", "jabber", "sms", "irc", ...',
+ created datetime not null comment 'date this record was created',
+ claimed datetime comment 'date this item was claimed',
+
+ constraint primary key (notice_id, transport),
+ index queue_item_created_idx (created)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ /* Hash tags */
+ create table notice_tag (
+ tag varchar( 64 ) not null comment 'hash tag associated with this notice',
+ notice_id integer not null comment 'notice tagged' references notice (id),
+ created datetime not null comment 'date this record was created',
+
+ constraint primary key (tag, notice_id),
+ index notice_tag_created_idx (created),
+ index notice_tag_notice_id_idx (notice_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ /* Synching with foreign services */
+
+ create table foreign_service (
+ id int not null primary key comment 'numeric key for service',
+ name varchar(32) not null unique key comment 'name of the service',
+ description varchar(255) comment 'description',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table foreign_user (
+ id bigint not null comment 'unique numeric key on foreign service',
+ service int not null comment 'foreign key to service' references foreign_service(id),
+ uri varchar(255) not null unique key comment 'identifying URI',
+ nickname varchar(255) comment 'nickname on foreign service',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (id, service)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table foreign_link (
+ user_id int comment 'link to user on this system, if exists' references user (id),
+ foreign_id bigint unsigned comment 'link to user on foreign service, if exists' references foreign_user(id),
+ service int not null comment 'foreign key to service' references foreign_service(id),
+ credentials varchar(255) comment 'authc credentials, typically a password',
+ noticesync tinyint not null default 1 comment 'notice synchronization, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies',
+ friendsync tinyint not null default 2 comment 'friend synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
+ profilesync tinyint not null default 1 comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming',
+ last_noticesync datetime default null comment 'last time notices were imported',
+ last_friendsync datetime default null comment 'last time friends were imported',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (user_id, foreign_id, service),
+ index foreign_user_user_id_idx (user_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table foreign_subscription (
+ service int not null comment 'service where relationship happens' references foreign_service(id),
+ subscriber int not null comment 'subscriber on foreign service' references foreign_user (id),
+ subscribed int not null comment 'subscribed user' references foreign_user (id),
+ created datetime not null comment 'date this record was created',
+
+ constraint primary key (service, subscriber, subscribed),
+ index foreign_subscription_subscriber_idx (subscriber),
+ index foreign_subscription_subscribed_idx (subscribed)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table invitation (
+ code varchar(32) not null primary key comment 'random code for an invitation',
+ user_id int not null comment 'who sent the invitation' references user (id),
+ address varchar(255) not null comment 'invitation sent to',
+ address_type varchar(8) not null comment 'address type ("email", "jabber", "sms")',
+ created datetime not null comment 'date this record was created',
+
+ index invitation_address_idx (address, address_type),
+ index invitation_user_id_idx (user_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table message (
+ id integer auto_increment primary key comment 'unique identifier',
+ uri varchar(255) unique key comment 'universally unique identifier',
+ from_profile integer not null comment 'who the message is from' references profile (id),
+ to_profile integer not null comment 'who the message is to' references profile (id),
- description varchar(140) comment 'descriptive biography',
++ content text comment 'message content',
+ rendered text comment 'HTML version of the content',
+ url varchar(255) comment 'URL of any attachment (image, video, bookmark, whatever)',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+ source varchar(32) comment 'source of comment, like "web", "im", or "clientname"',
+
+ index message_from_idx (from_profile),
+ index message_to_idx (to_profile),
+ index message_created_idx (created)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ create table notice_inbox (
+ user_id integer not null comment 'user receiving the message' references user (id),
+ notice_id integer not null comment 'notice received' references notice (id),
+ created datetime not null comment 'date the notice was created',
+ source tinyint default 1 comment 'reason it is in the inbox, 1=subscription',
+
+ constraint primary key (user_id, notice_id),
+ index notice_inbox_notice_id_idx (notice_id)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table profile_tag (
+ tagger integer not null comment 'user making the tag' references user (id),
+ tagged integer not null comment 'profile tagged' references profile (id),
+ tag varchar(64) not null comment 'hash tag associated with this notice',
+ modified timestamp comment 'date the tag was added',
+
+ constraint primary key (tagger, tagged, tag),
+ index profile_tag_modified_idx (modified),
+ index profile_tag_tagger_tag_idx (tagger, tag),
+ index profile_tag_tagged_idx (tagged)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table profile_block (
+ blocker integer not null comment 'user making the block' references user (id),
+ blocked integer not null comment 'profile that is blocked' references profile (id),
+ modified timestamp comment 'date of blocking',
+
+ constraint primary key (blocker, blocked)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table user_group (
+ id integer auto_increment primary key comment 'unique identifier',
+
+ nickname varchar(64) unique key comment 'nickname for addressing',
+ fullname varchar(255) comment 'display name',
+ homepage varchar(255) comment 'URL, cached so we dont regenerate',
-) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
++ description text comment 'group description',
+ location varchar(255) comment 'related physical location, if any',
+
+ original_logo varchar(255) comment 'original size logo',
+ homepage_logo varchar(255) comment 'homepage (profile) size logo',
+ stream_logo varchar(255) comment 'stream-sized logo',
+ mini_logo varchar(255) comment 'mini logo',
+ design_id integer comment 'id of a design' references design(id),
+
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ index user_group_nickname_idx (nickname)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ create table group_member (
+ group_id integer not null comment 'foreign key to user_group' references user_group (id),
+ profile_id integer not null comment 'foreign key to profile table' references profile (id),
+ is_admin boolean default false comment 'is this user an admin?',
+
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (group_id, profile_id),
+ index group_member_profile_id_idx (profile_id),
+ index group_member_created_idx (created)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table related_group (
+ group_id integer not null comment 'foreign key to user_group' references user_group (id),
+ related_group_id integer not null comment 'foreign key to user_group' references user_group (id),
+
+ created datetime not null comment 'date this record was created',
+
+ constraint primary key (group_id, related_group_id)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table group_inbox (
+ group_id integer not null comment 'group receiving the message' references user_group (id),
+ notice_id integer not null comment 'notice received' references notice (id),
+ created datetime not null comment 'date the notice was created',
+
+ constraint primary key (group_id, notice_id),
+ index group_inbox_created_idx (created)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table file (
+
+ id integer primary key auto_increment,
+ url varchar(255) comment 'destination URL after following redirections',
+ mimetype varchar(50) comment 'mime type of resource',
+ size integer comment 'size of resource when available',
+ title varchar(255) comment 'title of resource when available',
+ date integer(11) comment 'date of resource according to http query',
+ protected integer(1) comment 'true when URL is private (needs login)',
+ filename varchar(255) comment 'if a local file, name of the file',
+
+ modified timestamp comment 'date this record was modified',
+
+ unique(url)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ create table file_oembed (
+ file_id integer primary key comment 'oEmbed for that URL/file' references file (id),
+ version varchar(20) comment 'oEmbed spec. version',
+ type varchar(20) comment 'oEmbed type: photo, video, link, rich',
+ provider varchar(50) comment 'name of this oEmbed provider',
+ provider_url varchar(255) comment 'URL of this oEmbed provider',
+ width integer comment 'width of oEmbed resource when available',
+ height integer comment 'height of oEmbed resource when available',
+ html text comment 'html representation of this oEmbed resource when applicable',
+ title varchar(255) comment 'title of oEmbed resource when available',
+ author_name varchar(50) comment 'author name for this oEmbed resource',
+ author_url varchar(255) comment 'author URL for this oEmbed resource',
+ url varchar(255) comment 'URL for this oEmbed resource when applicable (photo, link)',
+ modified timestamp comment 'date this record was modified'
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;
+
+ create table file_redirection (
+
+ url varchar(255) primary key comment 'short URL (or any other kind of redirect) for file (id)',
+ file_id integer comment 'short URL for what URL/file' references file (id),
+ redirections integer comment 'redirect count',
+ httpcode integer comment 'HTTP status code (20x, 30x, etc.)',
+ modified timestamp comment 'date this record was modified'
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table file_thumbnail (
+
+ file_id integer primary key comment 'thumbnail for what URL/file' references file (id),
+ url varchar(255) comment 'URL of thumbnail',
+ width integer comment 'width of thumbnail',
+ height integer comment 'height of thumbnail',
+ modified timestamp comment 'date this record was modified',
+
+ unique(url)
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table file_to_post (
+
+ file_id integer comment 'id of URL/file' references file (id),
+ post_id integer comment 'id of the notice it belongs to' references notice (id),
+ modified timestamp comment 'date this record was modified',
+
+ constraint primary key (file_id, post_id)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table design (
+ id integer primary key auto_increment comment 'design ID',
+ backgroundcolor integer comment 'main background color',
+ contentcolor integer comment 'content area background color',
+ sidebarcolor integer comment 'sidebar background color',
+ textcolor integer comment 'text color',
+ linkcolor integer comment 'link color',
+ backgroundimage varchar(255) comment 'background image, if any',
+ disposition tinyint default 1 comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table group_block (
+ group_id integer not null comment 'group profile is blocked from' references user_group (id),
+ blocked integer not null comment 'profile that is blocked' references profile (id),
+ blocker integer not null comment 'user making the block' references user (id),
+ modified timestamp comment 'date of blocking',
+
+ constraint primary key (group_id, blocked)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table group_alias (
+
+ alias varchar(64) primary key comment 'additional nickname for the group',
+ group_id integer not null comment 'group profile is blocked from' references user_group (id),
+ modified timestamp comment 'date alias was created',
+
+ index group_alias_group_id_idx (group_id)
+
+ ) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
+
+ create table session (
+
+ id varchar(32) primary key comment 'session ID',
+ session_data text comment 'session data',
+ created datetime not null comment 'date this record was created',
+ modified timestamp comment 'date this record was modified',
+
+ index session_modified_idx (modified)
+
++) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
++
++create table deleted_notice (
++
++ id integer primary key comment 'identity of notice',
++ profile_id integer not null comment 'author of the notice',
++ uri varchar(255) unique key comment 'universally unique identifier, usually a tag URI',
++ created datetime not null comment 'date the notice record was created',
++ deleted datetime not null comment 'date the notice record was created',
++
++ index deleted_notice_profile_id_idx (profile_id)
++
++) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
++
++create table config (
++
++ section varchar(32) comment 'configuration section',
++ setting varchar(32) comment 'configuration setting',
++ value varchar(255) comment 'configuration value',
++
++ constraint primary key (section, setting)
++
++) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin;
--- /dev/null
+ /* local and remote users have profiles */
+
+ create sequence profile_seq;
+ create table profile (
+ id bigint default nextval('profile_seq') primary key /* comment 'unique identifier' */,
+ nickname varchar(64) not null /* comment 'nickname or username' */,
+ fullname varchar(255) /* comment 'display name' */,
+ profileurl varchar(255) /* comment 'URL, cached so we dont regenerate' */,
+ homepage varchar(255) /* comment 'identifying URL' */,
+ bio varchar(140) /* comment 'descriptive biography' */,
+ location varchar(255) /* comment 'physical location' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ textsearch tsvector
+ );
+ create index profile_nickname_idx on profile using btree(nickname);
+
+ create table avatar (
+ profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id) ,
+ original integer default 0 /* comment 'uploaded by user or generated?' */,
+ width integer not null /* comment 'image width' */,
+ height integer not null /* comment 'image height' */,
+ mediatype varchar(32) not null /* comment 'file type' */,
+ filename varchar(255) null /* comment 'local filename, if local' */,
+ url varchar(255) unique /* comment 'avatar location' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key(profile_id, width, height)
+ );
+ create index avatar_profile_id_idx on avatar using btree(profile_id);
+
+ create sequence sms_carrier_seq;
+ create table sms_carrier (
+ id bigint default nextval('sms_carrier_seq') primary key /* comment 'primary key for SMS carrier' */,
+ name varchar(64) unique /* comment 'name of the carrier' */,
+ email_pattern varchar(255) not null /* comment 'sprintf pattern for making an email address from a phone number' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified ' */
+ );
+
+ create sequence design_seq;
+ create table design (
+ id bigint default nextval('design_seq') /* comment 'design ID'*/,
+ backgroundcolor integer /* comment 'main background color'*/ ,
+ contentcolor integer /*comment 'content area background color'*/ ,
+ sidebarcolor integer /*comment 'sidebar background color'*/ ,
+ textcolor integer /*comment 'text color'*/ ,
+ linkcolor integer /*comment 'link color'*/,
+ backgroundimage varchar(255) /*comment 'background image, if any'*/,
+ disposition int default 1 /*comment 'bit 1 = hide background image, bit 2 = display background image, bit 4 = tile background image'*/,
+ primary key (id)
+ );
+
+ /* local users */
+
+ create table "user" (
+ id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
+ nickname varchar(64) unique /* comment 'nickname or username, duped in profile' */,
+ password varchar(255) /* comment 'salted password, can be null for OpenID users' */,
+ email varchar(255) unique /* comment 'email address for password recovery etc.' */,
+ incomingemail varchar(255) unique /* comment 'email address for post-by-email' */,
+ emailnotifysub integer default 1 /* comment 'Notify by email of subscriptions' */,
+ emailnotifyfav integer default 1 /* comment 'Notify by email of favorites' */,
+ emailnotifynudge integer default 1 /* comment 'Notify by email of nudges' */,
+ emailnotifymsg integer default 1 /* comment 'Notify by email of direct messages' */,
+ emailnotifyattn integer default 1 /* command 'Notify by email of @-replies' */,
+ emailmicroid integer default 1 /* comment 'whether to publish email microid' */,
+ language varchar(50) /* comment 'preferred language' */,
+ timezone varchar(50) /* comment 'timezone' */,
+ emailpost integer default 1 /* comment 'Post by email' */,
+ jabber varchar(255) unique /* comment 'jabber ID for notices' */,
+ jabbernotify integer default 0 /* comment 'whether to send notices to jabber' */,
+ jabberreplies integer default 0 /* comment 'whether to send notices to jabber on replies' */,
+ jabbermicroid integer default 1 /* comment 'whether to publish xmpp microid' */,
+ updatefrompresence integer default 0 /* comment 'whether to record updates from Jabber presence notices' */,
+ sms varchar(64) unique /* comment 'sms phone number' */,
+ carrier integer /* comment 'foreign key to sms_carrier' */ references sms_carrier (id) ,
+ smsnotify integer default 0 /* comment 'whether to send notices to SMS' */,
+ smsreplies integer default 0 /* comment 'whether to send notices to SMS on replies' */,
+ smsemail varchar(255) /* comment 'built from sms and carrier' */,
+ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+ autosubscribe integer default 0 /* comment 'automatically subscribe to users who subscribe to us' */,
+ urlshorteningservice varchar(50) default 'ur1.ca' /* comment 'service to use for auto-shortening URLs' */,
+ inboxed integer default 0 /* comment 'has an inbox been created for this user?' */,
+ design_id integer /* comment 'id of a design' */references design(id),
+ viewdesigns integer default 1 /* comment 'whether to view user-provided designs'*/,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+
+ );
+ create index user_smsemail_idx on "user" using btree(smsemail);
+
+ /* remote people */
+
+ create table remote_profile (
+ id integer primary key /* comment 'foreign key to profile table' */ references profile (id) ,
+ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+ postnoticeurl varchar(255) /* comment 'URL we use for posting notices' */,
+ updateprofileurl varchar(255) /* comment 'URL we use for updates to this profile' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+ );
+
+ create table subscription (
+ subscriber integer not null /* comment 'profile listening' */,
+ subscribed integer not null /* comment 'profile being listened to' */,
+ jabber integer default 1 /* comment 'deliver jabber messages' */,
+ sms integer default 1 /* comment 'deliver sms messages' */,
+ token varchar(255) /* comment 'authorization token' */,
+ secret varchar(255) /* comment 'token secret' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (subscriber, subscribed)
+ );
+ create index subscription_subscriber_idx on subscription using btree(subscriber);
+ create index subscription_subscribed_idx on subscription using btree(subscribed);
+
+ create sequence notice_seq;
+ create table notice (
+
+ id bigint default nextval('notice_seq') primary key /* comment 'unique identifier' */,
+ profile_id integer not null /* comment 'who made the update' */ references profile (id) ,
+ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI' */,
+ content varchar(140) /* comment 'update content' */,
+ rendered text /* comment 'HTML version of the content' */,
+ url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+ reply_to integer /* comment 'notice replied to (usually a guess)' */ references notice (id) ,
+ is_local integer default 0 /* comment 'notice was generated by a user' */,
+ source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */,
+ conversation integer /*id of root notice in this conversation' */ references notice (id)
+
+
+ /* FULLTEXT(content) */
+ );
+ create index notice_profile_id_idx on notice using btree(profile_id);
+ create index notice_created_idx on notice using btree(created);
+
+ create table notice_source (
+ code varchar(32) primary key not null /* comment 'source code' */,
+ name varchar(255) not null /* comment 'name of the source' */,
+ url varchar(255) not null /* comment 'url to link to' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+ );
+
+ create table reply (
+
+ notice_id integer not null /* comment 'notice that is the reply' */ references notice (id) ,
+ profile_id integer not null /* comment 'profile replied to' */ references profile (id) ,
+ modified timestamp /* comment 'date this record was modified' */,
+ replied_id integer /* comment 'notice replied to (not used, see notice.reply_to)' */,
+
+ primary key (notice_id, profile_id)
+
+ );
+ create index reply_notice_id_idx on reply using btree(notice_id);
+ create index reply_profile_id_idx on reply using btree(profile_id);
+ create index reply_replied_id_idx on reply using btree(replied_id);
+
+ create table fave (
+
+ notice_id integer not null /* comment 'notice that is the favorite' */ references notice (id),
+ user_id integer not null /* comment 'user who likes this notice' */ references "user" (id) ,
+ modified timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was modified' */,
+ primary key (notice_id, user_id)
+
+ );
+ create index fave_notice_id_idx on fave using btree(notice_id);
+ create index fave_user_id_idx on fave using btree(user_id);
+ create index fave_modified_idx on fave using btree(modified);
+
+ /* tables for OAuth */
+
+ create table consumer (
+ consumer_key varchar(255) primary key /* comment 'unique identifier, root URL' */,
+ seed char(32) not null /* comment 'seed for new tokens by this consumer' */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+ );
+
+ create table token (
+ consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */ references consumer (consumer_key),
+ tok char(32) not null /* comment 'identifying value' */,
+ secret char(32) not null /* comment 'secret value' */,
+ type integer not null default 0 /* comment 'request or access' */,
+ state integer default 0 /* comment 'for requests 0 = initial, 1 = authorized, 2 = used' */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (consumer_key, tok)
+ );
+
+ create table nonce (
+ consumer_key varchar(255) not null /* comment 'unique identifier, root URL' */,
+ tok char(32) /* comment 'buggy old value, ignored' */,
+ nonce char(32) null /* comment 'buggy old value, ignored */,
+ ts integer not null /* comment 'timestamp sent' values are epoch, and only used internally */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (consumer_key, ts, nonce)
+ );
+
+ /* One-to-many relationship of user to openid_url */
+
+ create table user_openid (
+ canonical varchar(255) primary key /* comment 'Canonical true URL' */,
+ display varchar(255) not null unique /* comment 'URL for viewing, may be different from canonical' */,
+ user_id integer not null /* comment 'user owning this URL' */ references "user" (id) ,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+
+ );
+ create index user_openid_user_id_idx on user_openid using btree(user_id);
+
+ /* These are used by JanRain OpenID library */
+
+ create table oid_associations (
+ server_url varchar(2047),
+ handle varchar(255),
+ secret bytea,
+ issued integer,
+ lifetime integer,
+ assoc_type varchar(64),
+ primary key (server_url, handle)
+ );
+
+ create table oid_nonces (
+ server_url varchar(2047),
+ "timestamp" integer,
+ salt character(40),
+ unique (server_url, "timestamp", salt)
+ );
+
+ create table confirm_address (
+ code varchar(32) not null primary key /* comment 'good random code' */,
+ user_id integer not null /* comment 'user who requested confirmation' */ references "user" (id),
+ address varchar(255) not null /* comment 'address (email, Jabber, SMS, etc.)' */,
+ address_extra varchar(255) not null default '' /* comment 'carrier ID, for SMS' */,
+ address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms")' */,
+ claimed timestamp /* comment 'date this was claimed for queueing' */,
+ sent timestamp /* comment 'date this was sent for queueing' */,
+ modified timestamp /* comment 'date this record was modified' */
+ );
+
+ create table remember_me (
+ code varchar(32) not null primary key /* comment 'good random code' */,
+ user_id integer not null /* comment 'user who is logged in' */ references "user" (id),
+ modified timestamp /* comment 'date this record was modified' */
+ );
+
+ create table queue_item (
+
+ notice_id integer not null /* comment 'notice queued' */ references notice (id) ,
+ transport varchar(8) not null /* comment 'queue for what? "email", "jabber", "sms", "irc", ...' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ claimed timestamp /* comment 'date this item was claimed' */,
+
+ primary key (notice_id, transport)
+
+ );
+ create index queue_item_created_idx on queue_item using btree(created);
+
+ /* Hash tags */
+ create table notice_tag (
+ tag varchar( 64 ) not null /* comment 'hash tag associated with this notice' */,
+ notice_id integer not null /* comment 'notice tagged' */ references notice (id) ,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+
+ primary key (tag, notice_id)
+ );
+ create index notice_tag_created_idx on notice_tag using btree(created);
+
+ /* Synching with foreign services */
+
+ create table foreign_service (
+ id int not null primary key /* comment 'numeric key for service' */,
+ name varchar(32) not null unique /* comment 'name of the service' */,
+ description varchar(255) /* comment 'description' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+ );
+
+ create table foreign_user (
+ id int not null unique /* comment 'unique numeric key on foreign service' */,
+ service int not null /* comment 'foreign key to service' */ references foreign_service(id) ,
+ uri varchar(255) not null unique /* comment 'identifying URI' */,
+ nickname varchar(255) /* comment 'nickname on foreign service' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (id, service)
+ );
+
+ create table foreign_link (
+ user_id int /* comment 'link to user on this system, if exists' */ references "user" (id),
+ foreign_id int /* comment 'link' */ references foreign_user (id),
+ service int not null /* comment 'foreign key to service' */ references foreign_service (id),
+ credentials varchar(255) /* comment 'authc credentials, typically a password' */,
+ noticesync int not null default 1 /* comment 'notice synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming, bit 3 = filter local replies' */,
+ friendsync int not null default 2 /* comment 'friend synchronisation, bit 1 = sync outgoing, bit 2 = sync incoming */,
+ profilesync int not null default 1 /* comment 'profile synchronization, bit 1 = sync outgoing, bit 2 = sync incoming' */,
+ last_noticesync timestamp default null /* comment 'last time notices were imported' */,
+ last_friendsync timestamp default null /* comment 'last time friends were imported' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (user_id,foreign_id,service)
+ );
+ create index foreign_user_user_id_idx on foreign_link using btree(user_id);
+
+ create table foreign_subscription (
+ service int not null /* comment 'service where relationship happens' */ references foreign_service(id) ,
+ subscriber int not null /* comment 'subscriber on foreign service' */ ,
+ subscribed int not null /* comment 'subscribed user' */ ,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+
+ primary key (service, subscriber, subscribed)
+ );
+ create index foreign_subscription_subscriber_idx on foreign_subscription using btree(subscriber);
+ create index foreign_subscription_subscribed_idx on foreign_subscription using btree(subscribed);
+
+ create table invitation (
+ code varchar(32) not null primary key /* comment 'random code for an invitation' */,
+ user_id int not null /* comment 'who sent the invitation' */ references "user" (id),
+ address varchar(255) not null /* comment 'invitation sent to' */,
+ address_type varchar(8) not null /* comment 'address type ("email", "jabber", "sms") '*/,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */
+
+ );
+ create index invitation_address_idx on invitation using btree(address,address_type);
+ create index invitation_user_id_idx on invitation using btree(user_id);
+
+ create sequence message_seq;
+ create table message (
+
+ id bigint default nextval('message_seq') primary key /* comment 'unique identifier' */,
+ uri varchar(255) unique /* comment 'universally unique identifier' */,
+ from_profile integer not null /* comment 'who the message is from' */ references profile (id),
+ to_profile integer not null /* comment 'who the message is to' */ references profile (id),
+ content varchar(140) /* comment 'message content' */,
+ rendered text /* comment 'HTML version of the content' */,
+ url varchar(255) /* comment 'URL of any attachment (image, video, bookmark, whatever)' */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+ source varchar(32) /* comment 'source of comment, like "web", "im", or "clientname"' */
+
+ );
+ create index message_from_idx on message using btree(from_profile);
+ create index message_to_idx on message using btree(to_profile);
+ create index message_created_idx on message using btree(created);
+
+ create table notice_inbox (
+
+ user_id integer not null /* comment 'user receiving the message' */ references "user" (id),
+ notice_id integer not null /* comment 'notice received' */ references notice (id),
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
+ source integer default 1 /* comment 'reason it is in the inbox: 1=subscription' */,
+
+ primary key (user_id, notice_id)
+ );
+ create index notice_inbox_notice_id_idx on notice_inbox using btree(notice_id);
+
+ create table profile_tag (
+ tagger integer not null /* comment 'user making the tag' */ references "user" (id),
+ tagged integer not null /* comment 'profile tagged' */ references profile (id),
+ tag varchar(64) not null /* comment 'hash tag associated with this notice' */,
+ modified timestamp /* comment 'date the tag was added' */,
+
+ primary key (tagger, tagged, tag)
+ );
+ create index profile_tag_modified_idx on profile_tag using btree(modified);
+ create index profile_tag_tagger_tag_idx on profile_tag using btree(tagger,tag);
+
+ create table profile_block (
+
+ blocker integer not null /* comment 'user making the block' */ references "user" (id),
+ blocked integer not null /* comment 'profile that is blocked' */ references profile (id),
+ modified timestamp /* comment 'date of blocking' */,
+
+ primary key (blocker, blocked)
+
+ );
+
+ create sequence user_group_seq;
+ create table user_group (
+
+ id bigint default nextval('user_group_seq') primary key /* comment 'unique identifier' */,
+
+ nickname varchar(64) unique /* comment 'nickname for addressing' */,
+ fullname varchar(255) /* comment 'display name' */,
+ homepage varchar(255) /* comment 'URL, cached so we dont regenerate' */,
+ description varchar(140) /* comment 'descriptive biography' */,
+ location varchar(255) /* comment 'related physical location, if any' */,
+
+ original_logo varchar(255) /* comment 'original size logo' */,
+ homepage_logo varchar(255) /* comment 'homepage (profile) size logo' */,
+ stream_logo varchar(255) /* comment 'stream-sized logo' */,
+ mini_logo varchar(255) /* comment 'mini logo' */,
+ design_id integer /*comment 'id of a design' */ references design(id),
+
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */
+
+ );
+ create index user_group_nickname_idx on user_group using btree(nickname);
+
+ create table group_member (
+
+ group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
+ profile_id integer not null /* comment 'foreign key to profile table' */ references profile (id),
+ is_admin integer default 0 /* comment 'is this user an admin?' */,
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+ modified timestamp /* comment 'date this record was modified' */,
+
+ primary key (group_id, profile_id)
+ );
+
+ create table related_group (
+
+ group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id) ,
+ related_group_id integer not null /* comment 'foreign key to user_group' */ references user_group (id),
+
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date this record was created' */,
+
+ primary key (group_id, related_group_id)
+
+ );
+
+ create table group_inbox (
+ group_id integer not null /* comment 'group receiving the message' references user_group (id) */,
+ notice_id integer not null /* comment 'notice received' references notice (id) */,
+ created timestamp not null default CURRENT_TIMESTAMP /* comment 'date the notice was created' */,
+ primary key (group_id, notice_id)
+ );
+ create index group_inbox_created_idx on group_inbox using btree(created);
+
+
+ /*attachments and URLs stuff */
+ create sequence file_seq;
+ create table file (
+ id bigint default nextval('file_seq') primary key /* comment 'unique identifier' */,
+ url varchar(255) unique,
+ mimetype varchar(50),
+ size integer,
+ title varchar(255),
+ date integer,
+ protected integer,
+ filename text /* comment 'if a local file, name of the file' */,
+ modified timestamp default CURRENT_TIMESTAMP /* comment 'date this record was modified'*/
+ );
+
+ create sequence file_oembed_seq;
+ create table file_oembed (
+ file_id bigint default nextval('file_oembed_seq') primary key /* comment 'unique identifier' */,
+ version varchar(20),
+ type varchar(20),
+ provider varchar(50),
+ provider_url varchar(255),
+ width integer,
+ height integer,
+ html text,
+ title varchar(255),
+ author_name varchar(50),
+ author_url varchar(255),
+ url varchar(255)
+ );
+
+ create sequence file_redirection_seq;
+ create table file_redirection (
+ url varchar(255) primary key,
+ file_id bigint,
+ redirections integer,
+ httpcode integer
+ );
+
+ create sequence file_thumbnail_seq;
+ create table file_thumbnail (
+ file_id bigint primary key,
+ url varchar(255) unique,
+ width integer,
+ height integer
+ );
+
+ create sequence file_to_post_seq;
+ create table file_to_post (
+ file_id bigint,
+ post_id bigint,
+
+ primary key (file_id, post_id)
+ );
+
+ create table group_block (
+ group_id integer not null /* comment 'group profile is blocked from' */ references user_group (id),
+ blocked integer not null /* comment 'profile that is blocked' */references profile (id),
+ blocker integer not null /* comment 'user making the block'*/ references "user" (id),
+ modified timestamp /* comment 'date of blocking'*/ ,
+
+ primary key (group_id, blocked)
+ );
+
+ create table group_alias (
+
+ alias varchar(64) /* comment 'additional nickname for the group'*/ ,
+ group_id integer not null /* comment 'group profile is blocked from'*/ references user_group (id),
+ modified timestamp /* comment 'date alias was created'*/,
+ primary key (alias)
+
+ );
+ create index group_alias_group_id_idx on group_alias (group_id);
+
+ create table session (
+
+ id varchar(32) primary key /* comment 'session ID'*/,
+ session_data text /* comment 'session data'*/,
+ created timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date this record was created'*/,
+ modified integer DEFAULT extract(epoch from CURRENT_TIMESTAMP) /* comment 'date this record was modified'*/
+ );
+
+ create index session_modified_idx on session (modified);
+
++create table deleted_notice (
++
++ id integer primary key /* comment 'identity of notice'*/ ,
++ profile_id integer /* not null comment 'author of the notice'*/,
++ uri varchar(255) unique /* comment 'universally unique identifier, usually a tag URI'*/,
++ created timestamp not null /* comment 'date the notice record was created'*/ ,
++ deleted timestamp not null DEFAULT CURRENT_TIMESTAMP /* comment 'date the notice record was created'*/
++);
++
++CREATE index deleted_notice_profile_id_idx on deleted_notice (profile_id);
++
+
+ /* Textsearch stuff */
+
+ create index textsearch_idx on profile using gist(textsearch);
+ create index noticecontent_idx on notice using gist(to_tsvector('english',content));
+ create trigger textsearchupdate before insert or update on profile for each row
+ execute procedure tsvector_update_trigger(textsearch, 'pg_catalog.english', nickname, fullname, location, bio, homepage);
+
* [SMS](%%doc.sms%%) - tying your cellphone to %%site.name%%
* [tags](%%doc.tags%%) - different ways to use tagging
* [Groups](%%doc.groups%%) - joining together in groups
-* [OpenID](%%doc.openid%%) - what OpenID is and how to use it with this service
* [OpenMicroBlogging](%%doc.openmublog%%) - subscribing to remote users
* [Privacy](%%doc.privacy%%) - %%site.name%%'s privacy policy
- * [Source](%%doc.source%%) - How to get the Laconica source code
- * [Badge](%%doc.badge%%) - How to put a Laconica badge on your blog or homepage
+ * [Source](%%doc.source%%) - How to get the StatusNet source code
+ * [Badge](%%doc.badge%%) - How to put a StatusNet badge on your blog or homepage
* [Bookmarklet](%%doc.bookmarklet%%) - Bookmarklet for posting Web pages
// site location
"\$config['site']['server'] = '$server';\n".
"\$config['site']['path'] = '$path'; \n\n".
-
+
// checks if fancy URLs are enabled
($fancy ? "\$config['site']['fancy'] = true;\n\n":'').
-
+
// database
"\$config['db']['database'] = '{$db['database']}';\n\n".
- ($db['type'] == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
+ ($type == 'pgsql' ? "\$config['db']['quote_identifiers'] = true;\n\n":'').
"\$config['db']['type'] = '{$db['type']}';\n\n".
-
+
"?>";
// write configuration file out to install directory
$res = file_put_contents(INSTALLDIR.'/config.php', $cfg);
?>
<?php echo"<?"; ?> xml version="1.0" encoding="UTF-8" <?php echo "?>"; ?>
-<!DOCTYPE html>
+<!DOCTYPE html
+PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
<head>
- <title>Install Laconica</title>
+ <title>Install StatusNet</title>
<link rel="shortcut icon" href="favicon.ico"/>
<link rel="stylesheet" type="text/css" href="theme/default/css/display.css?version=0.8" media="screen, projection, tv"/>
<!--[if IE]><link rel="stylesheet" type="text/css" href="theme/base/css/ie.css?version=0.8" /><![endif]-->
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- if (!defined('LACONICA')) { exit(1); }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
- define('LACONICA_VERSION', '0.9.0dev');
-define('STATUSNET_VERSION', '0.8.1');
++define('STATUSNET_VERSION', '0.9.0dev');
+ define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
- // XXX: move these to class variables
-define('STATUSNET_CODENAME', 'Second Guessing');
++define('STATUSNET_CODENAME', 'Stand');
define('AVATAR_PROFILE_SIZE', 96);
define('AVATAR_STREAM_SIZE', 48);
'ssl' => 'never',
'sslserver' => null,
'shorturllength' => 30,
- 'dupelimit' => 60), # default for same person saying the same thing
+ 'dupelimit' => 60, # default for same person saying the same thing
+ 'textlimit' => 140,
+ ),
'syslog' =>
- array('appname' => 'laconica', # for syslog
+ array('appname' => 'statusnet', # for syslog
'priority' => 'debug', # XXX: currently ignored
'facility' => LOG_USER),
'queue' =>
$_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1);
- if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
- $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini';
+ if ($_db_name != 'statusnet' && !array_key_exists('ini_'.$_db_name, $config['db'])) {
+ $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/statusnet.ini';
}
-// Ignore openidonly if OpenID is disabled
-
-if (!$config['openid']['enabled']) {
- $config['site']['openidonly'] = false;
+function __autoload($cls)
+{
+ if (file_exists(INSTALLDIR.'/classes/' . $cls . '.php')) {
+ require_once(INSTALLDIR.'/classes/' . $cls . '.php');
+ } else if (file_exists(INSTALLDIR.'/lib/' . strtolower($cls) . '.php')) {
+ require_once(INSTALLDIR.'/lib/' . strtolower($cls) . '.php');
+ } else if (mb_substr($cls, -6) == 'Action' &&
+ file_exists(INSTALLDIR.'/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php')) {
+ require_once(INSTALLDIR.'/actions/' . strtolower(mb_substr($cls, 0, -6)) . '.php');
+ } else if ($cls == 'OAuthRequest') {
+ require_once('OAuth.php');
+ } else {
+ Event::handle('Autoload', array(&$cls));
+ }
}
// XXX: how many of these could be auto-loaded on use?
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once(INSTALLDIR.'/lib/omb.php');
+require_once 'libomb/datastore.php';
- class LaconicaDataStore extends OMB_Datastore
+ class StatusNetOAuthDataStore extends OAuthDataStore
{
// We keep a record of who's contacted us
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- if (!defined('LACONICA')) {
- exit(1);
- }
+ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
-require_once('OAuth.php');
-require_once(INSTALLDIR.'/lib/oauthstore.php');
-
-require_once(INSTALLDIR.'/classes/Consumer.php');
-require_once(INSTALLDIR.'/classes/Nonce.php');
-require_once(INSTALLDIR.'/classes/Token.php');
-
-require_once('Auth/Yadis/Yadis.php');
-
-define('OAUTH_NAMESPACE', 'http://oauth.net/core/1.0/');
-define('OMB_NAMESPACE', 'http://openmicroblogging.org/protocol/0.1');
-define('OMB_VERSION_01', 'http://openmicroblogging.org/protocol/0.1');
-define('OAUTH_DISCOVERY', 'http://oauth.net/discovery/1.0');
-
-define('OMB_ENDPOINT_UPDATEPROFILE', OMB_NAMESPACE.'/updateProfile');
-define('OMB_ENDPOINT_POSTNOTICE', OMB_NAMESPACE.'/postNotice');
-define('OAUTH_ENDPOINT_REQUEST', OAUTH_NAMESPACE.'endpoint/request');
-define('OAUTH_ENDPOINT_AUTHORIZE', OAUTH_NAMESPACE.'endpoint/authorize');
-define('OAUTH_ENDPOINT_ACCESS', OAUTH_NAMESPACE.'endpoint/access');
-define('OAUTH_ENDPOINT_RESOURCE', OAUTH_NAMESPACE.'endpoint/resource');
-define('OAUTH_AUTH_HEADER', OAUTH_NAMESPACE.'parameters/auth-header');
-define('OAUTH_POST_BODY', OAUTH_NAMESPACE.'parameters/post-body');
-define('OAUTH_HMAC_SHA1', OAUTH_NAMESPACE.'signature/HMAC-SHA1');
+require_once INSTALLDIR.'/lib/oauthstore.php';
+require_once 'OAuth.php';
+require_once 'libomb/constants.php';
+require_once 'libomb/service_consumer.php';
+require_once 'libomb/notice.php';
+require_once 'libomb/profile.php';
+require_once 'Auth/Yadis/Yadis.php';
function omb_oauth_consumer()
{
function omb_oauth_datastore()
{
static $store = null;
- if (!$store) {
+ if (is_null($store)) {
- $store = new LaconicaDataStore();
+ $store = new StatusNetOAuthDataStore();
}
return $store;
}
return false;
}
- $con = omb_oauth_consumer();
+ $profile = $user->getProfile();
- $token = new OAuthToken($tk, $secret);
-
- $url = $postnoticeurl;
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
-
- $req = OAuthRequest::from_consumer_and_token($con, $token,
- 'POST', $url, $params);
-
- $req->set_parameter('omb_version', OMB_VERSION_01);
- $req->set_parameter('omb_listenee', $user->uri);
- $req->set_parameter('omb_notice', $notice->uri);
- $req->set_parameter('omb_notice_content', $notice->content);
- $req->set_parameter('omb_notice_url', common_local_url('shownotice',
- array('notice' =>
- $notice->id)));
- $req->set_parameter('omb_notice_license', common_config('license', 'url'));
+ $omb_profile = profile_to_omb_profile($user->uri, $profile, true);
- $user->free();
- unset($user);
+ /* Get remote users subscribed to this profile. */
+ $rp = new Remote_profile();
- $req->sign_request(omb_hmac_sha1(), $con, $token);
+ $rp->query('SELECT updateprofileurl, token, secret ' .
+ 'FROM subscription JOIN remote_profile ' .
+ 'ON subscription.subscriber = remote_profile.id ' .
+ 'WHERE subscription.subscribed = ' . $profile->id . ' ');
- # We re-use this tool's fetcher, since it's pretty good
+ $posted = array();
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+ while ($rp->fetch()) {
+ if (isset($posted[$rp->updateprofileurl])) {
+ /* We already posted to this url. */
+ continue;
+ }
+ common_debug('Posting to ' . $rp->updateprofileurl, __FILE__);
+
+ /* Update profile. */
- $service = new Laconica_OMB_Service_Consumer(
++ $service = new StatusNet_OMB_Service_Consumer(
+ array(OMB_ENDPOINT_UPDATEPROFILE => $rp->updateprofileurl));
+ try {
+ $service->setToken($rp->token, $rp->secret);
+ $service->updateProfile($omb_profile);
+ } catch (Exception $e) {
+ common_log(LOG_ERR, 'Failed posting to ' . $rp->updateprofileurl);
+ common_log(LOG_ERR, 'Error status '.$e);
+ continue;
+ }
+ $posted[$rp->updateprofileurl] = true;
- if (!$fetcher) {
- common_log(LOG_WARNING, 'Failed to initialize Yadis fetcher.', __FILE__);
- return false;
+ common_debug('Finished to ' . $rp->updateprofileurl, __FILE__);
}
- $result = $fetcher->post($req->get_normalized_http_url(),
- $req->to_postdata(),
- array('User-Agent: StatusNet/' . STATUSNET_VERSION));
-
- if ($result->status == 403) { # not authorized, don't send again
- common_debug('403 result, deleting subscription', __FILE__);
- # FIXME: figure out how to delete this
- # $subscription->delete();
- return false;
- } else if ($result->status != 200) {
- common_debug('Error status '.$result->status, __FILE__);
- return false;
- } else { # success!
- parse_str($result->body, $return);
- if ($return['omb_version'] == OMB_VERSION_01) {
- return true;
- } else {
- return false;
- }
- }
+ return;
}
- class Laconica_OMB_Service_Consumer extends OMB_Service_Consumer {
-function omb_broadcast_profile($profile)
-{
- # First, get remote users subscribed to this profile
- # XXX: use a join here rather than looping through results
- $sub = new Subscription();
- $sub->subscribed = $profile->id;
- if ($sub->find()) {
- $updated = array();
- while ($sub->fetch()) {
- $rp = Remote_profile::staticGet('id', $sub->subscriber);
- if ($rp) {
- if (!array_key_exists($rp->updateprofileurl, $updated)) {
- if (omb_update_profile($profile, $rp, $sub)) {
- $updated[$rp->updateprofileurl] = true;
- }
- }
- }
- }
++class StatusNet_OMB_Service_Consumer extends OMB_Service_Consumer {
+ public function __construct($urls)
+ {
+ $this->services = $urls;
+ $this->datastore = omb_oauth_datastore();
+ $this->oauth_consumer = omb_oauth_consumer();
+ $this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
}
+
}
-function omb_update_profile($profile, $remote_profile, $subscription)
+function profile_to_omb_profile($uri, $profile, $force = false)
{
- $user = User::staticGet($profile->id);
- $con = omb_oauth_consumer();
- $token = new OAuthToken($subscription->token, $subscription->secret);
- $url = $remote_profile->updateprofileurl;
- $parsed = parse_url($url);
- $params = array();
- parse_str($parsed['query'], $params);
- $req = OAuthRequest::from_consumer_and_token($con, $token,
- "POST", $url, $params);
- $req->set_parameter('omb_version', OMB_VERSION_01);
- $req->set_parameter('omb_listenee', $user->uri);
- $req->set_parameter('omb_listenee_profile', common_profile_url($profile->nickname));
- $req->set_parameter('omb_listenee_nickname', $profile->nickname);
-
- # We use blanks to force emptying any existing values in these optional fields
-
- $req->set_parameter('omb_listenee_fullname',
- ($profile->fullname) ? $profile->fullname : '');
- $req->set_parameter('omb_listenee_homepage',
- ($profile->homepage) ? $profile->homepage : '');
- $req->set_parameter('omb_listenee_bio',
- ($profile->bio) ? $profile->bio : '');
- $req->set_parameter('omb_listenee_location',
- ($profile->location) ? $profile->location : '');
+ $omb_profile = new OMB_Profile($uri);
+ $omb_profile->setNickname($profile->nickname);
+ $omb_profile->setLicenseURL(common_config('license', 'url'));
+ if (!is_null($profile->fullname)) {
+ $omb_profile->setFullname($profile->fullname);
+ } elseif ($force) {
+ $omb_profile->setFullname('');
+ }
+ if (!is_null($profile->homepage)) {
+ $omb_profile->setHomepage($profile->homepage);
+ } elseif ($force) {
+ $omb_profile->setHomepage('');
+ }
+ if (!is_null($profile->bio)) {
+ $omb_profile->setBio($profile->bio);
+ } elseif ($force) {
+ $omb_profile->setBio('');
+ }
+ if (!is_null($profile->location)) {
+ $omb_profile->setLocation($profile->location);
+ } elseif ($force) {
+ $omb_profile->setLocation('');
+ }
+ if (!is_null($profile->profileurl)) {
+ $omb_profile->setProfileURL($profile->profileurl);
+ } elseif ($force) {
+ $omb_profile->setProfileURL('');
+ }
$avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
- $req->set_parameter('omb_listenee_avatar',
- ($avatar) ? $avatar->url : '');
+ if ($avatar) {
+ $omb_profile->setAvatarURL($avatar->url);
+ } elseif ($force) {
+ $omb_profile->setAvatarURL('');
+ }
+ return $omb_profile;
+}
- $req->sign_request(omb_hmac_sha1(), $con, $token);
+function notice_to_omb_notice($notice)
+{
+ /* Create an OMB_Notice for $notice. */
+ $user = User::staticGet('id', $notice->profile_id);
- # We re-use this tool's fetcher, since it's pretty good
+ if (!$user) {
+ return null;
+ }
- $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
+ $profile = $user->getProfile();
- $result = $fetcher->post($req->get_normalized_http_url(),
- $req->to_postdata(),
- array('User-Agent: StatusNet/' . STATUSNET_VERSION));
+ $omb_notice = new OMB_Notice(profile_to_omb_profile($user->uri, $profile),
+ $notice->uri,
+ $notice->content);
+ $omb_notice->setURL(common_local_url('shownotice', array('notice' =>
+ $notice->id)));
+ $omb_notice->setLicenseURL(common_config('license', 'url'));
- if (empty($result) || !$result) {
- common_debug("Unable to contact " . $req->get_normalized_http_url());
- } else if ($result->status == 403) { # not authorized, don't send again
- common_debug('403 result, deleting subscription', __FILE__);
- $subscription->delete();
- return false;
- } else if ($result->status != 200) {
- common_debug('Error status '.$result->status, __FILE__);
- return false;
- } else { # success!
- parse_str($result->body, $return);
- if (isset($return['omb_version']) && $return['omb_version'] === OMB_VERSION_01) {
- return true;
- } else {
- return false;
- }
- }
+ return $omb_notice;
}
+?>
--- /dev/null
- * Laconica, the distributed open-source microblogging tool
+<?php
+/**
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
++ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Complete adding an OpenID
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Settings
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- if (!defined('LACONICA')) {
++ * @link http://status.net/
+ */
+
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
++if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+/**
+ * Complete adding an OpenID
+ *
+ * Handle the return from an OpenID verification
+ *
+ * @category Settings
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
++ * @link http://status.net/
+ */
+
+class FinishaddopenidAction extends Action
+{
+ var $msg = null;
+
+ /**
+ * Handle the redirect back from OpenID confirmation
+ *
+ * Check to see if the user's logged in, and then try
+ * to use the OpenID login system.
+ *
+ * @param array $args $_REQUEST arguments
+ *
+ * @return void
+ */
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if (!common_logged_in()) {
+ $this->clientError(_('Not logged in.'));
+ } else {
+ $this->tryLogin();
+ }
+ }
+
+ /**
+ * Try to log in using OpenID
+ *
+ * Check the OpenID for validity; potentially store it.
+ *
+ * @return void
+ */
+
+ function tryLogin()
+ {
+ $consumer =& oid_consumer();
+
+ $response = $consumer->complete(common_local_url('finishaddopenid'));
+
+ if ($response->status == Auth_OpenID_CANCEL) {
+ $this->message(_('OpenID authentication cancelled.'));
+ return;
+ } else if ($response->status == Auth_OpenID_FAILURE) {
+ // Authentication failed; display the error message.
+ $this->message(sprintf(_('OpenID authentication failed: %s'),
+ $response->message));
+ } else if ($response->status == Auth_OpenID_SUCCESS) {
+
+ $display = $response->getDisplayIdentifier();
+ $canonical = ($response->endpoint && $response->endpoint->canonicalID) ?
+ $response->endpoint->canonicalID : $display;
+
+ $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
+
+ if ($sreg_resp) {
+ $sreg = $sreg_resp->contents();
+ }
+
+ $cur =& common_current_user();
+
+ $other = oid_get_user($canonical);
+
+ if ($other) {
+ if ($other->id == $cur->id) {
+ $this->message(_('You already have this OpenID!'));
+ } else {
+ $this->message(_('Someone else already has this OpenID.'));
+ }
+ return;
+ }
+
+ // start a transaction
+
+ $cur->query('BEGIN');
+
+ $result = oid_link_user($cur->id, $canonical, $display);
+
+ if (!$result) {
+ $this->message(_('Error connecting user.'));
+ return;
+ }
+ if ($sreg) {
+ if (!oid_update_user($cur, $sreg)) {
+ $this->message(_('Error updating profile'));
+ return;
+ }
+ }
+
+ // success!
+
+ $cur->query('COMMIT');
+
+ oid_set_last($display);
+
+ common_redirect(common_local_url('openidsettings'), 303);
+ }
+ }
+
+ /**
+ * Show a failure message
+ *
+ * Something went wrong. Save the message, and show the page.
+ *
+ * @param string $msg Error message to show
+ *
+ * @return void
+ */
+
+ function message($msg)
+ {
+ $this->message = $msg;
+ $this->showPage();
+ }
+
+ /**
+ * Title of the page
+ *
+ * @return string title
+ */
+
+ function title()
+ {
+ return _('OpenID Login');
+ }
+
+ /**
+ * Show error message
+ *
+ * @return void
+ */
+
+ function showPageNotice()
+ {
+ if ($this->message) {
+ $this->element('p', 'error', $this->message);
+ }
+ }
+}
--- /dev/null
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+<?php
+/*
- if (!defined('LACONICA')) { exit(1); }
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
- # We try to use an OpenID URL as a legal Laconica user name in this order
++if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+class FinishopenidloginAction extends Action
+{
+ var $error = null;
+ var $username = null;
+ var $message = null;
+
+ function handle($args)
+ {
+ parent::handle($args);
+ if (common_is_real_login()) {
+ $this->clientError(_('Already logged in.'));
+ } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ $this->showForm(_('There was a problem with your session token. Try again, please.'));
+ return;
+ }
+ if ($this->arg('create')) {
+ if (!$this->boolean('license')) {
+ $this->showForm(_('You can\'t register if you don\'t agree to the license.'),
+ $this->trimmed('newname'));
+ return;
+ }
+ $this->createNewUser();
+ } else if ($this->arg('connect')) {
+ $this->connectUser();
+ } else {
+ common_debug(print_r($this->args, true), __FILE__);
+ $this->showForm(_('Something weird happened.'),
+ $this->trimmed('newname'));
+ }
+ } else {
+ $this->tryLogin();
+ }
+ }
+
+ function showPageNotice()
+ {
+ if ($this->error) {
+ $this->element('div', array('class' => 'error'), $this->error);
+ } else {
+ $this->element('div', 'instructions',
+ sprintf(_('This is the first time you\'ve logged into %s so we must connect your OpenID to a local account. You can either create a new account, or connect with your existing account, if you have one.'), common_config('site', 'name')));
+ }
+ }
+
+ function title()
+ {
+ return _('OpenID Account Setup');
+ }
+
+ function showForm($error=null, $username=null)
+ {
+ $this->error = $error;
+ $this->username = $username;
+
+ $this->showPage();
+ }
+
+ function showContent()
+ {
+ if (!empty($this->message_text)) {
+ $this->element('div', array('class' => 'error'), $this->message_text);
+ return;
+ }
+
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'account_connect',
+ 'action' => common_local_url('finishopenidlogin')));
+ $this->hidden('token', common_session_token());
+ $this->element('h2', null,
+ _('Create new account'));
+ $this->element('p', null,
+ _('Create a new user with this nickname.'));
+ $this->input('newname', _('New nickname'),
+ ($this->username) ? $this->username : '',
+ _('1-64 lowercase letters or numbers, no punctuation or spaces'));
+ $this->elementStart('p');
+ $this->element('input', array('type' => 'checkbox',
+ 'id' => 'license',
+ 'name' => 'license',
+ 'value' => 'true'));
+ $this->text(_('My text and files are available under '));
+ $this->element('a', array('href' => common_config('license', 'url')),
+ common_config('license', 'title'));
+ $this->text(_(' except this private data: password, email address, IM address, phone number.'));
+ $this->elementEnd('p');
+ $this->submit('create', _('Create'));
+ $this->element('h2', null,
+ _('Connect existing account'));
+ $this->element('p', null,
+ _('If you already have an account, login with your username and password to connect it to your OpenID.'));
+ $this->input('nickname', _('Existing nickname'));
+ $this->password('password', _('Password'));
+ $this->submit('connect', _('Connect'));
+ $this->elementEnd('form');
+ }
+
+ function tryLogin()
+ {
+ $consumer = oid_consumer();
+
+ $response = $consumer->complete(common_local_url('finishopenidlogin'));
+
+ if ($response->status == Auth_OpenID_CANCEL) {
+ $this->message(_('OpenID authentication cancelled.'));
+ return;
+ } else if ($response->status == Auth_OpenID_FAILURE) {
+ // Authentication failed; display the error message.
+ $this->message(sprintf(_('OpenID authentication failed: %s'), $response->message));
+ } else if ($response->status == Auth_OpenID_SUCCESS) {
+ // This means the authentication succeeded; extract the
+ // identity URL and Simple Registration data (if it was
+ // returned).
+ $display = $response->getDisplayIdentifier();
+ $canonical = ($response->endpoint->canonicalID) ?
+ $response->endpoint->canonicalID : $response->getDisplayIdentifier();
+
+ $sreg_resp = Auth_OpenID_SRegResponse::fromSuccessResponse($response);
+
+ if ($sreg_resp) {
+ $sreg = $sreg_resp->contents();
+ }
+
+ $user = oid_get_user($canonical);
+
+ if ($user) {
+ oid_set_last($display);
+ # XXX: commented out at @edd's request until better
+ # control over how data flows from OpenID provider.
+ # oid_update_user($user, $sreg);
+ common_set_user($user);
+ common_real_login(true);
+ if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
+ common_rememberme($user);
+ }
+ unset($_SESSION['openid_rememberme']);
+ $this->goHome($user->nickname);
+ } else {
+ $this->saveValues($display, $canonical, $sreg);
+ $this->showForm(null, $this->bestNewNickname($display, $sreg));
+ }
+ }
+ }
+
+ function message($msg)
+ {
+ $this->message_text = $msg;
+ $this->showPage();
+ }
+
+ function saveValues($display, $canonical, $sreg)
+ {
+ common_ensure_session();
+ $_SESSION['openid_display'] = $display;
+ $_SESSION['openid_canonical'] = $canonical;
+ $_SESSION['openid_sreg'] = $sreg;
+ }
+
+ function getSavedValues()
+ {
+ return array($_SESSION['openid_display'],
+ $_SESSION['openid_canonical'],
+ $_SESSION['openid_sreg']);
+ }
+
+ function createNewUser()
+ {
+ # FIXME: save invite code before redirect, and check here
+
+ if (common_config('site', 'closed')) {
+ $this->clientError(_('Registration not allowed.'));
+ return;
+ }
+
+ $invite = null;
+
+ if (common_config('site', 'inviteonly')) {
+ $code = $_SESSION['invitecode'];
+ if (empty($code)) {
+ $this->clientError(_('Registration not allowed.'));
+ return;
+ }
+
+ $invite = Invitation::staticGet($code);
+
+ if (empty($invite)) {
+ $this->clientError(_('Not a valid invitation code.'));
+ return;
+ }
+ }
+
+ $nickname = $this->trimmed('newname');
+
+ if (!Validate::string($nickname, array('min_length' => 1,
+ 'max_length' => 64,
+ 'format' => NICKNAME_FMT))) {
+ $this->showForm(_('Nickname must have only lowercase letters and numbers and no spaces.'));
+ return;
+ }
+
+ if (!User::allowed_nickname($nickname)) {
+ $this->showForm(_('Nickname not allowed.'));
+ return;
+ }
+
+ if (User::staticGet('nickname', $nickname)) {
+ $this->showForm(_('Nickname already in use. Try another one.'));
+ return;
+ }
+
+ list($display, $canonical, $sreg) = $this->getSavedValues();
+
+ if (!$display || !$canonical) {
+ $this->serverError(_('Stored OpenID not found.'));
+ return;
+ }
+
+ # Possible race condition... let's be paranoid
+
+ $other = oid_get_user($canonical);
+
+ if ($other) {
+ $this->serverError(_('Creating new account for OpenID that already has a user.'));
+ return;
+ }
+
+ $location = '';
+ if (!empty($sreg['country'])) {
+ if ($sreg['postcode']) {
+ # XXX: use postcode to get city and region
+ # XXX: also, store postcode somewhere -- it's valuable!
+ $location = $sreg['postcode'] . ', ' . $sreg['country'];
+ } else {
+ $location = $sreg['country'];
+ }
+ }
+
+ if (!empty($sreg['fullname']) && mb_strlen($sreg['fullname']) <= 255) {
+ $fullname = $sreg['fullname'];
+ } else {
+ $fullname = '';
+ }
+
+ if (!empty($sreg['email']) && Validate::email($sreg['email'], true)) {
+ $email = $sreg['email'];
+ } else {
+ $email = '';
+ }
+
+ # XXX: add language
+ # XXX: add timezone
+
+ $args = array('nickname' => $nickname,
+ 'email' => $email,
+ 'fullname' => $fullname,
+ 'location' => $location);
+
+ if (!empty($invite)) {
+ $args['code'] = $invite->code;
+ }
+
+ $user = User::register($args);
+
+ $result = oid_link_user($user->id, $canonical, $display);
+
+ oid_set_last($display);
+ common_set_user($user);
+ common_real_login(true);
+ if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
+ common_rememberme($user);
+ }
+ unset($_SESSION['openid_rememberme']);
+ common_redirect(common_local_url('showstream', array('nickname' => $user->nickname)),
+ 303);
+ }
+
+ function connectUser()
+ {
+ $nickname = $this->trimmed('nickname');
+ $password = $this->trimmed('password');
+
+ if (!common_check_user($nickname, $password)) {
+ $this->showForm(_('Invalid username or password.'));
+ return;
+ }
+
+ # They're legit!
+
+ $user = User::staticGet('nickname', $nickname);
+
+ list($display, $canonical, $sreg) = $this->getSavedValues();
+
+ if (!$display || !$canonical) {
+ $this->serverError(_('Stored OpenID not found.'));
+ return;
+ }
+
+ $result = oid_link_user($user->id, $canonical, $display);
+
+ if (!$result) {
+ $this->serverError(_('Error connecting user to OpenID.'));
+ return;
+ }
+
+ oid_update_user($user, $sreg);
+ oid_set_last($display);
+ common_set_user($user);
+ common_real_login(true);
+ if (isset($_SESSION['openid_rememberme']) && $_SESSION['openid_rememberme']) {
+ common_rememberme($user);
+ }
+ unset($_SESSION['openid_rememberme']);
+ $this->goHome($user->nickname);
+ }
+
+ function goHome($nickname)
+ {
+ $url = common_get_returnto();
+ if ($url) {
+ # We don't have to return to it again
+ common_set_returnto(null);
+ } else {
+ $url = common_local_url('all',
+ array('nickname' =>
+ $nickname));
+ }
+ common_redirect($url, 303);
+ }
+
+ function bestNewNickname($display, $sreg)
+ {
+
+ # Try the passed-in nickname
+
+ if (!empty($sreg['nickname'])) {
+ $nickname = $this->nicknamize($sreg['nickname']);
+ if ($this->isNewNickname($nickname)) {
+ return $nickname;
+ }
+ }
+
+ # Try the full name
+
+ if (!empty($sreg['fullname'])) {
+ $fullname = $this->nicknamize($sreg['fullname']);
+ if ($this->isNewNickname($fullname)) {
+ return $fullname;
+ }
+ }
+
+ # Try the URL
+
+ $from_url = $this->openidToNickname($display);
+
+ if ($from_url && $this->isNewNickname($from_url)) {
+ return $from_url;
+ }
+
+ # XXX: others?
+
+ return null;
+ }
+
+ function isNewNickname($str)
+ {
+ if (!Validate::string($str, array('min_length' => 1,
+ 'max_length' => 64,
+ 'format' => NICKNAME_FMT))) {
+ return false;
+ }
+ if (!User::allowed_nickname($str)) {
+ return false;
+ }
+ if (User::staticGet('nickname', $str)) {
+ return false;
+ }
+ return true;
+ }
+
+ function openidToNickname($openid)
+ {
+ if (Auth_Yadis_identifierScheme($openid) == 'XRI') {
+ return $this->xriToNickname($openid);
+ } else {
+ return $this->urlToNickname($openid);
+ }
+ }
+
++ # We try to use an OpenID URL as a legal StatusNet user name in this order
+ # 1. Plain hostname, like http://evanp.myopenid.com/
+ # 2. One element in path, like http://profile.typekey.com/EvanProdromou/
+ # or http://getopenid.com/evanprodromou
+
+ function urlToNickname($openid)
+ {
+ static $bad = array('query', 'user', 'password', 'port', 'fragment');
+
+ $parts = parse_url($openid);
+
+ # If any of these parts exist, this won't work
+
+ foreach ($bad as $badpart) {
+ if (array_key_exists($badpart, $parts)) {
+ return null;
+ }
+ }
+
+ # We just have host and/or path
+
+ # If it's just a host...
+ if (array_key_exists('host', $parts) &&
+ (!array_key_exists('path', $parts) || strcmp($parts['path'], '/') == 0))
+ {
+ $hostparts = explode('.', $parts['host']);
+
+ # Try to catch common idiom of nickname.service.tld
+
+ if ((count($hostparts) > 2) &&
+ (strlen($hostparts[count($hostparts) - 2]) > 3) && # try to skip .co.uk, .com.au
+ (strcmp($hostparts[0], 'www') != 0))
+ {
+ return $this->nicknamize($hostparts[0]);
+ } else {
+ # Do the whole hostname
+ return $this->nicknamize($parts['host']);
+ }
+ } else {
+ if (array_key_exists('path', $parts)) {
+ # Strip starting, ending slashes
+ $path = preg_replace('@/$@', '', $parts['path']);
+ $path = preg_replace('@^/@', '', $path);
+ if (strpos($path, '/') === false) {
+ return $this->nicknamize($path);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ function xriToNickname($xri)
+ {
+ $base = $this->xriBase($xri);
+
+ if (!$base) {
+ return null;
+ } else {
+ # =evan.prodromou
+ # or @gratis*evan.prodromou
+ $parts = explode('*', substr($base, 1));
+ return $this->nicknamize(array_pop($parts));
+ }
+ }
+
+ function xriBase($xri)
+ {
+ if (substr($xri, 0, 6) == 'xri://') {
+ return substr($xri, 6);
+ } else {
+ return $xri;
+ }
+ }
+
+ # Given a string, try to make it work as a nickname
+
+ function nicknamize($str)
+ {
+ $str = preg_replace('/\W/', '', $str);
+ return strtolower($str);
+ }
+}
--- /dev/null
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+<?php
+/*
- if (!defined('LACONICA')) { exit(1); }
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once(INSTALLDIR.'/plugins/OpenID/User_openid.php');
+
+require_once('Auth/OpenID.php');
+require_once('Auth/OpenID/Consumer.php');
+require_once('Auth/OpenID/SReg.php');
+require_once('Auth/OpenID/MySQLStore.php');
+
+# About one year cookie expiry
+
+define('OPENID_COOKIE_EXPIRY', round(365.25 * 24 * 60 * 60));
+define('OPENID_COOKIE_KEY', 'lastusedopenid');
+
+function oid_store()
+{
+ static $store = null;
+ if (!$store) {
+ # Can't be called statically
+ $user = new User();
+ $conn = $user->getDatabaseConnection();
+ $store = new Auth_OpenID_MySQLStore($conn);
+ }
+ return $store;
+}
+
+function oid_consumer()
+{
+ $store = oid_store();
+ $consumer = new Auth_OpenID_Consumer($store);
+ return $consumer;
+}
+
+function oid_clear_last()
+{
+ oid_set_last('');
+}
+
+function oid_set_last($openid_url)
+{
+ common_set_cookie(OPENID_COOKIE_KEY,
+ $openid_url,
+ time() + OPENID_COOKIE_EXPIRY);
+}
+
+function oid_get_last()
+{
+ if (empty($_COOKIE[OPENID_COOKIE_KEY])) {
+ return null;
+ }
+ $openid_url = $_COOKIE[OPENID_COOKIE_KEY];
+ if ($openid_url && strlen($openid_url) > 0) {
+ return $openid_url;
+ } else {
+ return null;
+ }
+}
+
+function oid_link_user($id, $canonical, $display)
+{
+
+ $oid = new User_openid();
+ $oid->user_id = $id;
+ $oid->canonical = $canonical;
+ $oid->display = $display;
+ $oid->created = DB_DataObject_Cast::dateTime();
+
+ if (!$oid->insert()) {
+ $err = PEAR::getStaticProperty('DB_DataObject','lastError');
+ common_debug('DB error ' . $err->code . ': ' . $err->message, __FILE__);
+ return false;
+ }
+
+ return true;
+}
+
+function oid_get_user($openid_url)
+{
+ $user = null;
+ $oid = User_openid::staticGet('canonical', $openid_url);
+ if ($oid) {
+ $user = User::staticGet('id', $oid->user_id);
+ }
+ return $user;
+}
+
+function oid_check_immediate($openid_url, $backto=null)
+{
+ if (!$backto) {
+ $action = $_REQUEST['action'];
+ $args = common_copy_args($_GET);
+ unset($args['action']);
+ $backto = common_local_url($action, $args);
+ }
+ common_debug('going back to "' . $backto . '"', __FILE__);
+
+ common_ensure_session();
+
+ $_SESSION['openid_immediate_backto'] = $backto;
+ common_debug('passed-in variable is "' . $backto . '"', __FILE__);
+ common_debug('session variable is "' . $_SESSION['openid_immediate_backto'] . '"', __FILE__);
+
+ oid_authenticate($openid_url,
+ 'finishimmediate',
+ true);
+}
+
+function oid_authenticate($openid_url, $returnto, $immediate=false)
+{
+
+ $consumer = oid_consumer();
+
+ if (!$consumer) {
+ common_server_error(_('Cannot instantiate OpenID consumer object.'));
+ return false;
+ }
+
+ common_ensure_session();
+
+ $auth_request = $consumer->begin($openid_url);
+
+ // Handle failure status return values.
+ if (!$auth_request) {
+ return _('Not a valid OpenID.');
+ } else if (Auth_OpenID::isFailure($auth_request)) {
+ return sprintf(_('OpenID failure: %s'), $auth_request->message);
+ }
+
+ $sreg_request = Auth_OpenID_SRegRequest::build(// Required
+ array(),
+ // Optional
+ array('nickname',
+ 'email',
+ 'fullname',
+ 'language',
+ 'timezone',
+ 'postcode',
+ 'country'));
+
+ if ($sreg_request) {
+ $auth_request->addExtension($sreg_request);
+ }
+
+ $trust_root = common_root_url(true);
+ $process_url = common_local_url($returnto);
+
+ if ($auth_request->shouldSendRedirect()) {
+ $redirect_url = $auth_request->redirectURL($trust_root,
+ $process_url,
+ $immediate);
+ if (!$redirect_url) {
+ } else if (Auth_OpenID::isFailure($redirect_url)) {
+ return sprintf(_('Could not redirect to server: %s'), $redirect_url->message);
+ } else {
+ common_redirect($redirect_url, 303);
+ }
+ } else {
+ // Generate form markup and render it.
+ $form_id = 'openid_message';
+ $form_html = $auth_request->formMarkup($trust_root, $process_url,
+ $immediate, array('id' => $form_id));
+
+ # XXX: This is cheap, but things choke if we don't escape ampersands
+ # in the HTML attributes
+
+ $form_html = preg_replace('/&/', '&', $form_html);
+
+ // Display an error if the form markup couldn't be generated;
+ // otherwise, render the HTML.
+ if (Auth_OpenID::isFailure($form_html)) {
+ common_server_error(sprintf(_('Could not create OpenID form: %s'), $form_html->message));
+ } else {
+ $action = new AutosubmitAction(); // see below
+ $action->form_html = $form_html;
+ $action->form_id = $form_id;
+ $action->prepare(array('action' => 'autosubmit'));
+ $action->handle(array('action' => 'autosubmit'));
+ }
+ }
+}
+
+# Half-assed attempt at a module-private function
+
+function _oid_print_instructions()
+{
+ common_element('div', 'instructions',
+ _('This form should automatically submit itself. '.
+ 'If not, click the submit button to go to your '.
+ 'OpenID provider.'));
+}
+
+# update a user from sreg parameters
+
+function oid_update_user(&$user, &$sreg)
+{
+
+ $profile = $user->getProfile();
+
+ $orig_profile = clone($profile);
+
+ if ($sreg['fullname'] && strlen($sreg['fullname']) <= 255) {
+ $profile->fullname = $sreg['fullname'];
+ }
+
+ if ($sreg['country']) {
+ if ($sreg['postcode']) {
+ # XXX: use postcode to get city and region
+ # XXX: also, store postcode somewhere -- it's valuable!
+ $profile->location = $sreg['postcode'] . ', ' . $sreg['country'];
+ } else {
+ $profile->location = $sreg['country'];
+ }
+ }
+
+ # XXX save language if it's passed
+ # XXX save timezone if it's passed
+
+ if (!$profile->update($orig_profile)) {
+ common_server_error(_('Error saving the profile.'));
+ return false;
+ }
+
+ $orig_user = clone($user);
+
+ if ($sreg['email'] && Validate::email($sreg['email'], true)) {
+ $user->email = $sreg['email'];
+ }
+
+ if (!$user->update($orig_user)) {
+ common_server_error(_('Error saving the user.'));
+ return false;
+ }
+
+ return true;
+}
+
+class AutosubmitAction extends Action
+{
+ var $form_html = null;
+ var $form_id = null;
+
+ function handle($args)
+ {
+ parent::handle($args);
+ $this->showPage();
+ }
+
+ function title()
+ {
+ return _('OpenID Auto-Submit');
+ }
+
+ function showContent()
+ {
+ $this->raw($this->form_html);
+ $this->element('script', null,
+ '$(document).ready(function() { ' .
+ ' $(\'#'. $this->form_id .'\').submit(); '.
+ '});');
+ }
+}
--- /dev/null
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
+<?php
+/*
- if (!defined('LACONICA')) { exit(1); }
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+class OpenidloginAction extends Action
+{
+ function handle($args)
+ {
+ parent::handle($args);
+ if (common_is_real_login()) {
+ $this->clientError(_('Already logged in.'));
+ } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $openid_url = $this->trimmed('openid_url');
+
+ # 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.'), $openid_url);
+ return;
+ }
+
+ $rememberme = $this->boolean('rememberme');
+
+ common_ensure_session();
+
+ $_SESSION['openid_rememberme'] = $rememberme;
+
+ $result = oid_authenticate($openid_url,
+ 'finishopenidlogin');
+
+ if (is_string($result)) { # error message
+ unset($_SESSION['openid_rememberme']);
+ $this->showForm($result, $openid_url);
+ }
+ } else {
+ $openid_url = oid_get_last();
+ $this->showForm(null, $openid_url);
+ }
+ }
+
+ function getInstructions()
+ {
+ if (common_logged_in() && !common_is_real_login() &&
+ common_get_returnto()) {
+ // rememberme logins have to reauthenticate before
+ // changing any profile settings (cookie-stealing protection)
+ return _('For security reasons, please re-login with your ' .
+ '[OpenID](%%doc.openid%%) ' .
+ 'before changing your settings.');
+ } else {
+ return _('Login with an [OpenID](%%doc.openid%%) account.');
+ }
+ }
+
+ function showPageNotice()
+ {
+ if ($this->error) {
+ $this->element('div', array('class' => 'error'), $this->error);
+ } else {
+ $instr = $this->getInstructions();
+ $output = common_markup_to_html($instr);
+ $this->elementStart('div', 'instructions');
+ $this->raw($output);
+ $this->elementEnd('div');
+ }
+ }
+
+ function title()
+ {
+ return _('OpenID Login');
+ }
+
+ function showForm($error=null, $openid_url)
+ {
+ $this->error = $error;
+ $this->openid_url = $openid_url;
+ $this->showPage();
+ }
+
+ function showContent() {
+ $formaction = common_local_url('openidlogin');
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_openid_login',
+ 'class' => 'form_settings',
+ 'action' => $formaction));
+ $this->elementStart('fieldset');
+ $this->element('legend', null, _('OpenID login'));
+ $this->hidden('token', common_session_token());
+
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->input('openid_url', _('OpenID URL'),
+ $this->openid_url,
+ _('Your OpenID URL'));
+ $this->elementEnd('li');
+ $this->elementStart('li', array('id' => 'settings_rememberme'));
+ $this->checkbox('rememberme', _('Remember me'), false,
+ _('Automatically login in the future; ' .
+ 'not for shared computers!'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->submit('submit', _('Login'));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ }
+
+ function showLocalNav()
+ {
+ $nav = new LoginGroupNav($this);
+ $nav->show();
+ }
+}
--- /dev/null
- * Laconica, the distributed open-source microblogging tool
+<?php
+/**
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @copyright 2008-2009 Control Yourself, Inc.
++ * StatusNet, the distributed open-source microblogging tool
+ *
+ * Settings for OpenID
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category Settings
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @copyright 2008-2009 StatusNet, Inc.
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- if (!defined('LACONICA')) {
++ * @link http://status.net/
+ */
+
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
++if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/lib/accountsettingsaction.php';
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+/**
+ * Settings for OpenID
+ *
+ * Lets users add, edit and delete OpenIDs from their account
+ *
+ * @category Settings
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
++ * @link http://status.net/
+ */
+
+class OpenidsettingsAction extends AccountSettingsAction
+{
+ /**
+ * Title of the page
+ *
+ * @return string Page title
+ */
+
+ function title()
+ {
+ return _('OpenID settings');
+ }
+
+ /**
+ * Instructions for use
+ *
+ * @return string Instructions for use
+ */
+
+ function getInstructions()
+ {
+ return _('[OpenID](%%doc.openid%%) lets you log into many sites' .
+ ' with the same user account.'.
+ ' Manage your associated OpenIDs from here.');
+ }
+
+ /**
+ * Show the form for OpenID management
+ *
+ * We have one form with a few different submit buttons to do different things.
+ *
+ * @return void
+ */
+
+ function showContent()
+ {
+ $user = common_current_user();
+
+ $this->elementStart('form', array('method' => 'post',
+ 'id' => 'form_settings_openid_add',
+ 'class' => 'form_settings',
+ 'action' =>
+ common_local_url('openidsettings')));
+ $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
+ $this->element('legend', null, _('Add OpenID'));
+ $this->hidden('token', common_session_token());
+ $this->element('p', 'form_guide',
+ _('If you want to add an OpenID to your account, ' .
+ 'enter it in the box below and click "Add".'));
+ $this->elementStart('ul', 'form_data');
+ $this->elementStart('li');
+ $this->element('label', array('for' => 'openid_url'),
+ _('OpenID URL'));
+ $this->element('input', array('name' => 'openid_url',
+ 'type' => 'text',
+ 'id' => 'openid_url'));
+ $this->elementEnd('li');
+ $this->elementEnd('ul');
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'settings_openid_add_action-submit',
+ 'name' => 'add',
+ 'class' => 'submit',
+ 'value' => _('Add')));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+
+ $oid = new User_openid();
+
+ $oid->user_id = $user->id;
+
+ $cnt = $oid->find();
+
+ if ($cnt > 0) {
+
+ $this->element('h2', null, _('Remove OpenID'));
+
+ if ($cnt == 1 && !$user->password) {
+
+ $this->element('p', 'form_guide',
+ _('Removing your only OpenID '.
+ 'would make it impossible to log in! ' .
+ 'If you need to remove it, '.
+ 'add another OpenID first.'));
+
+ if ($oid->fetch()) {
+ $this->elementStart('p');
+ $this->element('a', array('href' => $oid->canonical),
+ $oid->display);
+ $this->elementEnd('p');
+ }
+
+ } else {
+
+ $this->element('p', 'form_guide',
+ _('You can remove an OpenID from your account '.
+ 'by clicking the button marked "Remove".'));
+ $idx = 0;
+
+ while ($oid->fetch()) {
+ $this->elementStart('form',
+ array('method' => 'POST',
+ 'id' => 'form_settings_openid_delete' . $idx,
+ 'class' => 'form_settings',
+ 'action' =>
+ common_local_url('openidsettings')));
+ $this->elementStart('fieldset');
+ $this->hidden('token', common_session_token());
+ $this->element('a', array('href' => $oid->canonical),
+ $oid->display);
+ $this->element('input', array('type' => 'hidden',
+ 'id' => 'openid_url'.$idx,
+ 'name' => 'openid_url',
+ 'value' => $oid->canonical));
+ $this->element('input', array('type' => 'submit',
+ 'id' => 'remove'.$idx,
+ 'name' => 'remove',
+ 'class' => 'submit remove',
+ 'value' => _('Remove')));
+ $this->elementEnd('fieldset');
+ $this->elementEnd('form');
+ $idx++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Handle a POST request
+ *
+ * Muxes to different sub-functions based on which button was pushed
+ *
+ * @return void
+ */
+
+ function handlePost()
+ {
+ // CSRF protection
+ $token = $this->trimmed('token');
+ if (!$token || $token != common_session_token()) {
+ $this->showForm(_('There was a problem with your session token. '.
+ 'Try again, please.'));
+ return;
+ }
+
+ if ($this->arg('add')) {
+ $result = oid_authenticate($this->trimmed('openid_url'),
+ 'finishaddopenid');
+ if (is_string($result)) { // error message
+ $this->showForm($result);
+ }
+ } else if ($this->arg('remove')) {
+ $this->removeOpenid();
+ } else {
+ $this->showForm(_('Something weird happened.'));
+ }
+ }
+
+ /**
+ * Handles a request to remove an OpenID from the user's account
+ *
+ * Validates input and, if everything is OK, deletes the OpenID.
+ * Reloads the form with a success or error notification.
+ *
+ * @return void
+ */
+
+ function removeOpenid()
+ {
+ $openid_url = $this->trimmed('openid_url');
+
+ $oid = User_openid::staticGet('canonical', $openid_url);
+
+ if (!$oid) {
+ $this->showForm(_('No such OpenID.'));
+ return;
+ }
+ $cur = common_current_user();
+ if (!$cur || $oid->user_id != $cur->id) {
+ $this->showForm(_('That OpenID does not belong to you.'));
+ return;
+ }
+ $oid->delete();
+ $this->showForm(_('OpenID removed.'), true);
+ return;
+ }
+}
--- /dev/null
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
+<?php
+
+/**
+ * Public XRDS for OpenID
+ *
+ * PHP version 5
+ *
+ * @category Action
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
- * Laconica - a distributed open-source microblogging tool
- * Copyright (C) 2008, 2009, Control Yourself, Inc.
++ * @link http://status.net/
+ *
- if (!defined('LACONICA')) {
++ * StatusNet - the distributed open-source microblogging tool
++ * Copyright (C) 2008, 2009, StatusNet, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
- * @package Laconica
- * @author Evan Prodromou <evan@controlyourself.ca>
- * @author Robin Millette <millette@controlyourself.ca>
++if (!defined('STATUSNET') && !defined('LACONICA')) {
+ exit(1);
+}
+
+require_once INSTALLDIR.'/plugins/OpenID/openid.php';
+
+/**
+ * Public XRDS for OpenID
+ *
+ * @category Action
- * @link http://laconi.ca/
++ * @package StatusNet
++ * @author Evan Prodromou <evan@status.net>
++ * @author Robin Millette <millette@status.net>
+ * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
++ * @link http://status.net/
+ *
+ * @todo factor out similarities with XrdsAction
+ */
+class PublicxrdsAction extends Action
+{
+ /**
+ * Is read only?
+ *
+ * @return boolean true
+ */
+ function isReadOnly($args)
+ {
+ return true;
+ }
+
+ /**
+ * Class handler.
+ *
+ * @param array $args array of arguments
+ *
+ * @return nothing
+ */
+ function handle($args)
+ {
+ parent::handle($args);
+ header('Content-Type: application/xrds+xml');
+ $this->startXML();
+ $this->elementStart('XRDS', array('xmlns' => 'xri://$xrds'));
+ $this->elementStart('XRD', array('xmlns' => 'xri://$xrd*($v*2.0)',
+ 'xmlns:simple' => 'http://xrds-simple.net/core/1.0',
+ 'version' => '2.0'));
+ $this->element('Type', null, 'xri://$xrds*simple');
+ foreach (array('finishopenidlogin', 'finishaddopenid') as $finish) {
+ $this->showService(Auth_OpenID_RP_RETURN_TO_URL_TYPE,
+ common_local_url($finish));
+ }
+ $this->elementEnd('XRD');
+ $this->elementEnd('XRDS');
+ $this->endXML();
+ }
+
+ /**
+ * Show service.
+ *
+ * @param string $type XRDS type
+ * @param string $uri URI
+ * @param array $params type parameters, null by default
+ * @param array $sigs type signatures, null by default
+ * @param string $localId local ID, null by default
+ *
+ * @return void
+ */
+ function showService($type, $uri, $params=null, $sigs=null, $localId=null)
+ {
+ $this->elementStart('Service');
+ if ($uri) {
+ $this->element('URI', null, $uri);
+ }
+ $this->element('Type', null, $type);
+ if ($params) {
+ foreach ($params as $param) {
+ $this->element('Type', null, $param);
+ }
+ }
+ if ($sigs) {
+ foreach ($sigs as $sig) {
+ $this->element('Type', null, $sig);
+ }
+ }
+ if ($localId) {
+ $this->element('LocalID', null, $localId);
+ }
+ $this->elementEnd('Service');
+ }
+}
+