forked from GNUsocial/gnu-social
Merge branch 'master' into 0.9.x
This commit is contained in:
commit
b09276635c
40
EVENTS.txt
40
EVENTS.txt
@ -1057,3 +1057,43 @@ StartCloseNoticeListItemElement: Before the closing </li> of a notice list eleme
|
|||||||
|
|
||||||
EndCloseNoticeListItemElement: After the closing </li> of a notice list element
|
EndCloseNoticeListItemElement: After the closing </li> of a notice list element
|
||||||
- $nli: The notice list item being shown
|
- $nli: The notice list item being shown
|
||||||
|
|
||||||
|
StartGroupEditFormData: Beginning the group edit form entries
|
||||||
|
- $form: The form widget being shown
|
||||||
|
|
||||||
|
EndGroupEditFormData: Ending the group edit form entries
|
||||||
|
- $form: The form widget being shown
|
||||||
|
|
||||||
|
StartGroupSave: After initializing but before saving a group
|
||||||
|
- &$group: group about to be saved
|
||||||
|
|
||||||
|
EndGroupSave: After saving a group, aliases, and first member
|
||||||
|
- $group: group that was saved
|
||||||
|
|
||||||
|
StartInterpretCommand: Before running a command
|
||||||
|
- $cmd: First word in the string, 'foo' in 'foo argument'
|
||||||
|
- $arg: Argument, if any, like 'argument' in 'foo argument'
|
||||||
|
- $user: User who issued the command
|
||||||
|
- &$result: Resulting command; you can set this!
|
||||||
|
|
||||||
|
EndInterpretCommand: Before running a command
|
||||||
|
- $cmd: First word in the string, 'foo' in 'foo argument'
|
||||||
|
- $arg: Argument, if any, like 'argument' in 'foo argument'
|
||||||
|
- $user: User who issued the command
|
||||||
|
- $result: Resulting command
|
||||||
|
|
||||||
|
StartGroupActionsList: Start the list of actions on a group profile page (after <ul>, before first <li>)
|
||||||
|
- $action: action being executed (for output and params)
|
||||||
|
- $group: group for the page
|
||||||
|
|
||||||
|
EndGroupActionsList: End the list of actions on a group profile page (before </ul>, after last </li>)
|
||||||
|
- $action: action being executed (for output and params)
|
||||||
|
- $group: group for the page
|
||||||
|
|
||||||
|
StartGroupProfileElements: Start showing stuff about the group on its profile page
|
||||||
|
- $action: action being executed (for output and params)
|
||||||
|
- $group: group for the page
|
||||||
|
|
||||||
|
EndGroupProfileElements: Start showing stuff about the group on its profile page
|
||||||
|
- $action: action being executed (for output and params)
|
||||||
|
- $group: group for the page
|
||||||
|
19
README
19
README
@ -1279,7 +1279,7 @@ biolimit: max character length of bio; 0 means no limit; null means to use
|
|||||||
backup: whether users can backup their own profiles. Defaults to true.
|
backup: whether users can backup their own profiles. Defaults to true.
|
||||||
restore: whether users can restore their profiles from backup files. Defaults
|
restore: whether users can restore their profiles from backup files. Defaults
|
||||||
to true.
|
to true.
|
||||||
delete: whether users can delete their own accounts. Defaults to true.
|
delete: whether users can delete their own accounts. Defaults to false.
|
||||||
move: whether users can move their accounts to another server. Defaults
|
move: whether users can move their accounts to another server. Defaults
|
||||||
to true.
|
to true.
|
||||||
|
|
||||||
@ -1572,6 +1572,23 @@ proxy_user: Username to use for authenticating to the HTTP proxy. Default null.
|
|||||||
proxy_password: Password to use for authenticating to the HTTP proxy. Default null.
|
proxy_password: Password to use for authenticating to the HTTP proxy. Default null.
|
||||||
proxy_auth_scheme: Scheme to use for authenticating to the HTTP proxy. Default null.
|
proxy_auth_scheme: Scheme to use for authenticating to the HTTP proxy. Default null.
|
||||||
|
|
||||||
|
plugins
|
||||||
|
-------
|
||||||
|
|
||||||
|
default: associative array mapping plugin name to array of arguments. To disable
|
||||||
|
a default plugin, unset its value in this array.
|
||||||
|
locale_path: path for finding plugin locale files. In the plugin's directory
|
||||||
|
by default.
|
||||||
|
server: Server to find static files for a plugin when the page is plain old HTTP.
|
||||||
|
Defaults to site/server (same as pages). Use this to move plugin CSS and
|
||||||
|
JS files to a CDN.
|
||||||
|
sslserver: Server to find static files for a plugin when the page is HTTPS. Defaults
|
||||||
|
to site/server (same as pages). Use this to move plugin CSS and JS files
|
||||||
|
to a CDN.
|
||||||
|
path: Path to the plugin files. defaults to site/path + '/plugins/'. Expects that
|
||||||
|
each plugin will have a subdirectory at plugins/NameOfPlugin. Change this
|
||||||
|
if you're using a CDN.
|
||||||
|
|
||||||
Plugins
|
Plugins
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
@ -177,6 +177,8 @@ class EditgroupAction extends GroupDesignAction
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Event::handle('StartGroupSaveForm', array($this))) {
|
||||||
|
|
||||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||||
$fullname = $this->trimmed('fullname');
|
$fullname = $this->trimmed('fullname');
|
||||||
$homepage = $this->trimmed('homepage');
|
$homepage = $this->trimmed('homepage');
|
||||||
@ -287,6 +289,9 @@ class EditgroupAction extends GroupDesignAction
|
|||||||
|
|
||||||
$this->group->query('COMMIT');
|
$this->group->query('COMMIT');
|
||||||
|
|
||||||
|
Event::handle('EndGroupSaveForm', array($this));
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->group->nickname != $orig->nickname) {
|
if ($this->group->nickname != $orig->nickname) {
|
||||||
common_redirect(common_local_url('editgroup',
|
common_redirect(common_local_url('editgroup',
|
||||||
array('nickname' => $nickname)),
|
array('nickname' => $nickname)),
|
||||||
|
@ -90,18 +90,9 @@ class InboxAction extends MailboxAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function getMessageList($message)
|
||||||
* Returns the profile we want to show with the message
|
|
||||||
*
|
|
||||||
* For inboxes, we show the sender; for outboxes, the recipient.
|
|
||||||
*
|
|
||||||
* @param Message $message The message to get the profile for
|
|
||||||
*
|
|
||||||
* @return Profile The profile that matches the message
|
|
||||||
*/
|
|
||||||
function getMessageProfile($message)
|
|
||||||
{
|
{
|
||||||
return $message->getFrom();
|
return new InboxMessageList($this, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,3 +106,24 @@ class InboxAction extends MailboxAction
|
|||||||
return _('This is your inbox, which lists your incoming private messages.');
|
return _('This is your inbox, which lists your incoming private messages.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class InboxMessageList extends MessageList
|
||||||
|
{
|
||||||
|
function newItem($message)
|
||||||
|
{
|
||||||
|
return new InboxMessageListItem($this->out, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InboxMessageListItem extends MessageListItem
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the profile we want to show with the message
|
||||||
|
*
|
||||||
|
* @return Profile The profile that matches the message
|
||||||
|
*/
|
||||||
|
function getMessageProfile()
|
||||||
|
{
|
||||||
|
return $this->message->getFrom();
|
||||||
|
}
|
||||||
|
}
|
@ -120,6 +120,7 @@ class NewgroupAction extends Action
|
|||||||
|
|
||||||
function trySave()
|
function trySave()
|
||||||
{
|
{
|
||||||
|
if (Event::handle('StartGroupSaveForm', array($this))) {
|
||||||
try {
|
try {
|
||||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||||
} catch (NicknameException $e) {
|
} catch (NicknameException $e) {
|
||||||
@ -216,8 +217,13 @@ class NewgroupAction extends Action
|
|||||||
'userid' => $cur->id,
|
'userid' => $cur->id,
|
||||||
'local' => true));
|
'local' => true));
|
||||||
|
|
||||||
|
$this->group = $group;
|
||||||
|
|
||||||
|
Event::handle('EndGroupSaveForm', array($this));
|
||||||
|
|
||||||
common_redirect($group->homeUrl(), 303);
|
common_redirect($group->homeUrl(), 303);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function nicknameExists($nickname)
|
function nicknameExists($nickname)
|
||||||
{
|
{
|
||||||
|
@ -88,21 +88,9 @@ class OutboxAction extends MailboxAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function getMessageList($message)
|
||||||
* returns the profile we want to show with the message
|
|
||||||
*
|
|
||||||
* For outboxes, we show the recipient.
|
|
||||||
*
|
|
||||||
* @param Message $message The message to get the profile for
|
|
||||||
*
|
|
||||||
* @return Profile The profile of the message recipient
|
|
||||||
*
|
|
||||||
* @see MailboxAction::getMessageProfile()
|
|
||||||
*/
|
|
||||||
|
|
||||||
function getMessageProfile($message)
|
|
||||||
{
|
{
|
||||||
return $message->getTo();
|
return new OutboxMessageList($this, $message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -116,3 +104,24 @@ class OutboxAction extends MailboxAction
|
|||||||
return _('This is your outbox, which lists private messages you have sent.');
|
return _('This is your outbox, which lists private messages you have sent.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class OutboxMessageList extends MessageList
|
||||||
|
{
|
||||||
|
function newItem($message)
|
||||||
|
{
|
||||||
|
return new OutboxMessageListItem($this->out, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OutboxMessageListItem extends MessageListItem
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the profile we want to show with the message
|
||||||
|
*
|
||||||
|
* @return Profile The profile that matches the message
|
||||||
|
*/
|
||||||
|
function getMessageProfile()
|
||||||
|
{
|
||||||
|
return $this->message->getTo();
|
||||||
|
}
|
||||||
|
}
|
@ -181,6 +181,7 @@ class ShowgroupAction extends GroupDesignAction
|
|||||||
function showContent()
|
function showContent()
|
||||||
{
|
{
|
||||||
$this->showGroupProfile();
|
$this->showGroupProfile();
|
||||||
|
$this->showGroupActions();
|
||||||
$this->showGroupNotices();
|
$this->showGroupNotices();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,6 +217,8 @@ class ShowgroupAction extends GroupDesignAction
|
|||||||
$this->elementStart('div', array('id' => 'i',
|
$this->elementStart('div', array('id' => 'i',
|
||||||
'class' => 'entity_profile vcard author'));
|
'class' => 'entity_profile vcard author'));
|
||||||
|
|
||||||
|
if (Event::handle('StartGroupProfileElements', array($this, $this->group))) {
|
||||||
|
|
||||||
// TRANS: Group profile header (h2). Text hidden by default.
|
// TRANS: Group profile header (h2). Text hidden by default.
|
||||||
$this->element('h2', null, _('Group profile'));
|
$this->element('h2', null, _('Group profile'));
|
||||||
|
|
||||||
@ -296,13 +299,20 @@ class ShowgroupAction extends GroupDesignAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->elementEnd('div');
|
Event::handle('EndGroupProfileElements', array($this, $this->group));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showGroupActions()
|
||||||
|
{
|
||||||
$cur = common_current_user();
|
$cur = common_current_user();
|
||||||
$this->elementStart('div', 'entity_actions');
|
$this->elementStart('div', 'entity_actions');
|
||||||
// TRANS: Group actions header (h2). Text hidden by default.
|
// TRANS: Group actions header (h2). Text hidden by default.
|
||||||
$this->element('h2', null, _('Group actions'));
|
$this->element('h2', null, _('Group actions'));
|
||||||
$this->elementStart('ul');
|
$this->elementStart('ul');
|
||||||
|
if (Event::handle('StartGroupActionsList', array($this, $this->group))) {
|
||||||
$this->elementStart('li', 'entity_subscribe');
|
$this->elementStart('li', 'entity_subscribe');
|
||||||
if (Event::handle('StartGroupSubscribe', array($this, $this->group))) {
|
if (Event::handle('StartGroupSubscribe', array($this, $this->group))) {
|
||||||
if ($cur) {
|
if ($cur) {
|
||||||
@ -323,6 +333,8 @@ class ShowgroupAction extends GroupDesignAction
|
|||||||
$df->show();
|
$df->show();
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
}
|
}
|
||||||
|
Event::handle('EndGroupActionsList', array($this, $this->group));
|
||||||
|
}
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
@ -30,20 +30,17 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once INSTALLDIR.'/lib/mailbox.php';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a single message
|
* Show a single message
|
||||||
*
|
*
|
||||||
* // XXX: It is totally weird how this works!
|
|
||||||
*
|
|
||||||
* @category Personal
|
* @category Personal
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @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
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
class ShowmessageAction extends MailboxAction
|
|
||||||
|
class ShowmessageAction extends Action
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Message object to show
|
* Message object to show
|
||||||
@ -82,22 +79,20 @@ class ShowmessageAction extends MailboxAction
|
|||||||
|
|
||||||
$this->user = common_current_user();
|
$this->user = common_current_user();
|
||||||
|
|
||||||
|
if (empty($this->user) ||
|
||||||
|
($this->user->id != $this->message->from_profile &&
|
||||||
|
$this->user->id != $this->message->to_profile)) {
|
||||||
|
// TRANS: Client error displayed requesting a single direct message the requesting user was not a party in.
|
||||||
|
throw new ClientException(_('Only the sender and recipient ' .
|
||||||
|
'may read this message.'), 403);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
Action::handle($args);
|
|
||||||
|
|
||||||
if ($this->user && ($this->user->id == $this->message->from_profile ||
|
|
||||||
$this->user->id == $this->message->to_profile)) {
|
|
||||||
$this->showPage();
|
$this->showPage();
|
||||||
} else {
|
|
||||||
// TRANS: Client error displayed requesting a single direct message the requesting user was not a party in.
|
|
||||||
$this->clientError(_('Only the sender and recipient ' .
|
|
||||||
'may read this message.'), 403);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function title()
|
function title()
|
||||||
@ -121,12 +116,38 @@ class ShowmessageAction extends MailboxAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessages()
|
|
||||||
|
function showContent()
|
||||||
{
|
{
|
||||||
$message = new Message();
|
$this->elementStart('ul', 'notices messages');
|
||||||
$message->id = $this->message->id;
|
$ml = new ShowMessageListItem($this, $this->message, $this->user);
|
||||||
$message->find();
|
$ml->show();
|
||||||
return $message;
|
$this->elementEnd('ul');
|
||||||
|
}
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Don't show aside
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showAside() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ShowMessageListItem extends MessageListItem
|
||||||
|
{
|
||||||
|
var $user;
|
||||||
|
|
||||||
|
function __construct($out, $message, $user)
|
||||||
|
{
|
||||||
|
parent::__construct($out, $message);
|
||||||
|
$this->user = $user;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMessageProfile()
|
function getMessageProfile()
|
||||||
@ -140,46 +161,4 @@ class ShowmessageAction extends MailboxAction
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't show local navigation
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showLocalNavBlock()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't show page notice
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showPageNoticeBlock()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't show aside
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
function showAside()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Don't show any instructions
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function getInstructions()
|
|
||||||
{
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function isReadOnly($args)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -55,14 +55,20 @@ class File extends Memcached_DataObject
|
|||||||
return 'http://www.facebook.com/login.php' === $url;
|
return 'http://www.facebook.com/login.php' === $url;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAttachments($post_id) {
|
/**
|
||||||
$query = "select file.* from file join file_to_post on (file_id = file.id) join notice on (post_id = notice.id) where post_id = " . $this->escape($post_id);
|
* Get the attachments for a particlar notice.
|
||||||
$this->query($query);
|
*
|
||||||
|
* @param int $post_id
|
||||||
|
* @return array of File objects
|
||||||
|
*/
|
||||||
|
static function getAttachments($post_id) {
|
||||||
|
$file = new File();
|
||||||
|
$query = "select file.* from file join file_to_post on (file_id = file.id) where post_id = " . $file->escape($post_id);
|
||||||
|
$file = Memcached_DataObject::cachedQuery('File', $query);
|
||||||
$att = array();
|
$att = array();
|
||||||
while ($this->fetch()) {
|
while ($file->fetch()) {
|
||||||
$att[] = clone($this);
|
$att[] = clone($file);
|
||||||
}
|
}
|
||||||
$this->free();
|
|
||||||
return $att;
|
return $att;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,6 +340,7 @@ class Memcached_DataObject extends Safe_DataObject
|
|||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$result = null;
|
$result = null;
|
||||||
if (Event::handle('StartDBQuery', array($this, $string, &$result))) {
|
if (Event::handle('StartDBQuery', array($this, $string, &$result))) {
|
||||||
|
common_perf_counter('query', $string);
|
||||||
$result = parent::_query($string);
|
$result = parent::_query($string);
|
||||||
Event::handle('EndDBQuery', array($this, $string, &$result));
|
Event::handle('EndDBQuery', array($this, $string, &$result));
|
||||||
}
|
}
|
||||||
|
@ -446,7 +446,10 @@ class Notice extends Memcached_DataObject
|
|||||||
function blowOnInsert($conversation = false)
|
function blowOnInsert($conversation = false)
|
||||||
{
|
{
|
||||||
self::blow('profile:notice_ids:%d', $this->profile_id);
|
self::blow('profile:notice_ids:%d', $this->profile_id);
|
||||||
|
|
||||||
|
if ($this->isPublic()) {
|
||||||
self::blow('public');
|
self::blow('public');
|
||||||
|
}
|
||||||
|
|
||||||
// XXX: Before we were blowing the casche only if the notice id
|
// XXX: Before we were blowing the casche only if the notice id
|
||||||
// was not the root of the conversation. What to do now?
|
// was not the root of the conversation. What to do now?
|
||||||
@ -481,8 +484,11 @@ class Notice extends Memcached_DataObject
|
|||||||
$this->blowOnInsert();
|
$this->blowOnInsert();
|
||||||
|
|
||||||
self::blow('profile:notice_ids:%d;last', $this->profile_id);
|
self::blow('profile:notice_ids:%d;last', $this->profile_id);
|
||||||
|
|
||||||
|
if ($this->isPublic()) {
|
||||||
self::blow('public;last');
|
self::blow('public;last');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** save all urls in the notice to the db
|
/** save all urls in the notice to the db
|
||||||
*
|
*
|
||||||
@ -958,7 +964,7 @@ class Notice extends Memcached_DataObject
|
|||||||
$groups = array();
|
$groups = array();
|
||||||
|
|
||||||
/* extract all !group */
|
/* extract all !group */
|
||||||
$count = preg_match_all('/(?:^|\s)!([A-Za-z0-9]{1,64})/',
|
$count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
|
||||||
strtolower($this->content),
|
strtolower($this->content),
|
||||||
$match);
|
$match);
|
||||||
if (!$count) {
|
if (!$count) {
|
||||||
@ -2107,4 +2113,14 @@ class Notice extends Memcached_DataObject
|
|||||||
$obj->whereAdd($max);
|
$obj->whereAdd($max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPublic()
|
||||||
|
{
|
||||||
|
if (common_config('public', 'localonly')) {
|
||||||
|
return ($this->is_local == Notice::LOCAL_PUBLIC);
|
||||||
|
} else {
|
||||||
|
return (($this->is_local != Notice::LOCAL_NONPUBLIC) &&
|
||||||
|
($this->is_local != Notice::GATEWAY));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -918,6 +918,31 @@ class Profile extends Memcached_DataObject
|
|||||||
return $xs->getString();
|
return $xs->getString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra profile info for atom entries
|
||||||
|
*
|
||||||
|
* Clients use some extra profile info in the atom stream.
|
||||||
|
* This gives it to them.
|
||||||
|
*
|
||||||
|
* @param User $cur Current user
|
||||||
|
*
|
||||||
|
* @return array representation of <statusnet:profile_info> element
|
||||||
|
*/
|
||||||
|
|
||||||
|
function profileInfo($cur)
|
||||||
|
{
|
||||||
|
$profileInfoAttr = array();
|
||||||
|
|
||||||
|
if ($cur != null) {
|
||||||
|
// Whether the current user is a subscribed to this profile
|
||||||
|
$profileInfoAttr['following'] = $cur->isSubscribed($this) ? 'true' : 'false';
|
||||||
|
// Whether the current user is has blocked this profile
|
||||||
|
$profileInfoAttr['blocking'] = $cur->hasBlocked($this) ? 'true' : 'false';
|
||||||
|
}
|
||||||
|
|
||||||
|
return array('statusnet:profile_info', $profileInfoAttr, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an XML string fragment with profile information as an
|
* Returns an XML string fragment with profile information as an
|
||||||
* Activity Streams <activity:actor> element.
|
* Activity Streams <activity:actor> element.
|
||||||
|
@ -156,6 +156,13 @@ class Session extends Memcached_DataObject
|
|||||||
$session->selectAdd();
|
$session->selectAdd();
|
||||||
$session->selectAdd('id');
|
$session->selectAdd('id');
|
||||||
|
|
||||||
|
$limit = common_config('sessions', 'gc_limit');
|
||||||
|
if ($limit > 0) {
|
||||||
|
// On large sites, too many sessions to expire
|
||||||
|
// at once will just result in failure.
|
||||||
|
$session->limit($limit);
|
||||||
|
}
|
||||||
|
|
||||||
$session->find();
|
$session->find();
|
||||||
|
|
||||||
while ($session->fetch()) {
|
while ($session->fetch()) {
|
||||||
|
@ -512,6 +512,8 @@ class User_group extends Memcached_DataObject
|
|||||||
$group->mainpage = $mainpage;
|
$group->mainpage = $mainpage;
|
||||||
$group->created = common_sql_now();
|
$group->created = common_sql_now();
|
||||||
|
|
||||||
|
if (Event::handle('StartGroupSave', array(&$group))) {
|
||||||
|
|
||||||
$result = $group->insert();
|
$result = $group->insert();
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
@ -570,6 +572,10 @@ class User_group extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
$group->query('COMMIT');
|
$group->query('COMMIT');
|
||||||
|
|
||||||
|
Event::handle('EndGroupSave', array($group));
|
||||||
|
}
|
||||||
|
|
||||||
return $group;
|
return $group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
104
extlib/Auth/SASL.php
Normal file
104
extlib/Auth/SASL.php
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: SASL.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client implementation of various SASL mechanisms
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('PEAR.php');
|
||||||
|
|
||||||
|
class Auth_SASL
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Factory class. Returns an object of the request
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* @param string $type One of: Anonymous
|
||||||
|
* Plain
|
||||||
|
* CramMD5
|
||||||
|
* DigestMD5
|
||||||
|
* Types are not case sensitive
|
||||||
|
*/
|
||||||
|
function &factory($type)
|
||||||
|
{
|
||||||
|
switch (strtolower($type)) {
|
||||||
|
case 'anonymous':
|
||||||
|
$filename = 'Auth/SASL/Anonymous.php';
|
||||||
|
$classname = 'Auth_SASL_Anonymous';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'login':
|
||||||
|
$filename = 'Auth/SASL/Login.php';
|
||||||
|
$classname = 'Auth_SASL_Login';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'plain':
|
||||||
|
$filename = 'Auth/SASL/Plain.php';
|
||||||
|
$classname = 'Auth_SASL_Plain';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'external':
|
||||||
|
$filename = 'Auth/SASL/External.php';
|
||||||
|
$classname = 'Auth_SASL_External';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'crammd5':
|
||||||
|
$filename = 'Auth/SASL/CramMD5.php';
|
||||||
|
$classname = 'Auth_SASL_CramMD5';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'digestmd5':
|
||||||
|
$filename = 'Auth/SASL/DigestMD5.php';
|
||||||
|
$classname = 'Auth_SASL_DigestMD5';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return PEAR::raiseError('Invalid SASL mechanism type');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once($filename);
|
||||||
|
$obj = new $classname();
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
71
extlib/Auth/SASL/Anonymous.php
Normal file
71
extlib/Auth/SASL/Anonymous.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Anonymous.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implmentation of ANONYMOUS SASL mechanism
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('Auth/SASL/Common.php');
|
||||||
|
|
||||||
|
class Auth_SASL_Anonymous extends Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Not much to do here except return the token supplied.
|
||||||
|
* No encoding, hashing or encryption takes place for this
|
||||||
|
* mechanism, simply one of:
|
||||||
|
* o An email address
|
||||||
|
* o An opaque string not containing "@" that can be interpreted
|
||||||
|
* by the sysadmin
|
||||||
|
* o Nothing
|
||||||
|
*
|
||||||
|
* We could have some logic here for the second option, but this
|
||||||
|
* would by no means create something interpretable.
|
||||||
|
*
|
||||||
|
* @param string $token Optional email address or string to provide
|
||||||
|
* as trace information.
|
||||||
|
* @return string The unaltered input token
|
||||||
|
*/
|
||||||
|
function getResponse($token = '')
|
||||||
|
{
|
||||||
|
return $token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
74
extlib/Auth/SASL/Common.php
Normal file
74
extlib/Auth/SASL/Common.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Common.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common functionality to SASL mechanisms
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Function which implements HMAC MD5 digest
|
||||||
|
*
|
||||||
|
* @param string $key The secret key
|
||||||
|
* @param string $data The data to protect
|
||||||
|
* @return string The HMAC MD5 digest
|
||||||
|
*/
|
||||||
|
function _HMAC_MD5($key, $data)
|
||||||
|
{
|
||||||
|
if (strlen($key) > 64) {
|
||||||
|
$key = pack('H32', md5($key));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($key) < 64) {
|
||||||
|
$key = str_pad($key, 64, chr(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
$k_ipad = substr($key, 0, 64) ^ str_repeat(chr(0x36), 64);
|
||||||
|
$k_opad = substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64);
|
||||||
|
|
||||||
|
$inner = pack('H32', md5($k_ipad . $data));
|
||||||
|
$digest = md5($k_opad . $inner);
|
||||||
|
|
||||||
|
return $digest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
68
extlib/Auth/SASL/CramMD5.php
Normal file
68
extlib/Auth/SASL/CramMD5.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: CramMD5.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implmentation of CRAM-MD5 SASL mechanism
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('Auth/SASL/Common.php');
|
||||||
|
|
||||||
|
class Auth_SASL_CramMD5 extends Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Implements the CRAM-MD5 SASL mechanism
|
||||||
|
* This DOES NOT base64 encode the return value,
|
||||||
|
* you will need to do that yourself.
|
||||||
|
*
|
||||||
|
* @param string $user Username
|
||||||
|
* @param string $pass Password
|
||||||
|
* @param string $challenge The challenge supplied by the server.
|
||||||
|
* this should be already base64_decoded.
|
||||||
|
*
|
||||||
|
* @return string The string to pass back to the server, of the form
|
||||||
|
* "<user> <digest>". This is NOT base64_encoded.
|
||||||
|
*/
|
||||||
|
function getResponse($user, $pass, $challenge)
|
||||||
|
{
|
||||||
|
return $user . ' ' . $this->_HMAC_MD5($pass, $challenge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
197
extlib/Auth/SASL/DigestMD5.php
Normal file
197
extlib/Auth/SASL/DigestMD5.php
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: DigestMD5.php 294702 2010-02-07 16:03:55Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implmentation of DIGEST-MD5 SASL mechanism
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('Auth/SASL/Common.php');
|
||||||
|
|
||||||
|
class Auth_SASL_DigestMD5 extends Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Provides the (main) client response for DIGEST-MD5
|
||||||
|
* requires a few extra parameters than the other
|
||||||
|
* mechanisms, which are unavoidable.
|
||||||
|
*
|
||||||
|
* @param string $authcid Authentication id (username)
|
||||||
|
* @param string $pass Password
|
||||||
|
* @param string $challenge The digest challenge sent by the server
|
||||||
|
* @param string $hostname The hostname of the machine you're connecting to
|
||||||
|
* @param string $service The servicename (eg. imap, pop, acap etc)
|
||||||
|
* @param string $authzid Authorization id (username to proxy as)
|
||||||
|
* @return string The digest response (NOT base64 encoded)
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
function getResponse($authcid, $pass, $challenge, $hostname, $service, $authzid = '')
|
||||||
|
{
|
||||||
|
$challenge = $this->_parseChallenge($challenge);
|
||||||
|
$authzid_string = '';
|
||||||
|
if ($authzid != '') {
|
||||||
|
$authzid_string = ',authzid="' . $authzid . '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($challenge)) {
|
||||||
|
$cnonce = $this->_getCnonce();
|
||||||
|
$digest_uri = sprintf('%s/%s', $service, $hostname);
|
||||||
|
$response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid);
|
||||||
|
|
||||||
|
if ($challenge['realm']) {
|
||||||
|
return sprintf('username="%s",realm="%s"' . $authzid_string .
|
||||||
|
',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
|
||||||
|
} else {
|
||||||
|
return sprintf('username="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return PEAR::raiseError('Invalid digest challenge');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and verifies the digest challenge*
|
||||||
|
*
|
||||||
|
* @param string $challenge The digest challenge
|
||||||
|
* @return array The parsed challenge as an assoc
|
||||||
|
* array in the form "directive => value".
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _parseChallenge($challenge)
|
||||||
|
{
|
||||||
|
$tokens = array();
|
||||||
|
while (preg_match('/^([a-z-]+)=("[^"]+(?<!\\\)"|[^,]+)/i', $challenge, $matches)) {
|
||||||
|
|
||||||
|
// Ignore these as per rfc2831
|
||||||
|
if ($matches[1] == 'opaque' OR $matches[1] == 'domain') {
|
||||||
|
$challenge = substr($challenge, strlen($matches[0]) + 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allowed multiple "realm" and "auth-param"
|
||||||
|
if (!empty($tokens[$matches[1]]) AND ($matches[1] == 'realm' OR $matches[1] == 'auth-param')) {
|
||||||
|
if (is_array($tokens[$matches[1]])) {
|
||||||
|
$tokens[$matches[1]][] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
|
||||||
|
} else {
|
||||||
|
$tokens[$matches[1]] = array($tokens[$matches[1]], preg_replace('/^"(.*)"$/', '\\1', $matches[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any other multiple instance = failure
|
||||||
|
} elseif (!empty($tokens[$matches[1]])) {
|
||||||
|
$tokens = array();
|
||||||
|
break;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$tokens[$matches[1]] = preg_replace('/^"(.*)"$/', '\\1', $matches[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the just parsed directive from the challenge
|
||||||
|
$challenge = substr($challenge, strlen($matches[0]) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defaults and required directives
|
||||||
|
*/
|
||||||
|
// Realm
|
||||||
|
if (empty($tokens['realm'])) {
|
||||||
|
$tokens['realm'] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maxbuf
|
||||||
|
if (empty($tokens['maxbuf'])) {
|
||||||
|
$tokens['maxbuf'] = 65536;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required: nonce, algorithm
|
||||||
|
if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the response= part of the digest response
|
||||||
|
*
|
||||||
|
* @param string $authcid Authentication id (username)
|
||||||
|
* @param string $pass Password
|
||||||
|
* @param string $realm Realm as provided by the server
|
||||||
|
* @param string $nonce Nonce as provided by the server
|
||||||
|
* @param string $cnonce Client nonce
|
||||||
|
* @param string $digest_uri The digest-uri= value part of the response
|
||||||
|
* @param string $authzid Authorization id
|
||||||
|
* @return string The response= part of the digest response
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _getResponseValue($authcid, $pass, $realm, $nonce, $cnonce, $digest_uri, $authzid = '')
|
||||||
|
{
|
||||||
|
if ($authzid == '') {
|
||||||
|
$A1 = sprintf('%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce);
|
||||||
|
} else {
|
||||||
|
$A1 = sprintf('%s:%s:%s:%s', pack('H32', md5(sprintf('%s:%s:%s', $authcid, $realm, $pass))), $nonce, $cnonce, $authzid);
|
||||||
|
}
|
||||||
|
$A2 = 'AUTHENTICATE:' . $digest_uri;
|
||||||
|
return md5(sprintf('%s:%s:00000001:%s:auth:%s', md5($A1), $nonce, $cnonce, md5($A2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the client nonce for the response
|
||||||
|
*
|
||||||
|
* @return string The cnonce value
|
||||||
|
* @access private
|
||||||
|
*/
|
||||||
|
function _getCnonce()
|
||||||
|
{
|
||||||
|
if (@file_exists('/dev/urandom') && $fd = @fopen('/dev/urandom', 'r')) {
|
||||||
|
return base64_encode(fread($fd, 32));
|
||||||
|
|
||||||
|
} elseif (@file_exists('/dev/random') && $fd = @fopen('/dev/random', 'r')) {
|
||||||
|
return base64_encode(fread($fd, 32));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$str = '';
|
||||||
|
for ($i=0; $i<32; $i++) {
|
||||||
|
$str .= chr(mt_rand(0, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64_encode($str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
63
extlib/Auth/SASL/External.php
Normal file
63
extlib/Auth/SASL/External.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2008 Christoph Schulz |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Christoph Schulz <develop@kristov.de> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: External.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implmentation of EXTERNAL SASL mechanism
|
||||||
|
*
|
||||||
|
* @author Christoph Schulz <develop@kristov.de>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0.3
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('Auth/SASL/Common.php');
|
||||||
|
|
||||||
|
class Auth_SASL_External extends Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns EXTERNAL response
|
||||||
|
*
|
||||||
|
* @param string $authcid Authentication id (username)
|
||||||
|
* @param string $pass Password
|
||||||
|
* @param string $authzid Autorization id
|
||||||
|
* @return string EXTERNAL Response
|
||||||
|
*/
|
||||||
|
function getResponse($authcid, $pass, $authzid = '')
|
||||||
|
{
|
||||||
|
return $authzid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
65
extlib/Auth/SASL/Login.php
Normal file
65
extlib/Auth/SASL/Login.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Login.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is technically not a SASL mechanism, however
|
||||||
|
* it's used by Net_Sieve, Net_Cyrus and potentially
|
||||||
|
* other protocols , so here is a good place to abstract
|
||||||
|
* it.
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('Auth/SASL/Common.php');
|
||||||
|
|
||||||
|
class Auth_SASL_Login extends Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Pseudo SASL LOGIN mechanism
|
||||||
|
*
|
||||||
|
* @param string $user Username
|
||||||
|
* @param string $pass Password
|
||||||
|
* @return string LOGIN string
|
||||||
|
*/
|
||||||
|
function getResponse($user, $pass)
|
||||||
|
{
|
||||||
|
return sprintf('LOGIN %s %s', $user, $pass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
63
extlib/Auth/SASL/Plain.php
Normal file
63
extlib/Auth/SASL/Plain.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Copyright (c) 2002-2003 Richard Heyes |
|
||||||
|
// | All rights reserved. |
|
||||||
|
// | |
|
||||||
|
// | Redistribution and use in source and binary forms, with or without |
|
||||||
|
// | modification, are permitted provided that the following conditions |
|
||||||
|
// | are met: |
|
||||||
|
// | |
|
||||||
|
// | o Redistributions of source code must retain the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer. |
|
||||||
|
// | o Redistributions in binary form must reproduce the above copyright |
|
||||||
|
// | notice, this list of conditions and the following disclaimer in the |
|
||||||
|
// | documentation and/or other materials provided with the distribution.|
|
||||||
|
// | o The names of the authors may not be used to endorse or promote |
|
||||||
|
// | products derived from this software without specific prior written |
|
||||||
|
// | permission. |
|
||||||
|
// | |
|
||||||
|
// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
|
// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
|
// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
|
// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
|
// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
|
// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
|
// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
|
// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
|
// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
|
// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
||||||
|
// | |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
// | Author: Richard Heyes <richard@php.net> |
|
||||||
|
// +-----------------------------------------------------------------------+
|
||||||
|
//
|
||||||
|
// $Id: Plain.php 286825 2009-08-05 06:23:42Z cweiske $
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implmentation of PLAIN SASL mechanism
|
||||||
|
*
|
||||||
|
* @author Richard Heyes <richard@php.net>
|
||||||
|
* @access public
|
||||||
|
* @version 1.0
|
||||||
|
* @package Auth_SASL
|
||||||
|
*/
|
||||||
|
|
||||||
|
require_once('Auth/SASL/Common.php');
|
||||||
|
|
||||||
|
class Auth_SASL_Plain extends Auth_SASL_Common
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns PLAIN response
|
||||||
|
*
|
||||||
|
* @param string $authcid Authentication id (username)
|
||||||
|
* @param string $pass Password
|
||||||
|
* @param string $authzid Autorization id
|
||||||
|
* @return string PLAIN Response
|
||||||
|
*/
|
||||||
|
function getResponse($authcid, $pass, $authzid = '')
|
||||||
|
{
|
||||||
|
return $authzid . chr(0) . $authcid . chr(0) . $pass;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
@ -38,6 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$_startTime = microtime(true);
|
$_startTime = microtime(true);
|
||||||
|
$_perfCounters = array();
|
||||||
|
|
||||||
define('INSTALLDIR', dirname(__FILE__));
|
define('INSTALLDIR', dirname(__FILE__));
|
||||||
define('STATUSNET', true);
|
define('STATUSNET', true);
|
||||||
@ -45,6 +46,8 @@ define('LACONICA', true); // compatibility
|
|||||||
|
|
||||||
require_once INSTALLDIR . '/lib/common.php';
|
require_once INSTALLDIR . '/lib/common.php';
|
||||||
|
|
||||||
|
register_shutdown_function('common_log_perf_counters');
|
||||||
|
|
||||||
$user = null;
|
$user = null;
|
||||||
$action = null;
|
$action = null;
|
||||||
|
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
/*!
|
/*
|
||||||
* jQuery Form Plugin
|
* jQuery Form Plugin
|
||||||
* version: 2.63 (29-JAN-2011)
|
* version: 2.17 (06-NOV-2008)
|
||||||
* @requires jQuery v1.3.2 or later
|
* @requires jQuery v1.2.2 or later
|
||||||
*
|
*
|
||||||
* Examples and documentation at: http://malsup.com/jquery/form/
|
* Examples and documentation at: http://malsup.com/jquery/form/
|
||||||
* Dual licensed under the MIT and GPL licenses:
|
* Dual licensed under the MIT and GPL licenses:
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
* http://www.gnu.org/licenses/gpl.html
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*
|
||||||
|
* Revision: $Id$
|
||||||
*/
|
*/
|
||||||
;(function($) {
|
;(function($) {
|
||||||
|
|
||||||
@ -18,11 +20,11 @@
|
|||||||
to bind your own submit handler to the form. For example,
|
to bind your own submit handler to the form. For example,
|
||||||
|
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
$('#myForm').bind('submit', function(e) {
|
$('#myForm').bind('submit', function() {
|
||||||
e.preventDefault(); // <-- important
|
|
||||||
$(this).ajaxSubmit({
|
$(this).ajaxSubmit({
|
||||||
target: '#output'
|
target: '#output'
|
||||||
});
|
});
|
||||||
|
return false; // <-- important!
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -50,23 +52,13 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options == 'function') {
|
if (typeof options == 'function')
|
||||||
options = { success: options };
|
options = { success: options };
|
||||||
}
|
|
||||||
|
|
||||||
var action = this.attr('action');
|
options = $.extend({
|
||||||
var url = (typeof action === 'string') ? $.trim(action) : '';
|
url: this.attr('action') || window.location.toString(),
|
||||||
if (url) {
|
type: this.attr('method') || 'GET'
|
||||||
// clean url (don't include hash vaue)
|
}, options || {});
|
||||||
url = (url.match(/^([^#]+)/)||[])[1];
|
|
||||||
}
|
|
||||||
url = url || window.location.href || '';
|
|
||||||
|
|
||||||
options = $.extend(true, {
|
|
||||||
url: url,
|
|
||||||
type: this[0].getAttribute('method') || 'GET', // IE7 massage (see issue 57)
|
|
||||||
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank'
|
|
||||||
}, options);
|
|
||||||
|
|
||||||
// hook for manipulating the form data before it is extracted;
|
// hook for manipulating the form data before it is extracted;
|
||||||
// convenient for use with rich editors like tinyMCE or FCKEditor
|
// convenient for use with rich editors like tinyMCE or FCKEditor
|
||||||
@ -83,20 +75,16 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
var n,v,a = this.formToArray(options.semantic);
|
var a = this.formToArray(options.semantic);
|
||||||
if (options.data) {
|
if (options.data) {
|
||||||
options.extraData = options.data;
|
options.extraData = options.data;
|
||||||
for (n in options.data) {
|
for (var n in options.data) {
|
||||||
if(options.data[n] instanceof Array) {
|
if(options.data[n] instanceof Array) {
|
||||||
for (var k in options.data[n]) {
|
for (var k in options.data[n])
|
||||||
a.push( { name: n, value: options.data[n][k] } );
|
a.push( { name: n, value: options.data[n][k] } )
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
v = options.data[n];
|
|
||||||
v = $.isFunction(v) ? v() : v; // if value is fn, invoke it
|
|
||||||
a.push( { name: n, value: v } );
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
a.push( { name: n, value: options.data[n] } );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,57 +107,46 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
options.url += (options.url.indexOf('?') >= 0 ? '&' : '?') + q;
|
||||||
options.data = null; // data is null for 'get'
|
options.data = null; // data is null for 'get'
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
options.data = q; // data is the query string for 'post'
|
options.data = q; // data is the query string for 'post'
|
||||||
}
|
|
||||||
|
|
||||||
var $form = this, callbacks = [];
|
var $form = this, callbacks = [];
|
||||||
if (options.resetForm) {
|
if (options.resetForm) callbacks.push(function() { $form.resetForm(); });
|
||||||
callbacks.push(function() { $form.resetForm(); });
|
if (options.clearForm) callbacks.push(function() { $form.clearForm(); });
|
||||||
}
|
|
||||||
if (options.clearForm) {
|
|
||||||
callbacks.push(function() { $form.clearForm(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform a load on the target only if dataType is not provided
|
// perform a load on the target only if dataType is not provided
|
||||||
if (!options.dataType && options.target) {
|
if (!options.dataType && options.target) {
|
||||||
var oldSuccess = options.success || function(){};
|
var oldSuccess = options.success || function(){};
|
||||||
callbacks.push(function(data) {
|
callbacks.push(function(data) {
|
||||||
var fn = options.replaceTarget ? 'replaceWith' : 'html';
|
$(options.target).html(data).each(oldSuccess, arguments);
|
||||||
$(options.target)[fn](data).each(oldSuccess, arguments);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (options.success) {
|
else if (options.success)
|
||||||
callbacks.push(options.success);
|
callbacks.push(options.success);
|
||||||
}
|
|
||||||
|
|
||||||
options.success = function(data, status, xhr) { // jQuery 1.4+ passes xhr as 3rd arg
|
options.success = function(data, status) {
|
||||||
var context = options.context || options; // jQuery 1.4+ supports scope context
|
for (var i=0, max=callbacks.length; i < max; i++)
|
||||||
for (var i=0, max=callbacks.length; i < max; i++) {
|
callbacks[i].apply(options, [data, status, $form]);
|
||||||
callbacks[i].apply(context, [data, status, xhr || $form, $form]);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// are there files to upload?
|
// are there files to upload?
|
||||||
var fileInputs = $('input:file', this).length > 0;
|
var files = $('input:file', this).fieldValue();
|
||||||
var mp = 'multipart/form-data';
|
var found = false;
|
||||||
var multipart = ($form.attr('enctype') == mp || $form.attr('encoding') == mp);
|
for (var j=0; j < files.length; j++)
|
||||||
|
if (files[j])
|
||||||
|
found = true;
|
||||||
|
|
||||||
// options.iframe allows user to force iframe mode
|
// options.iframe allows user to force iframe mode
|
||||||
// 06-NOV-09: now defaulting to iframe mode if file input is detected
|
if (options.iframe || found) {
|
||||||
if (options.iframe !== false && (fileInputs || options.iframe || multipart)) {
|
|
||||||
// hack to fix Safari hang (thanks to Tim Molendijk for this)
|
// hack to fix Safari hang (thanks to Tim Molendijk for this)
|
||||||
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
|
// see: http://groups.google.com/group/jquery-dev/browse_thread/thread/36395b7ab510dd5d
|
||||||
if (options.closeKeepAlive) {
|
if ($.browser.safari && options.closeKeepAlive)
|
||||||
$.get(options.closeKeepAlive, fileUpload);
|
$.get(options.closeKeepAlive, fileUpload);
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
fileUpload();
|
fileUpload();
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else {
|
|
||||||
$.ajax(options);
|
$.ajax(options);
|
||||||
}
|
|
||||||
|
|
||||||
// fire 'notify' event
|
// fire 'notify' event
|
||||||
this.trigger('form-submit-notify', [this, options]);
|
this.trigger('form-submit-notify', [this, options]);
|
||||||
@ -180,19 +157,20 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
function fileUpload() {
|
function fileUpload() {
|
||||||
var form = $form[0];
|
var form = $form[0];
|
||||||
|
|
||||||
if ($(':input[name=submit],:input[id=submit]', form).length) {
|
if ($(':input[name=submit]', form).length) {
|
||||||
// if there is an input with a name or id of 'submit' then we won't be
|
alert('Error: Form elements must not be named "submit".');
|
||||||
// able to invoke the submit fn on the form (at least not x-browser)
|
|
||||||
alert('Error: Form elements must not have name or id of "submit".');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var s = $.extend(true, {}, $.ajaxSettings, options);
|
var opts = $.extend({}, $.ajaxSettings, options);
|
||||||
s.context = s.context || s;
|
var s = jQuery.extend(true, {}, $.extend(true, {}, $.ajaxSettings), opts);
|
||||||
var id = 'jqFormIO' + (new Date().getTime()), fn = '_'+id;
|
|
||||||
var $io = $('<iframe id="' + id + '" name="' + id + '" src="'+ s.iframeSrc +'" />');
|
var id = 'jqFormIO' + (new Date().getTime());
|
||||||
|
var $io = $('<iframe id="' + id + '" name="' + id + '" />');
|
||||||
var io = $io[0];
|
var io = $io[0];
|
||||||
|
|
||||||
|
if ($.browser.msie || $.browser.opera)
|
||||||
|
io.src = 'javascript:false;document.write("");';
|
||||||
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
$io.css({ position: 'absolute', top: '-1000px', left: '-1000px' });
|
||||||
|
|
||||||
var xhr = { // mock object
|
var xhr = { // mock object
|
||||||
@ -206,29 +184,23 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
setRequestHeader: function() {},
|
setRequestHeader: function() {},
|
||||||
abort: function() {
|
abort: function() {
|
||||||
this.aborted = 1;
|
this.aborted = 1;
|
||||||
$io.attr('src', s.iframeSrc); // abort op in progress
|
$io.attr('src','about:blank'); // abort op in progress
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var g = s.global;
|
var g = opts.global;
|
||||||
// trigger ajax global events so that activity/block indicators work like normal
|
// trigger ajax global events so that activity/block indicators work like normal
|
||||||
if (g && ! $.active++) {
|
if (g && ! $.active++) $.event.trigger("ajaxStart");
|
||||||
$.event.trigger("ajaxStart");
|
if (g) $.event.trigger("ajaxSend", [xhr, opts]);
|
||||||
}
|
|
||||||
if (g) {
|
|
||||||
$.event.trigger("ajaxSend", [xhr, s]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s.beforeSend && s.beforeSend.call(s.context, xhr, s) === false) {
|
if (s.beforeSend && s.beforeSend(xhr, s) === false) {
|
||||||
if (s.global) {
|
s.global && jQuery.active--;
|
||||||
$.active--;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (xhr.aborted) {
|
if (xhr.aborted)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
|
var cbInvoked = 0;
|
||||||
var timedOut = 0;
|
var timedOut = 0;
|
||||||
|
|
||||||
// add submitting element to data if we know it
|
// add submitting element to data if we know it
|
||||||
@ -236,31 +208,27 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
if (sub) {
|
if (sub) {
|
||||||
var n = sub.name;
|
var n = sub.name;
|
||||||
if (n && !sub.disabled) {
|
if (n && !sub.disabled) {
|
||||||
s.extraData = s.extraData || {};
|
options.extraData = options.extraData || {};
|
||||||
s.extraData[n] = sub.value;
|
options.extraData[n] = sub.value;
|
||||||
if (sub.type == "image") {
|
if (sub.type == "image") {
|
||||||
s.extraData[n+'.x'] = form.clk_x;
|
options.extraData[name+'.x'] = form.clk_x;
|
||||||
s.extraData[n+'.y'] = form.clk_y;
|
options.extraData[name+'.y'] = form.clk_y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// take a breath so that pending repaints get some cpu time before the upload starts
|
// take a breath so that pending repaints get some cpu time before the upload starts
|
||||||
function doSubmit() {
|
setTimeout(function() {
|
||||||
// make sure form attrs are set
|
// make sure form attrs are set
|
||||||
var t = $form.attr('target'), a = $form.attr('action');
|
var t = $form.attr('target'), a = $form.attr('action');
|
||||||
|
$form.attr({
|
||||||
// update form attrs in IE friendly way
|
target: id,
|
||||||
form.setAttribute('target',id);
|
method: 'POST',
|
||||||
if (form.getAttribute('method') != 'POST') {
|
action: opts.url
|
||||||
form.setAttribute('method', 'POST');
|
});
|
||||||
}
|
|
||||||
if (form.getAttribute('action') != s.url) {
|
|
||||||
form.setAttribute('action', s.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ie borks in some cases when setting encoding
|
// ie borks in some cases when setting encoding
|
||||||
if (! s.skipEncodingOverride) {
|
if (! options.skipEncodingOverride) {
|
||||||
$form.attr({
|
$form.attr({
|
||||||
encoding: 'multipart/form-data',
|
encoding: 'multipart/form-data',
|
||||||
enctype: 'multipart/form-data'
|
enctype: 'multipart/form-data'
|
||||||
@ -268,20 +236,17 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// support timout
|
// support timout
|
||||||
if (s.timeout) {
|
if (opts.timeout)
|
||||||
setTimeout(function() { timedOut = true; cb(); }, s.timeout);
|
setTimeout(function() { timedOut = true; cb(); }, opts.timeout);
|
||||||
}
|
|
||||||
|
|
||||||
// add "extra" data to form if provided in options
|
// add "extra" data to form if provided in options
|
||||||
var extraInputs = [];
|
var extraInputs = [];
|
||||||
try {
|
try {
|
||||||
if (s.extraData) {
|
if (options.extraData)
|
||||||
for (var n in s.extraData) {
|
for (var n in options.extraData)
|
||||||
extraInputs.push(
|
extraInputs.push(
|
||||||
$('<input type="hidden" name="'+n+'" value="'+s.extraData[n]+'" />')
|
$('<input type="hidden" name="'+n+'" value="'+options.extraData[n]+'" />')
|
||||||
.appendTo(form)[0]);
|
.appendTo(form)[0]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add iframe to doc and submit the form
|
// add iframe to doc and submit the form
|
||||||
$io.appendTo('body');
|
$io.appendTo('body');
|
||||||
@ -290,158 +255,83 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// reset attrs and remove "extra" input elements
|
// reset attrs and remove "extra" input elements
|
||||||
form.setAttribute('action',a);
|
$form.attr('action', a);
|
||||||
if(t) {
|
t ? $form.attr('target', t) : $form.removeAttr('target');
|
||||||
form.setAttribute('target', t);
|
|
||||||
} else {
|
|
||||||
$form.removeAttr('target');
|
|
||||||
}
|
|
||||||
$(extraInputs).remove();
|
$(extraInputs).remove();
|
||||||
}
|
}
|
||||||
}
|
}, 10);
|
||||||
|
|
||||||
if (s.forceSync) {
|
|
||||||
doSubmit();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setTimeout(doSubmit, 10); // this lets dom updates render
|
|
||||||
}
|
|
||||||
|
|
||||||
var data, doc, domCheckCount = 50;
|
|
||||||
|
|
||||||
function cb() {
|
function cb() {
|
||||||
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
|
if (cbInvoked++) return;
|
||||||
if (!doc || doc.location.href == s.iframeSrc) {
|
|
||||||
// response not received yet
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
|
io.detachEvent ? io.detachEvent('onload', cb) : io.removeEventListener('load', cb, false);
|
||||||
|
|
||||||
|
var operaHack = 0;
|
||||||
var ok = true;
|
var ok = true;
|
||||||
try {
|
try {
|
||||||
if (timedOut) {
|
if (timedOut) throw 'timeout';
|
||||||
throw 'timeout';
|
// extract the server response from the iframe
|
||||||
}
|
var data, doc;
|
||||||
|
|
||||||
var isXml = s.dataType == 'xml' || doc.XMLDocument || $.isXMLDoc(doc);
|
doc = io.contentWindow ? io.contentWindow.document : io.contentDocument ? io.contentDocument : io.document;
|
||||||
log('isXml='+isXml);
|
|
||||||
if (!isXml && window.opera && (doc.body == null || doc.body.innerHTML == '')) {
|
if (doc.body == null && !operaHack && $.browser.opera) {
|
||||||
if (--domCheckCount) {
|
// In Opera 9.2.x the iframe DOM is not always traversable when
|
||||||
// in some browsers (Opera) the iframe DOM is not always traversable when
|
// the onload callback fires so we give Opera 100ms to right itself
|
||||||
// the onload callback fires, so we loop a bit to accommodate
|
operaHack = 1;
|
||||||
log('requeing onLoad callback, DOM not available');
|
cbInvoked--;
|
||||||
setTimeout(cb, 250);
|
setTimeout(cb, 100);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// let this fall through because server response could be an empty document
|
|
||||||
//log('Could not access iframe DOM after mutiple tries.');
|
|
||||||
//throw 'DOMException: not available';
|
|
||||||
}
|
|
||||||
|
|
||||||
//log('response detected');
|
xhr.responseText = doc.body ? doc.body.innerHTML : null;
|
||||||
xhr.responseText = doc.body ? doc.body.innerHTML : doc.documentElement ? doc.documentElement.innerHTML : null;
|
|
||||||
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
xhr.responseXML = doc.XMLDocument ? doc.XMLDocument : doc;
|
||||||
xhr.getResponseHeader = function(header){
|
xhr.getResponseHeader = function(header){
|
||||||
var headers = {'content-type': s.dataType};
|
var headers = {'content-type': opts.dataType};
|
||||||
return headers[header];
|
return headers[header];
|
||||||
};
|
};
|
||||||
|
|
||||||
var scr = /(json|script)/.test(s.dataType);
|
if (opts.dataType == 'json' || opts.dataType == 'script') {
|
||||||
if (scr || s.textarea) {
|
|
||||||
// see if user embedded response in textarea
|
|
||||||
var ta = doc.getElementsByTagName('textarea')[0];
|
var ta = doc.getElementsByTagName('textarea')[0];
|
||||||
if (ta) {
|
xhr.responseText = ta ? ta.value : xhr.responseText;
|
||||||
xhr.responseText = ta.value;
|
|
||||||
}
|
}
|
||||||
else if (scr) {
|
else if (opts.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
|
||||||
// account for browsers injecting pre around json response
|
|
||||||
var pre = doc.getElementsByTagName('pre')[0];
|
|
||||||
var b = doc.getElementsByTagName('body')[0];
|
|
||||||
if (pre) {
|
|
||||||
xhr.responseText = pre.textContent;
|
|
||||||
}
|
|
||||||
else if (b) {
|
|
||||||
xhr.responseText = b.innerHTML;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (s.dataType == 'xml' && !xhr.responseXML && xhr.responseText != null) {
|
|
||||||
xhr.responseXML = toXml(xhr.responseText);
|
xhr.responseXML = toXml(xhr.responseText);
|
||||||
}
|
}
|
||||||
|
data = $.httpData(xhr, opts.dataType);
|
||||||
data = httpData(xhr, s.dataType, s);
|
|
||||||
}
|
}
|
||||||
catch(e){
|
catch(e){
|
||||||
log('error caught:',e);
|
|
||||||
ok = false;
|
|
||||||
xhr.error = e;
|
|
||||||
s.error.call(s.context, xhr, 'error', e);
|
|
||||||
g && $.event.trigger("ajaxError", [xhr, s, e]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xhr.aborted) {
|
|
||||||
log('upload aborted');
|
|
||||||
ok = false;
|
ok = false;
|
||||||
|
$.handleError(opts, xhr, 'error', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
// ordering of these callbacks/triggers is odd, but that's how $.ajax does it
|
||||||
if (ok) {
|
if (ok) {
|
||||||
s.success.call(s.context, data, 'success', xhr);
|
opts.success(data, 'success');
|
||||||
g && $.event.trigger("ajaxSuccess", [xhr, s]);
|
if (g) $.event.trigger("ajaxSuccess", [xhr, opts]);
|
||||||
}
|
}
|
||||||
|
if (g) $.event.trigger("ajaxComplete", [xhr, opts]);
|
||||||
g && $.event.trigger("ajaxComplete", [xhr, s]);
|
if (g && ! --$.active) $.event.trigger("ajaxStop");
|
||||||
|
if (opts.complete) opts.complete(xhr, ok ? 'success' : 'error');
|
||||||
if (g && ! --$.active) {
|
|
||||||
$.event.trigger("ajaxStop");
|
|
||||||
}
|
|
||||||
|
|
||||||
s.complete && s.complete.call(s.context, xhr, ok ? 'success' : 'error');
|
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
$io.removeData('form-plugin-onload');
|
|
||||||
$io.remove();
|
$io.remove();
|
||||||
xhr.responseXML = null;
|
xhr.responseXML = null;
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
};
|
||||||
|
|
||||||
var toXml = $.parseXML || function(s, doc) { // use parseXML if available (jQuery 1.5+)
|
function toXml(s, doc) {
|
||||||
if (window.ActiveXObject) {
|
if (window.ActiveXObject) {
|
||||||
doc = new ActiveXObject('Microsoft.XMLDOM');
|
doc = new ActiveXObject('Microsoft.XMLDOM');
|
||||||
doc.async = 'false';
|
doc.async = 'false';
|
||||||
doc.loadXML(s);
|
doc.loadXML(s);
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
doc = (new DOMParser()).parseFromString(s, 'text/xml');
|
||||||
}
|
return (doc && doc.documentElement && doc.documentElement.tagName != 'parsererror') ? doc : null;
|
||||||
return (doc && doc.documentElement && doc.documentElement.nodeName != 'parsererror') ? doc : null;
|
|
||||||
};
|
};
|
||||||
var parseJSON = $.parseJSON || function(s) {
|
|
||||||
return window['eval']('(' + s + ')');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var httpData = function( xhr, type, s ) { // mostly lifted from jq1.4.4
|
|
||||||
var ct = xhr.getResponseHeader('content-type') || '',
|
|
||||||
xml = type === 'xml' || !type && ct.indexOf('xml') >= 0,
|
|
||||||
data = xml ? xhr.responseXML : xhr.responseText;
|
|
||||||
|
|
||||||
if (xml && data.documentElement.nodeName === 'parsererror') {
|
|
||||||
$.error && $.error('parsererror');
|
|
||||||
}
|
|
||||||
if (s && s.dataFilter) {
|
|
||||||
data = s.dataFilter(data, type);
|
|
||||||
}
|
|
||||||
if (typeof data === 'string') {
|
|
||||||
if (type === 'json' || !type && ct.indexOf('json') >= 0) {
|
|
||||||
data = parseJSON(data);
|
|
||||||
} else if (type === "script" || !type && ct.indexOf("javascript") >= 0) {
|
|
||||||
$.globalEval(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -460,60 +350,40 @@ $.fn.ajaxSubmit = function(options) {
|
|||||||
* the form itself.
|
* the form itself.
|
||||||
*/
|
*/
|
||||||
$.fn.ajaxForm = function(options) {
|
$.fn.ajaxForm = function(options) {
|
||||||
// in jQuery 1.3+ we can fix mistakes with the ready state
|
return this.ajaxFormUnbind().bind('submit.form-plugin',function() {
|
||||||
if (this.length === 0) {
|
|
||||||
var o = { s: this.selector, c: this.context };
|
|
||||||
if (!$.isReady && o.s) {
|
|
||||||
log('DOM not ready, queuing ajaxForm');
|
|
||||||
$(function() {
|
|
||||||
$(o.s,o.c).ajaxForm(options);
|
|
||||||
});
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
// is your DOM ready? http://docs.jquery.com/Tutorials:Introducing_$(document).ready()
|
|
||||||
log('terminating; zero elements found by selector' + ($.isReady ? '' : ' (DOM not ready)'));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.ajaxFormUnbind().bind('submit.form-plugin', function(e) {
|
|
||||||
if (!e.isDefaultPrevented()) { // if event has been canceled, don't proceed
|
|
||||||
e.preventDefault();
|
|
||||||
$(this).ajaxSubmit(options);
|
$(this).ajaxSubmit(options);
|
||||||
}
|
return false;
|
||||||
}).bind('click.form-plugin', function(e) {
|
}).each(function() {
|
||||||
var target = e.target;
|
// store options in hash
|
||||||
var $el = $(target);
|
$(":submit,input:image", this).bind('click.form-plugin',function(e) {
|
||||||
if (!($el.is(":submit,input:image"))) {
|
var form = this.form;
|
||||||
// is this a child element of the submit el? (ex: a span within a button)
|
form.clk = this;
|
||||||
var t = $el.closest(':submit');
|
if (this.type == 'image') {
|
||||||
if (t.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
target = t[0];
|
|
||||||
}
|
|
||||||
var form = this;
|
|
||||||
form.clk = target;
|
|
||||||
if (target.type == 'image') {
|
|
||||||
if (e.offsetX != undefined) {
|
if (e.offsetX != undefined) {
|
||||||
form.clk_x = e.offsetX;
|
form.clk_x = e.offsetX;
|
||||||
form.clk_y = e.offsetY;
|
form.clk_y = e.offsetY;
|
||||||
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
} else if (typeof $.fn.offset == 'function') { // try to use dimensions plugin
|
||||||
var offset = $el.offset();
|
var offset = $(this).offset();
|
||||||
form.clk_x = e.pageX - offset.left;
|
form.clk_x = e.pageX - offset.left;
|
||||||
form.clk_y = e.pageY - offset.top;
|
form.clk_y = e.pageY - offset.top;
|
||||||
} else {
|
} else {
|
||||||
form.clk_x = e.pageX - target.offsetLeft;
|
form.clk_x = e.pageX - this.offsetLeft;
|
||||||
form.clk_y = e.pageY - target.offsetTop;
|
form.clk_y = e.pageY - this.offsetTop;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// clear form vars
|
// clear form vars
|
||||||
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 100);
|
setTimeout(function() { form.clk = form.clk_x = form.clk_y = null; }, 10);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
// ajaxFormUnbind unbinds the event handlers that were bound by ajaxForm
|
||||||
$.fn.ajaxFormUnbind = function() {
|
$.fn.ajaxFormUnbind = function() {
|
||||||
return this.unbind('submit.form-plugin click.form-plugin');
|
this.unbind('submit.form-plugin');
|
||||||
|
return this.each(function() {
|
||||||
|
$(":submit,input:image", this).unbind('click.form-plugin');
|
||||||
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -529,50 +399,39 @@ $.fn.ajaxFormUnbind = function() {
|
|||||||
*/
|
*/
|
||||||
$.fn.formToArray = function(semantic) {
|
$.fn.formToArray = function(semantic) {
|
||||||
var a = [];
|
var a = [];
|
||||||
if (this.length === 0) {
|
if (this.length == 0) return a;
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
var form = this[0];
|
var form = this[0];
|
||||||
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
var els = semantic ? form.getElementsByTagName('*') : form.elements;
|
||||||
if (!els) {
|
if (!els) return a;
|
||||||
return a;
|
for(var i=0, max=els.length; i < max; i++) {
|
||||||
}
|
var el = els[i];
|
||||||
|
var n = el.name;
|
||||||
var i,j,n,v,el,max,jmax;
|
if (!n) continue;
|
||||||
for(i=0, max=els.length; i < max; i++) {
|
|
||||||
el = els[i];
|
|
||||||
n = el.name;
|
|
||||||
if (!n) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (semantic && form.clk && el.type == "image") {
|
if (semantic && form.clk && el.type == "image") {
|
||||||
// handle image inputs on the fly when semantic == true
|
// handle image inputs on the fly when semantic == true
|
||||||
if(!el.disabled && form.clk == el) {
|
if(!el.disabled && form.clk == el)
|
||||||
a.push({name: n, value: $(el).val()});
|
|
||||||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
v = $.fieldValue(el, true);
|
var v = $.fieldValue(el, true);
|
||||||
if (v && v.constructor == Array) {
|
if (v && v.constructor == Array) {
|
||||||
for(j=0, jmax=v.length; j < jmax; j++) {
|
for(var j=0, jmax=v.length; j < jmax; j++)
|
||||||
a.push({name: n, value: v[j]});
|
a.push({name: n, value: v[j]});
|
||||||
}
|
}
|
||||||
}
|
else if (v !== null && typeof v != 'undefined')
|
||||||
else if (v !== null && typeof v != 'undefined') {
|
|
||||||
a.push({name: n, value: v});
|
a.push({name: n, value: v});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!semantic && form.clk) {
|
if (!semantic && form.clk) {
|
||||||
// input type=='image' are not found in elements array! handle it here
|
// input type=='image' are not found in elements array! handle them here
|
||||||
var $input = $(form.clk), input = $input[0];
|
var inputs = form.getElementsByTagName("input");
|
||||||
n = input.name;
|
for(var i=0, max=inputs.length; i < max; i++) {
|
||||||
if (n && !input.disabled && input.type == 'image') {
|
var input = inputs[i];
|
||||||
a.push({name: n, value: $input.val()});
|
var n = input.name;
|
||||||
|
if(n && !input.disabled && input.type == "image" && form.clk == input)
|
||||||
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
a.push({name: n+'.x', value: form.clk_x}, {name: n+'.y', value: form.clk_y});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -596,18 +455,14 @@ $.fn.fieldSerialize = function(successful) {
|
|||||||
var a = [];
|
var a = [];
|
||||||
this.each(function() {
|
this.each(function() {
|
||||||
var n = this.name;
|
var n = this.name;
|
||||||
if (!n) {
|
if (!n) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
var v = $.fieldValue(this, successful);
|
var v = $.fieldValue(this, successful);
|
||||||
if (v && v.constructor == Array) {
|
if (v && v.constructor == Array) {
|
||||||
for (var i=0,max=v.length; i < max; i++) {
|
for (var i=0,max=v.length; i < max; i++)
|
||||||
a.push({name: n, value: v[i]});
|
a.push({name: n, value: v[i]});
|
||||||
}
|
}
|
||||||
}
|
else if (v !== null && typeof v != 'undefined')
|
||||||
else if (v !== null && typeof v != 'undefined') {
|
|
||||||
a.push({name: this.name, value: v});
|
a.push({name: this.name, value: v});
|
||||||
}
|
|
||||||
});
|
});
|
||||||
//hand off to jQuery.param for proper encoding
|
//hand off to jQuery.param for proper encoding
|
||||||
return $.param(a);
|
return $.param(a);
|
||||||
@ -655,9 +510,8 @@ $.fn.fieldValue = function(successful) {
|
|||||||
for (var val=[], i=0, max=this.length; i < max; i++) {
|
for (var val=[], i=0, max=this.length; i < max; i++) {
|
||||||
var el = this[i];
|
var el = this[i];
|
||||||
var v = $.fieldValue(el, successful);
|
var v = $.fieldValue(el, successful);
|
||||||
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length)) {
|
if (v === null || typeof v == 'undefined' || (v.constructor == Array && !v.length))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
v.constructor == Array ? $.merge(val, v) : val.push(v);
|
v.constructor == Array ? $.merge(val, v) : val.push(v);
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
@ -668,41 +522,32 @@ $.fn.fieldValue = function(successful) {
|
|||||||
*/
|
*/
|
||||||
$.fieldValue = function(el, successful) {
|
$.fieldValue = function(el, successful) {
|
||||||
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
var n = el.name, t = el.type, tag = el.tagName.toLowerCase();
|
||||||
if (successful === undefined) {
|
if (typeof successful == 'undefined') successful = true;
|
||||||
successful = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
if (successful && (!n || el.disabled || t == 'reset' || t == 'button' ||
|
||||||
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
(t == 'checkbox' || t == 'radio') && !el.checked ||
|
||||||
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
(t == 'submit' || t == 'image') && el.form && el.form.clk != el ||
|
||||||
tag == 'select' && el.selectedIndex == -1)) {
|
tag == 'select' && el.selectedIndex == -1))
|
||||||
return null;
|
return null;
|
||||||
}
|
|
||||||
|
|
||||||
if (tag == 'select') {
|
if (tag == 'select') {
|
||||||
var index = el.selectedIndex;
|
var index = el.selectedIndex;
|
||||||
if (index < 0) {
|
if (index < 0) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
var a = [], ops = el.options;
|
var a = [], ops = el.options;
|
||||||
var one = (t == 'select-one');
|
var one = (t == 'select-one');
|
||||||
var max = (one ? index+1 : ops.length);
|
var max = (one ? index+1 : ops.length);
|
||||||
for(var i=(one ? index : 0); i < max; i++) {
|
for(var i=(one ? index : 0); i < max; i++) {
|
||||||
var op = ops[i];
|
var op = ops[i];
|
||||||
if (op.selected) {
|
if (op.selected) {
|
||||||
var v = op.value;
|
// extra pain for IE...
|
||||||
if (!v) { // extra pain for IE...
|
var v = $.browser.msie && !(op.attributes['value'].specified) ? op.text : op.value;
|
||||||
v = (op.attributes && op.attributes['value'] && !(op.attributes['value'].specified)) ? op.text : op.value;
|
if (one) return v;
|
||||||
}
|
|
||||||
if (one) {
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
a.push(v);
|
a.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
return $(el).val();
|
return el.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -725,15 +570,12 @@ $.fn.clearForm = function() {
|
|||||||
$.fn.clearFields = $.fn.clearInputs = function() {
|
$.fn.clearFields = $.fn.clearInputs = function() {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var t = this.type, tag = this.tagName.toLowerCase();
|
var t = this.type, tag = this.tagName.toLowerCase();
|
||||||
if (t == 'text' || t == 'password' || tag == 'textarea') {
|
if (t == 'file' || t == 'text' || t == 'password' || tag == 'textarea')
|
||||||
this.value = '';
|
this.value = '';
|
||||||
}
|
else if (t == 'checkbox' || t == 'radio')
|
||||||
else if (t == 'checkbox' || t == 'radio') {
|
|
||||||
this.checked = false;
|
this.checked = false;
|
||||||
}
|
else if (tag == 'select')
|
||||||
else if (tag == 'select') {
|
|
||||||
this.selectedIndex = -1;
|
this.selectedIndex = -1;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -744,9 +586,8 @@ $.fn.resetForm = function() {
|
|||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
// guard against an input with the name of 'reset'
|
// guard against an input with the name of 'reset'
|
||||||
// note that IE reports the reset function as an 'object'
|
// note that IE reports the reset function as an 'object'
|
||||||
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType)) {
|
if (typeof this.reset == 'function' || (typeof this.reset == 'object' && !this.reset.nodeType))
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -754,11 +595,9 @@ $.fn.resetForm = function() {
|
|||||||
* Enables or disables any matching elements.
|
* Enables or disables any matching elements.
|
||||||
*/
|
*/
|
||||||
$.fn.enable = function(b) {
|
$.fn.enable = function(b) {
|
||||||
if (b === undefined) {
|
if (b == undefined) b = true;
|
||||||
b = true;
|
|
||||||
}
|
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
this.disabled = !b;
|
this.disabled = !b
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -767,14 +606,11 @@ $.fn.enable = function(b) {
|
|||||||
* selects/deselects and matching option elements.
|
* selects/deselects and matching option elements.
|
||||||
*/
|
*/
|
||||||
$.fn.selected = function(select) {
|
$.fn.selected = function(select) {
|
||||||
if (select === undefined) {
|
if (select == undefined) select = true;
|
||||||
select = true;
|
|
||||||
}
|
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
var t = this.type;
|
var t = this.type;
|
||||||
if (t == 'checkbox' || t == 'radio') {
|
if (t == 'checkbox' || t == 'radio')
|
||||||
this.checked = select;
|
this.checked = select;
|
||||||
}
|
|
||||||
else if (this.tagName.toLowerCase() == 'option') {
|
else if (this.tagName.toLowerCase() == 'option') {
|
||||||
var $sel = $(this).parent('select');
|
var $sel = $(this).parent('select');
|
||||||
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
if (select && $sel[0] && $sel[0].type == 'select-one') {
|
||||||
@ -789,15 +625,8 @@ $.fn.selected = function(select) {
|
|||||||
// helper fn for console logging
|
// helper fn for console logging
|
||||||
// set $.fn.ajaxSubmit.debug to true to enable debug logging
|
// set $.fn.ajaxSubmit.debug to true to enable debug logging
|
||||||
function log() {
|
function log() {
|
||||||
if ($.fn.ajaxSubmit.debug) {
|
if ($.fn.ajaxSubmit.debug && window.console && window.console.log)
|
||||||
var msg = '[jquery.form] ' + Array.prototype.join.call(arguments,'');
|
window.console.log('[jquery.form] ' + Array.prototype.join.call(arguments,''));
|
||||||
if (window.console && window.console.log) {
|
|
||||||
window.console.log(msg);
|
|
||||||
}
|
|
||||||
else if (window.opera && window.opera.postError) {
|
|
||||||
window.opera.postError(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
12
js/jquery.form.min.js
vendored
12
js/jquery.form.min.js
vendored
File diff suppressed because one or more lines are too long
@ -392,6 +392,18 @@ class Activity
|
|||||||
|
|
||||||
if ($author) {
|
if ($author) {
|
||||||
$this->actor->outputTo($xs, 'author');
|
$this->actor->outputTo($xs, 'author');
|
||||||
|
|
||||||
|
// XXX: Remove <activity:actor> ASAP! Author information
|
||||||
|
// has been moved to the author element in the Activity
|
||||||
|
// Streams spec. We're outputting actor only for backward
|
||||||
|
// compatibility with clients that can only parse
|
||||||
|
// activities based on older versions of the spec.
|
||||||
|
|
||||||
|
$depMsg = 'Deprecation warning: activity:actor is present '
|
||||||
|
. 'only for backward compatibility. It will be '
|
||||||
|
. 'removed in the next version of StatusNet.';
|
||||||
|
$xs->comment($depMsg);
|
||||||
|
$this->actor->outputTo($xs, 'activity:actor');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->verb != ActivityVerb::POST || count($this->objects) != 1) {
|
if ($this->verb != ActivityVerb::POST || count($this->objects) != 1) {
|
||||||
|
@ -263,8 +263,7 @@ class ApiAction extends Action
|
|||||||
? Design::url($design->backgroundimage) : '';
|
? Design::url($design->backgroundimage) : '';
|
||||||
|
|
||||||
$twitter_user['profile_background_tile']
|
$twitter_user['profile_background_tile']
|
||||||
= empty($design->disposition)
|
= (bool)($design->disposition & BACKGROUND_TILE);
|
||||||
? '' : ($design->disposition & BACKGROUND_TILE) ? 'true' : 'false';
|
|
||||||
|
|
||||||
$twitter_user['statuses_count'] = $profile->noticeCount();
|
$twitter_user['statuses_count'] = $profile->noticeCount();
|
||||||
|
|
||||||
@ -1236,9 +1235,12 @@ class ApiAction extends Action
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function clientError($msg, $code = 400, $format = 'xml')
|
function clientError($msg, $code = 400, $format = null)
|
||||||
{
|
{
|
||||||
$action = $this->trimmed('action');
|
$action = $this->trimmed('action');
|
||||||
|
if ($format === null) {
|
||||||
|
$format = $this->format;
|
||||||
|
}
|
||||||
|
|
||||||
common_debug("User error '$code' on '$action': $msg", __FILE__);
|
common_debug("User error '$code' on '$action': $msg", __FILE__);
|
||||||
|
|
||||||
@ -1278,9 +1280,12 @@ class ApiAction extends Action
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function serverError($msg, $code = 500, $content_type = 'xml')
|
function serverError($msg, $code = 500, $content_type = null)
|
||||||
{
|
{
|
||||||
$action = $this->trimmed('action');
|
$action = $this->trimmed('action');
|
||||||
|
if ($content_type === null) {
|
||||||
|
$content_type = $this->format;
|
||||||
|
}
|
||||||
|
|
||||||
common_debug("Server error '$code' on '$action': $msg", __FILE__);
|
common_debug("Server error '$code' on '$action': $msg", __FILE__);
|
||||||
|
|
||||||
|
@ -91,8 +91,16 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
|
|||||||
|
|
||||||
$ao = ActivityObject::fromGroup($group);
|
$ao = ActivityObject::fromGroup($group);
|
||||||
|
|
||||||
$this->addAuthorRaw($ao->asString('author').
|
$this->addAuthorRaw($ao->asString('author'));
|
||||||
$ao->asString('activity:subject'));
|
|
||||||
|
$depMsg = 'Deprecation warning: activity:subject is present '
|
||||||
|
. 'only for backward compatibility. It will be '
|
||||||
|
. 'removed in the next version of StatusNet.';
|
||||||
|
|
||||||
|
$this->addAuthorRaw(
|
||||||
|
"<!--$depMsg-->\n"
|
||||||
|
. $ao->asString('activity:subject')
|
||||||
|
);
|
||||||
|
|
||||||
$this->addLink($group->homeUrl());
|
$this->addLink($group->homeUrl());
|
||||||
}
|
}
|
||||||
|
@ -59,9 +59,29 @@ class AtomUserNoticeFeed extends AtomNoticeFeed
|
|||||||
parent::__construct($cur, $indent);
|
parent::__construct($cur, $indent);
|
||||||
$this->user = $user;
|
$this->user = $user;
|
||||||
if (!empty($user)) {
|
if (!empty($user)) {
|
||||||
|
|
||||||
$profile = $user->getProfile();
|
$profile = $user->getProfile();
|
||||||
|
|
||||||
$ao = ActivityObject::fromProfile($profile);
|
$ao = ActivityObject::fromProfile($profile);
|
||||||
|
|
||||||
|
$ao->extra[] = $profile->profileInfo($cur);
|
||||||
|
|
||||||
|
// XXX: For users, we generate an author _AND_ an <activity:subject>
|
||||||
|
// This is for backward compatibility with clients (especially
|
||||||
|
// StatusNet's clients) that assume the Atom will conform to an
|
||||||
|
// older version of the Activity Streams API. Subject should be
|
||||||
|
// removed in future versions of StatusNet.
|
||||||
|
|
||||||
$this->addAuthorRaw($ao->asString('author'));
|
$this->addAuthorRaw($ao->asString('author'));
|
||||||
|
|
||||||
|
$depMsg = 'Deprecation warning: activity:subject is present '
|
||||||
|
. 'only for backward compatibility. It will be '
|
||||||
|
. 'removed in the next version of StatusNet.';
|
||||||
|
|
||||||
|
$this->addAuthorRaw(
|
||||||
|
"<!--$depMsg-->\n"
|
||||||
|
. $ao->asString('activity:subject')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TRANS: Title in atom user notice feed. %s is a user name.
|
// TRANS: Title in atom user notice feed. %s is a user name.
|
||||||
|
@ -76,8 +76,7 @@ class AttachmentList extends Widget
|
|||||||
*/
|
*/
|
||||||
function show()
|
function show()
|
||||||
{
|
{
|
||||||
$atts = new File;
|
$att = File::getAttachments($this->notice->id);
|
||||||
$att = $atts->getAttachments($this->notice->id);
|
|
||||||
if (empty($att)) return 0;
|
if (empty($att)) return 0;
|
||||||
$this->showListStart();
|
$this->showListStart();
|
||||||
|
|
||||||
|
@ -164,6 +164,7 @@ class Cache
|
|||||||
{
|
{
|
||||||
$value = false;
|
$value = false;
|
||||||
|
|
||||||
|
common_perf_counter('Cache::get', $key);
|
||||||
if (Event::handle('StartCacheGet', array(&$key, &$value))) {
|
if (Event::handle('StartCacheGet', array(&$key, &$value))) {
|
||||||
if (array_key_exists($key, $this->_items)) {
|
if (array_key_exists($key, $this->_items)) {
|
||||||
$value = unserialize($this->_items[$key]);
|
$value = unserialize($this->_items[$key]);
|
||||||
@ -188,6 +189,7 @@ class Cache
|
|||||||
{
|
{
|
||||||
$success = false;
|
$success = false;
|
||||||
|
|
||||||
|
common_perf_counter('Cache::set', $key);
|
||||||
if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag,
|
if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag,
|
||||||
&$expiry, &$success))) {
|
&$expiry, &$success))) {
|
||||||
|
|
||||||
@ -214,6 +216,7 @@ class Cache
|
|||||||
function increment($key, $step=1)
|
function increment($key, $step=1)
|
||||||
{
|
{
|
||||||
$value = false;
|
$value = false;
|
||||||
|
common_perf_counter('Cache::increment', $key);
|
||||||
if (Event::handle('StartCacheIncrement', array(&$key, &$step, &$value))) {
|
if (Event::handle('StartCacheIncrement', array(&$key, &$step, &$value))) {
|
||||||
// Fallback is not guaranteed to be atomic,
|
// Fallback is not guaranteed to be atomic,
|
||||||
// and may original expiry value.
|
// and may original expiry value.
|
||||||
@ -239,6 +242,7 @@ class Cache
|
|||||||
{
|
{
|
||||||
$success = false;
|
$success = false;
|
||||||
|
|
||||||
|
common_perf_counter('Cache::delete', $key);
|
||||||
if (Event::handle('StartCacheDelete', array(&$key, &$success))) {
|
if (Event::handle('StartCacheDelete', array(&$key, &$success))) {
|
||||||
if (array_key_exists($key, $this->_items)) {
|
if (array_key_exists($key, $this->_items)) {
|
||||||
unset($this->_items[$key]);
|
unset($this->_items[$key]);
|
||||||
|
@ -25,252 +25,287 @@ class CommandInterpreter
|
|||||||
{
|
{
|
||||||
function handle_command($user, $text)
|
function handle_command($user, $text)
|
||||||
{
|
{
|
||||||
# XXX: localise
|
// XXX: localise
|
||||||
|
|
||||||
$text = preg_replace('/\s+/', ' ', trim($text));
|
$text = preg_replace('/\s+/', ' ', trim($text));
|
||||||
list($cmd, $arg) = $this->split_arg($text);
|
list($cmd, $arg) = $this->split_arg($text);
|
||||||
|
|
||||||
# We try to support all the same commands as Twitter, see
|
// We try to support all the same commands as Twitter, see
|
||||||
# http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
|
// http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
|
||||||
# There are a few compatibility commands from earlier versions of
|
// There are a few compatibility commands from earlier versions of
|
||||||
# StatusNet
|
// StatusNet
|
||||||
|
|
||||||
switch(strtolower($cmd)) {
|
$cmd = strtolower($cmd);
|
||||||
|
|
||||||
|
if (Event::handle('StartIntepretCommand', array($cmd, $arg, $user, &$result))) {
|
||||||
|
switch($cmd) {
|
||||||
case 'help':
|
case 'help':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
return new HelpCommand($user);
|
$result = new HelpCommand($user);
|
||||||
|
break;
|
||||||
case 'login':
|
case 'login':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new LoginCommand($user);
|
$result = new LoginCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'lose':
|
case 'lose':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new LoseCommand($user, $other);
|
$result = new LoseCommand($user, $other);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'subscribers':
|
case 'subscribers':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new SubscribersCommand($user);
|
$result = new SubscribersCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'subscriptions':
|
case 'subscriptions':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new SubscriptionsCommand($user);
|
$result = new SubscriptionsCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'groups':
|
case 'groups':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new GroupsCommand($user);
|
$result = new GroupsCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'on':
|
case 'on':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new OnCommand($user, $other);
|
$result = new OnCommand($user, $other);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new OnCommand($user);
|
$result = new OnCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'off':
|
case 'off':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new OffCommand($user, $other);
|
$result = new OffCommand($user, $other);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return new OffCommand($user);
|
$result = new OffCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'stop':
|
case 'stop':
|
||||||
case 'quit':
|
case 'quit':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new OffCommand($user);
|
$result = new OffCommand($user);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'join':
|
case 'join':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new JoinCommand($user, $other);
|
$result = new JoinCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'drop':
|
case 'drop':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new DropCommand($user, $other);
|
$result = new DropCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'follow':
|
case 'follow':
|
||||||
case 'sub':
|
case 'sub':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new SubCommand($user, $other);
|
$result = new SubCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'leave':
|
case 'leave':
|
||||||
case 'unsub':
|
case 'unsub':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new UnsubCommand($user, $other);
|
$result = new UnsubCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'get':
|
case 'get':
|
||||||
case 'last':
|
case 'last':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new GetCommand($user, $other);
|
$result = new GetCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'dm':
|
case 'dm':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if (!$extra) {
|
if (!$extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new MessageCommand($user, $other, $extra);
|
$result = new MessageCommand($user, $other, $extra);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
case 'reply':
|
case 'reply':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if (!$extra) {
|
if (!$extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new ReplyCommand($user, $other, $extra);
|
$result = new ReplyCommand($user, $other, $extra);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'repeat':
|
case 'repeat':
|
||||||
case 'rp':
|
case 'rp':
|
||||||
case 'rt':
|
case 'rt':
|
||||||
case 'rd':
|
case 'rd':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new RepeatCommand($user, $other);
|
$result = new RepeatCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'whois':
|
case 'whois':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new WhoisCommand($user, $other);
|
$result = new WhoisCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'fav':
|
case 'fav':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new FavCommand($user, $other);
|
$result = new FavCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'nudge':
|
case 'nudge':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new NudgeCommand($user, $other);
|
$result = new NudgeCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'stats':
|
case 'stats':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
return new StatsCommand($user);
|
$result = new StatsCommand($user);
|
||||||
|
break;
|
||||||
case 'invite':
|
case 'invite':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($other, $extra) = $this->split_arg($arg);
|
list($other, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else {
|
} else {
|
||||||
return new InviteCommand($user, $other);
|
$result = new InviteCommand($user, $other);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'track':
|
case 'track':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($word, $extra) = $this->split_arg($arg);
|
list($word, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else if ($word == 'off') {
|
} else if ($word == 'off') {
|
||||||
return new TrackOffCommand($user);
|
$result = new TrackOffCommand($user);
|
||||||
} else {
|
} else {
|
||||||
return new TrackCommand($user, $word);
|
$result = new TrackCommand($user, $word);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'untrack':
|
case 'untrack':
|
||||||
if (!$arg) {
|
if (!$arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
list($word, $extra) = $this->split_arg($arg);
|
list($word, $extra) = $this->split_arg($arg);
|
||||||
if ($extra) {
|
if ($extra) {
|
||||||
return null;
|
$result = null;
|
||||||
} else if ($word == 'all') {
|
} else if ($word == 'all') {
|
||||||
return new TrackOffCommand($user);
|
$result = new TrackOffCommand($user);
|
||||||
} else {
|
} else {
|
||||||
return new UntrackCommand($user, $word);
|
$result = new UntrackCommand($user, $word);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case 'tracks':
|
case 'tracks':
|
||||||
case 'tracking':
|
case 'tracking':
|
||||||
if ($arg) {
|
if ($arg) {
|
||||||
return null;
|
$result = null;
|
||||||
}
|
}
|
||||||
return new TrackingCommand($user);
|
$result = new TrackingCommand($user);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
$result = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Event::handle('EndInterpretCommand', array($cmd, $arg, $user, $result));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -23,7 +23,7 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
|||||||
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
|
if (isset($_REQUEST['p']) && $_REQUEST['p'] == 'check-fancy') { exit; }
|
||||||
|
|
||||||
define('STATUSNET_BASE_VERSION', '0.9.7');
|
define('STATUSNET_BASE_VERSION', '0.9.7');
|
||||||
define('STATUSNET_LIFECYCLE', 'alpha1'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
|
define('STATUSNET_LIFECYCLE', 'beta2'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release'
|
||||||
define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE);
|
define('STATUSNET_VERSION', STATUSNET_BASE_VERSION . STATUSNET_LIFECYCLE);
|
||||||
|
|
||||||
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
define('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
||||||
@ -36,6 +36,7 @@ define('AVATAR_MINI_SIZE', 24);
|
|||||||
|
|
||||||
define('NOTICES_PER_PAGE', 20);
|
define('NOTICES_PER_PAGE', 20);
|
||||||
define('PROFILES_PER_PAGE', 20);
|
define('PROFILES_PER_PAGE', 20);
|
||||||
|
define('MESSAGES_PER_PAGE', 20);
|
||||||
|
|
||||||
define('FOREIGN_NOTICE_SEND', 1);
|
define('FOREIGN_NOTICE_SEND', 1);
|
||||||
define('FOREIGN_NOTICE_RECV', 2);
|
define('FOREIGN_NOTICE_RECV', 2);
|
||||||
|
@ -39,6 +39,8 @@ $default =
|
|||||||
'logo' => null,
|
'logo' => null,
|
||||||
'ssllogo' => null,
|
'ssllogo' => null,
|
||||||
'logdebug' => false,
|
'logdebug' => false,
|
||||||
|
'logperf' => false, // Enable to dump performance counters to syslog
|
||||||
|
'logperf_detail' => false, // Enable to dump every counter hit
|
||||||
'fancy' => false,
|
'fancy' => false,
|
||||||
'locale_path' => INSTALLDIR.'/locale',
|
'locale_path' => INSTALLDIR.'/locale',
|
||||||
'language' => 'en',
|
'language' => 'en',
|
||||||
@ -270,7 +272,8 @@ $default =
|
|||||||
array('type' => 'fulltext'),
|
array('type' => 'fulltext'),
|
||||||
'sessions' =>
|
'sessions' =>
|
||||||
array('handle' => false, // whether to handle sessions ourselves
|
array('handle' => false, // whether to handle sessions ourselves
|
||||||
'debug' => false), // debugging output for sessions
|
'debug' => false, // debugging output for sessions
|
||||||
|
'gc_limit' => 1000), // max sessions to expire at a time
|
||||||
'design' =>
|
'design' =>
|
||||||
array('backgroundcolor' => null, // null -> 'use theme default'
|
array('backgroundcolor' => null, // null -> 'use theme default'
|
||||||
'contentcolor' => null,
|
'contentcolor' => null,
|
||||||
@ -311,6 +314,9 @@ $default =
|
|||||||
'RSSCloud' => null,
|
'RSSCloud' => null,
|
||||||
'OpenID' => null),
|
'OpenID' => null),
|
||||||
'locale_path' => false, // Set to a path to use *instead of* each plugin's own locale subdirectories
|
'locale_path' => false, // Set to a path to use *instead of* each plugin's own locale subdirectories
|
||||||
|
'server' => null,
|
||||||
|
'sslserver' => null,
|
||||||
|
'path' => null,
|
||||||
),
|
),
|
||||||
'admin' =>
|
'admin' =>
|
||||||
array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'license')),
|
array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'license')),
|
||||||
|
@ -139,11 +139,12 @@ class GroupEditForm extends Form
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->out->elementStart('ul', 'form_data');
|
$this->out->elementStart('ul', 'form_data');
|
||||||
|
if (Event::handle('StartGroupEditFormData', array($this))) {
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
$this->out->hidden('groupid', $id);
|
$this->out->hidden('groupid', $id);
|
||||||
$this->out->input('nickname', _('Nickname'),
|
$this->out->input('nickname', _('Nickname'),
|
||||||
($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
|
($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
|
||||||
_('1-64 lowercase letters or numbers, no punctuation or spaces.'));
|
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
$this->out->elementStart('li');
|
$this->out->elementStart('li');
|
||||||
$this->out->input('fullname', _('Full name'),
|
$this->out->input('fullname', _('Full name'),
|
||||||
@ -159,8 +160,8 @@ class GroupEditForm extends Form
|
|||||||
if ($desclimit == 0) {
|
if ($desclimit == 0) {
|
||||||
$descinstr = _('Describe the group or topic');
|
$descinstr = _('Describe the group or topic');
|
||||||
} else {
|
} else {
|
||||||
$descinstr = sprintf(_m('Describe the group or topic in %d character or less.',
|
$descinstr = sprintf(_m('Describe the group or topic in %d character or less',
|
||||||
'Describe the group or topic in %d characters or less.',
|
'Describe the group or topic in %d characters or less',
|
||||||
$desclimit),
|
$desclimit),
|
||||||
$desclimit);
|
$desclimit);
|
||||||
}
|
}
|
||||||
@ -185,6 +186,8 @@ class GroupEditForm extends Form
|
|||||||
common_config('group', 'maxaliases')));;
|
common_config('group', 'maxaliases')));;
|
||||||
$this->out->elementEnd('li');
|
$this->out->elementEnd('li');
|
||||||
}
|
}
|
||||||
|
Event::handle('EndGroupEditFormData', array($this));
|
||||||
|
}
|
||||||
$this->out->elementEnd('ul');
|
$this->out->elementEnd('ul');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
161
lib/mailbox.php
161
lib/mailbox.php
@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
define('MESSAGES_PER_PAGE', 20);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* common superclass for direct messages inbox and outbox
|
* common superclass for direct messages inbox and outbox
|
||||||
*
|
*
|
||||||
@ -111,32 +109,22 @@ class MailboxAction extends CurrentUserDesignAction
|
|||||||
$message = $this->getMessages();
|
$message = $this->getMessages();
|
||||||
|
|
||||||
if ($message) {
|
if ($message) {
|
||||||
$cnt = 0;
|
|
||||||
$this->elementStart('div', array('id' =>'notices_primary'));
|
|
||||||
$this->element('h2', null, _('Notices'));
|
|
||||||
$this->elementStart('ul', 'notices');
|
|
||||||
|
|
||||||
while ($message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
|
$ml = $this->getMessageList($message);
|
||||||
$cnt++;
|
|
||||||
|
|
||||||
if ($cnt > MESSAGES_PER_PAGE) {
|
$cnt = $ml->show();
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->showMessage($message);
|
$this->pagination($this->page > 1,
|
||||||
}
|
$cnt > MESSAGES_PER_PAGE,
|
||||||
|
$this->page,
|
||||||
$this->elementEnd('ul');
|
$this->trimmed('action'),
|
||||||
|
|
||||||
$this->pagination($this->page > 1, $cnt > MESSAGES_PER_PAGE,
|
|
||||||
$this->page, $this->trimmed('action'),
|
|
||||||
array('nickname' => $this->user->nickname));
|
array('nickname' => $this->user->nickname));
|
||||||
$this->elementEnd('div');
|
} else {
|
||||||
$message->free();
|
$this->element('p',
|
||||||
unset($message);
|
'guide',
|
||||||
}
|
_('You have no private messages. '.
|
||||||
else {
|
'You can send private message to engage other users in conversation. '.
|
||||||
$this->element('p', 'guide', _('You have no private messages. You can send private message to engage other users in conversation. People can send you messages for your eyes only.'));
|
'People can send you messages for your eyes only.'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,95 +133,11 @@ class MailboxAction extends CurrentUserDesignAction
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function getMessageList($message)
|
||||||
* returns the profile we want to show with the message
|
|
||||||
*
|
|
||||||
* For inboxes, we show the sender; for outboxes, the recipient.
|
|
||||||
*
|
|
||||||
* @param Message $message The message to get the profile for
|
|
||||||
*
|
|
||||||
* @return Profile The profile that matches the message
|
|
||||||
*/
|
|
||||||
|
|
||||||
function getMessageProfile($message)
|
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* show a single message in the list format
|
|
||||||
*
|
|
||||||
* XXX: This needs to be extracted out into a MessageList similar
|
|
||||||
* to NoticeList.
|
|
||||||
*
|
|
||||||
* @param Message $message the message to show
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
|
|
||||||
function showMessage($message)
|
|
||||||
{
|
|
||||||
$this->elementStart('li', array('class' => 'hentry notice',
|
|
||||||
'id' => 'message-' . $message->id));
|
|
||||||
|
|
||||||
$profile = $this->getMessageProfile($message);
|
|
||||||
|
|
||||||
$this->elementStart('div', 'entry-title');
|
|
||||||
$this->elementStart('span', 'vcard author');
|
|
||||||
$this->elementStart('a', array('href' => $profile->profileurl,
|
|
||||||
'class' => 'url'));
|
|
||||||
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
|
||||||
$this->element('img', array('src' => ($avatar) ?
|
|
||||||
$avatar->displayUrl() :
|
|
||||||
Avatar::defaultImage(AVATAR_STREAM_SIZE),
|
|
||||||
'class' => 'photo avatar',
|
|
||||||
'width' => AVATAR_STREAM_SIZE,
|
|
||||||
'height' => AVATAR_STREAM_SIZE,
|
|
||||||
'alt' =>
|
|
||||||
($profile->fullname) ? $profile->fullname :
|
|
||||||
$profile->nickname));
|
|
||||||
$this->element('span', array('class' => 'nickname fn'),
|
|
||||||
$profile->nickname);
|
|
||||||
$this->elementEnd('a');
|
|
||||||
$this->elementEnd('span');
|
|
||||||
|
|
||||||
// FIXME: URL, image, video, audio
|
|
||||||
$this->elementStart('p', array('class' => 'entry-content'));
|
|
||||||
$this->raw($message->rendered);
|
|
||||||
$this->elementEnd('p');
|
|
||||||
$this->elementEnd('div');
|
|
||||||
|
|
||||||
$messageurl = common_local_url('showmessage',
|
|
||||||
array('message' => $message->id));
|
|
||||||
|
|
||||||
// XXX: we need to figure this out better. Is this right?
|
|
||||||
if (strcmp($message->uri, $messageurl) != 0 &&
|
|
||||||
preg_match('/^http/', $message->uri)) {
|
|
||||||
$messageurl = $message->uri;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->elementStart('div', 'entry-content');
|
|
||||||
$this->elementStart('a', array('rel' => 'bookmark',
|
|
||||||
'class' => 'timestamp',
|
|
||||||
'href' => $messageurl));
|
|
||||||
$dt = common_date_iso8601($message->created);
|
|
||||||
$this->element('abbr', array('class' => 'published',
|
|
||||||
'title' => $dt),
|
|
||||||
common_date_string($message->created));
|
|
||||||
$this->elementEnd('a');
|
|
||||||
|
|
||||||
if ($message->source) {
|
|
||||||
$this->elementStart('span', 'source');
|
|
||||||
// FIXME: bad i18n. Device should be a parameter (from %s).
|
|
||||||
$this->text(_('from'));
|
|
||||||
$this->element('span', 'device', $this->showSource($message->source));
|
|
||||||
$this->elementEnd('span');
|
|
||||||
}
|
|
||||||
$this->elementEnd('div');
|
|
||||||
|
|
||||||
$this->elementEnd('li');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the page notice
|
* Show the page notice
|
||||||
*
|
*
|
||||||
@ -252,44 +156,6 @@ class MailboxAction extends CurrentUserDesignAction
|
|||||||
$this->elementEnd('div');
|
$this->elementEnd('div');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show the source of the message
|
|
||||||
*
|
|
||||||
* Returns either the name (and link) of the API client that posted the notice,
|
|
||||||
* or one of other other channels.
|
|
||||||
*
|
|
||||||
* @param string $source the source of the message
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
|
|
||||||
function showSource($source)
|
|
||||||
{
|
|
||||||
$source_name = _($source);
|
|
||||||
switch ($source) {
|
|
||||||
case 'web':
|
|
||||||
case 'xmpp':
|
|
||||||
case 'mail':
|
|
||||||
case 'omb':
|
|
||||||
case 'api':
|
|
||||||
$this->element('span', 'device', $source_name);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$ns = Notice_source::staticGet($source);
|
|
||||||
if ($ns) {
|
|
||||||
$this->elementStart('span', 'device');
|
|
||||||
$this->element('a', array('href' => $ns->url,
|
|
||||||
'rel' => 'external'),
|
|
||||||
$ns->name);
|
|
||||||
$this->elementEnd('span');
|
|
||||||
} else {
|
|
||||||
$this->element('span', 'device', $source_name);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mailbox actions are read only
|
* Mailbox actions are read only
|
||||||
*
|
*
|
||||||
@ -302,5 +168,4 @@ class MailboxAction extends CurrentUserDesignAction
|
|||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
107
lib/messagelist.php
Normal file
107
lib/messagelist.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* The message list widget
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message list widget
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
abstract class MessageList extends Widget
|
||||||
|
{
|
||||||
|
var $message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param HTMLOutputter $out Output context
|
||||||
|
* @param Message $message Stream of messages to show
|
||||||
|
*/
|
||||||
|
function __construct($out, $message)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
$this->message = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the widget
|
||||||
|
*
|
||||||
|
* Uses newItem() to create each new item.
|
||||||
|
*
|
||||||
|
* @return integer count of messages seen.
|
||||||
|
*/
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$cnt = 0;
|
||||||
|
|
||||||
|
$this->out->elementStart('div', array('id' =>'notices_primary'));
|
||||||
|
|
||||||
|
$this->out->element('h2', null, _('Messages'));
|
||||||
|
|
||||||
|
$this->out->elementStart('ul', 'notices messages');
|
||||||
|
|
||||||
|
while ($this->message->fetch() && $cnt <= MESSAGES_PER_PAGE) {
|
||||||
|
|
||||||
|
$cnt++;
|
||||||
|
|
||||||
|
if ($cnt > MESSAGES_PER_PAGE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mli = $this->newItem($this->message);
|
||||||
|
|
||||||
|
$mli->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message item for a message
|
||||||
|
*
|
||||||
|
* @param Message $message The message to show
|
||||||
|
*
|
||||||
|
* @return MessageListItem an item to show
|
||||||
|
*/
|
||||||
|
abstract function newItem($message);
|
||||||
|
}
|
178
lib/messagelistitem.php
Normal file
178
lib/messagelistitem.php
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* A single list item for showing in a message list
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single item in a message list
|
||||||
|
*
|
||||||
|
* @category Widget
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
abstract class MessageListItem extends Widget
|
||||||
|
{
|
||||||
|
var $message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param HTMLOutputter $out Output context
|
||||||
|
* @param Message $message Message to show
|
||||||
|
*/
|
||||||
|
function __construct($out, $message)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
$this->message = $message;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the widget
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$this->out->elementStart('li', array('class' => 'hentry notice',
|
||||||
|
'id' => 'message-' . $this->message->id));
|
||||||
|
|
||||||
|
$profile = $this->getMessageProfile();
|
||||||
|
|
||||||
|
$this->out->elementStart('div', 'entry-title');
|
||||||
|
$this->out->elementStart('span', 'vcard author');
|
||||||
|
$this->out->elementStart('a', array('href' => $profile->profileurl,
|
||||||
|
'class' => 'url'));
|
||||||
|
$avatar = $profile->getAvatar(AVATAR_STREAM_SIZE);
|
||||||
|
$this->out->element('img', array('src' => ($avatar) ?
|
||||||
|
$avatar->displayUrl() :
|
||||||
|
Avatar::defaultImage(AVATAR_STREAM_SIZE),
|
||||||
|
'class' => 'photo avatar',
|
||||||
|
'width' => AVATAR_STREAM_SIZE,
|
||||||
|
'height' => AVATAR_STREAM_SIZE,
|
||||||
|
'alt' =>
|
||||||
|
($profile->fullname) ? $profile->fullname :
|
||||||
|
$profile->nickname));
|
||||||
|
$this->out->element('span', array('class' => 'nickname fn'),
|
||||||
|
$profile->nickname);
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
$this->out->elementEnd('span');
|
||||||
|
|
||||||
|
// FIXME: URL, image, video, audio
|
||||||
|
$this->out->elementStart('p', array('class' => 'entry-content'));
|
||||||
|
$this->out->raw($this->message->rendered);
|
||||||
|
$this->out->elementEnd('p');
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
|
$messageurl = common_local_url('showmessage',
|
||||||
|
array('message' => $this->message->id));
|
||||||
|
|
||||||
|
// XXX: we need to figure this out better. Is this right?
|
||||||
|
if (strcmp($this->message->uri, $messageurl) != 0 &&
|
||||||
|
preg_match('/^http/', $this->message->uri)) {
|
||||||
|
$messageurl = $this->message->uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementStart('div', 'entry-content');
|
||||||
|
$this->out->elementStart('a', array('rel' => 'bookmark',
|
||||||
|
'class' => 'timestamp',
|
||||||
|
'href' => $messageurl));
|
||||||
|
$dt = common_date_iso8601($this->message->created);
|
||||||
|
$this->out->element('abbr', array('class' => 'published',
|
||||||
|
'title' => $dt),
|
||||||
|
common_date_string($this->message->created));
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
|
||||||
|
if ($this->message->source) {
|
||||||
|
$this->out->elementStart('span', 'source');
|
||||||
|
// FIXME: bad i18n. Device should be a parameter (from %s).
|
||||||
|
$this->out->text(_('from'));
|
||||||
|
$this->showSource($this->message->source);
|
||||||
|
$this->out->elementEnd('span');
|
||||||
|
}
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the source of the message
|
||||||
|
*
|
||||||
|
* Returns either the name (and link) of the API client that posted the notice,
|
||||||
|
* or one of other other channels.
|
||||||
|
*
|
||||||
|
* @param string $source the source of the message
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function showSource($source)
|
||||||
|
{
|
||||||
|
$source_name = _($source);
|
||||||
|
switch ($source) {
|
||||||
|
case 'web':
|
||||||
|
case 'xmpp':
|
||||||
|
case 'mail':
|
||||||
|
case 'omb':
|
||||||
|
case 'api':
|
||||||
|
$this->out->element('span', 'device', $source_name);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$ns = Notice_source::staticGet($source);
|
||||||
|
if ($ns) {
|
||||||
|
$this->out->elementStart('span', 'device');
|
||||||
|
$this->out->element('a', array('href' => $ns->url,
|
||||||
|
'rel' => 'external'),
|
||||||
|
$ns->name);
|
||||||
|
$this->out->elementEnd('span');
|
||||||
|
} else {
|
||||||
|
$this->out->element('span', 'device', $source_name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the profile to show in the message item
|
||||||
|
*
|
||||||
|
* Overridden in sub-classes to show sender, receiver, or whatever
|
||||||
|
*
|
||||||
|
* @return Profile profile to show avatar and name of
|
||||||
|
*/
|
||||||
|
abstract function getMessageProfile();
|
||||||
|
}
|
@ -111,10 +111,15 @@ class Plugin
|
|||||||
$this->log(LOG_DEBUG, $msg);
|
$this->log(LOG_DEBUG, $msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPluginVersion(&$versions)
|
function name()
|
||||||
{
|
{
|
||||||
$cls = get_class($this);
|
$cls = get_class($this);
|
||||||
$name = mb_substr($cls, 0, -6);
|
return mb_substr($cls, 0, -6);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPluginVersion(&$versions)
|
||||||
|
{
|
||||||
|
$name = $this->name();
|
||||||
|
|
||||||
$versions[] = array('name' => $name,
|
$versions[] = array('name' => $name,
|
||||||
// TRANS: Displayed as version information for a plugin if no version information was found.
|
// TRANS: Displayed as version information for a plugin if no version information was found.
|
||||||
@ -122,4 +127,39 @@ class Plugin
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function path($relative)
|
||||||
|
{
|
||||||
|
return self::staticPath($this->name(), $relative);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function staticPath($plugin, $relative)
|
||||||
|
{
|
||||||
|
$isHTTPS = StatusNet::isHTTPS();
|
||||||
|
|
||||||
|
if ($isHTTPS) {
|
||||||
|
$server = common_config('plugins', 'sslserver');
|
||||||
|
} else {
|
||||||
|
$server = common_config('plugins', 'server');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($server)) {
|
||||||
|
if ($isHTTPS) {
|
||||||
|
$server = common_config('site', 'sslserver');
|
||||||
|
}
|
||||||
|
if (empty($server)) {
|
||||||
|
$server = common_config('site', 'server');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = common_config('plugins', 'path');
|
||||||
|
|
||||||
|
if (empty($path)) {
|
||||||
|
$path = common_config('site', 'path') . '/plugins/';
|
||||||
|
}
|
||||||
|
|
||||||
|
$protocol = ($isHTTPS) ? 'https' : 'http';
|
||||||
|
|
||||||
|
return $protocol.'://'.$server.$path.$plugin.'/'.$relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
37
lib/util.php
37
lib/util.php
@ -2184,3 +2184,40 @@ function common_nicknamize($str)
|
|||||||
$str = preg_replace('/\W/', '', $str);
|
$str = preg_replace('/\W/', '', $str);
|
||||||
return strtolower($str);
|
return strtolower($str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function common_perf_counter($key, $val=null)
|
||||||
|
{
|
||||||
|
global $_perfCounters;
|
||||||
|
if (isset($_perfCounters)) {
|
||||||
|
if (common_config('site', 'logperf')) {
|
||||||
|
if (array_key_exists($key, $_perfCounters)) {
|
||||||
|
$_perfCounters[$key][] = $val;
|
||||||
|
} else {
|
||||||
|
$_perfCounters[$key] = array($val);
|
||||||
|
}
|
||||||
|
if (common_config('site', 'logperf_detail')) {
|
||||||
|
common_log(LOG_DEBUG, "PERF COUNTER HIT: $key $val");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function common_log_perf_counters()
|
||||||
|
{
|
||||||
|
if (common_config('site', 'logperf')) {
|
||||||
|
global $_startTime, $_perfCounters;
|
||||||
|
|
||||||
|
if (isset($_startTime)) {
|
||||||
|
$endTime = microtime(true);
|
||||||
|
$diff = round(($endTime - $_startTime) * 1000);
|
||||||
|
common_log(LOG_DEBUG, "PERF runtime: ${diff}ms");
|
||||||
|
}
|
||||||
|
$counters = $_perfCounters;
|
||||||
|
ksort($counters);
|
||||||
|
foreach ($counters as $key => $values) {
|
||||||
|
$count = count($values);
|
||||||
|
$unique = count(array_unique($values));
|
||||||
|
common_log(LOG_DEBUG, "PERF COUNTER: $key $count ($unique unique)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -51,15 +51,15 @@ class AutocompletePlugin extends Plugin
|
|||||||
|
|
||||||
function onEndShowScripts($action){
|
function onEndShowScripts($action){
|
||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$action->script('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js');
|
$action->script($this->path('jquery-autocomplete/jquery.autocomplete.pack.js'));
|
||||||
$action->script('plugins/Autocomplete/Autocomplete.js');
|
$action->script($this->path('Autocomplete.js'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowStatusNetStyles($action)
|
function onEndShowStatusNetStyles($action)
|
||||||
{
|
{
|
||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$action->cssLink('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.css');
|
$action->cssLink($this->path('jquery-autocomplete/jquery.autocomplete.css'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ class BlankAdPlugin extends UAPPlugin
|
|||||||
$action->element('img',
|
$action->element('img',
|
||||||
array('width' => 300,
|
array('width' => 300,
|
||||||
'height' => 250,
|
'height' => 250,
|
||||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
'src' => $this->path('redpixel.png')),
|
||||||
'');
|
'');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class BlankAdPlugin extends UAPPlugin
|
|||||||
$action->element('img',
|
$action->element('img',
|
||||||
array('width' => 180,
|
array('width' => 180,
|
||||||
'height' => 150,
|
'height' => 150,
|
||||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
'src' => $this->path('redpixel.png')),
|
||||||
'');
|
'');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ class BlankAdPlugin extends UAPPlugin
|
|||||||
$action->element('img',
|
$action->element('img',
|
||||||
array('width' => 160,
|
array('width' => 160,
|
||||||
'height' => 600,
|
'height' => 600,
|
||||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
'src' => $this->path('redpixel.png')),
|
||||||
'');
|
'');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ class BlankAdPlugin extends UAPPlugin
|
|||||||
$action->element('img',
|
$action->element('img',
|
||||||
array('width' => 728,
|
array('width' => 728,
|
||||||
'height' => 90,
|
'height' => 90,
|
||||||
'src' => common_path('plugins/BlankAd/redpixel.png')),
|
'src' => $this->path('redpixel.png')),
|
||||||
'');
|
'');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ class BookmarkPlugin extends Plugin
|
|||||||
|
|
||||||
function onEndShowStyles($action)
|
function onEndShowStyles($action)
|
||||||
{
|
{
|
||||||
$action->cssLink('plugins/Bookmark/bookmark.css');
|
$action->cssLink($this->path('bookmark.css'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,6 @@ class BookmarkpopupAction extends NewbookmarkAction
|
|||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
$this->script(common_path('plugins/Bookmark/bookmarkpopup.js'));
|
$this->script(Plugin::staticPath('Bookmark', 'bookmarkpopup.js'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ class ClientSideShortenPlugin extends Plugin
|
|||||||
function onEndShowScripts($action){
|
function onEndShowScripts($action){
|
||||||
$action->inlineScript('var Notice_maxContent = ' . Notice::maxContent());
|
$action->inlineScript('var Notice_maxContent = ' . Notice::maxContent());
|
||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$action->script('plugins/ClientSideShorten/shorten.js');
|
$action->script($this->path('shorten.js'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ class DirectionDetectorPlugin extends Plugin {
|
|||||||
*/
|
*/
|
||||||
function onEndShowScripts($action){
|
function onEndShowScripts($action){
|
||||||
if (common_logged_in()) {
|
if (common_logged_in()) {
|
||||||
$action->script('plugins/DirectionDetector/jquery.DirectionDetector.js');
|
$action->script($this->path('jquery.DirectionDetector.js'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* @category Pugin
|
* @category Pugin
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Zach Copley <zach@status.net>
|
* @author Zach Copley <zach@status.net>
|
||||||
* @copyright 2010 StatusNet, Inc.
|
* @copyright 2011 StatusNet, Inc.
|
||||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
* @link http://status.net/
|
* @link http://status.net/
|
||||||
*/
|
*/
|
||||||
@ -47,8 +47,9 @@ define("FACEBOOK_SERVICE", 2);
|
|||||||
*/
|
*/
|
||||||
class FacebookBridgePlugin extends Plugin
|
class FacebookBridgePlugin extends Plugin
|
||||||
{
|
{
|
||||||
public $appId = null; // Facebook application ID
|
public $appId; // Facebook application ID
|
||||||
public $secret = null; // Facebook application secret
|
public $secret; // Facebook application secret
|
||||||
|
|
||||||
public $facebook = null; // Facebook application instance
|
public $facebook = null; // Facebook application instance
|
||||||
public $dir = null; // Facebook plugin dir
|
public $dir = null; // Facebook plugin dir
|
||||||
|
|
||||||
@ -61,6 +62,28 @@ class FacebookBridgePlugin extends Plugin
|
|||||||
*/
|
*/
|
||||||
function initialize()
|
function initialize()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
// Allow the id and key to be passed in
|
||||||
|
// Control panel will override
|
||||||
|
|
||||||
|
if (isset($this->appId)) {
|
||||||
|
$appId = common_config('facebook', 'appid');
|
||||||
|
if (empty($appId)) {
|
||||||
|
Config::save(
|
||||||
|
'facebook',
|
||||||
|
'appid',
|
||||||
|
$this->appId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($this->secret)) {
|
||||||
|
$secret = common_config('facebook', 'secret');
|
||||||
|
if (empty($secret)) {
|
||||||
|
Config::save('facebook', 'secret', $this->secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->facebook = Facebookclient::getFacebook(
|
$this->facebook = Facebookclient::getFacebook(
|
||||||
$this->appId,
|
$this->appId,
|
||||||
$this->secret
|
$this->secret
|
||||||
|
@ -89,10 +89,7 @@ class FacebookloginAction extends Action
|
|||||||
);
|
);
|
||||||
|
|
||||||
$attrs = array(
|
$attrs = array(
|
||||||
'src' => common_path(
|
'src' => Plugin::staticPath('FacebookBridge', 'images/login-button.png'),
|
||||||
'plugins/FacebookBridge/images/login-button.png',
|
|
||||||
true
|
|
||||||
),
|
|
||||||
'alt' => 'Login with Facebook',
|
'alt' => 'Login with Facebook',
|
||||||
'title' => 'Login with Facebook'
|
'title' => 'Login with Facebook'
|
||||||
);
|
);
|
||||||
|
@ -115,14 +115,7 @@ class Facebookclient
|
|||||||
function isFacebookBound() {
|
function isFacebookBound() {
|
||||||
|
|
||||||
if (empty($this->flink)) {
|
if (empty($this->flink)) {
|
||||||
common_log(
|
// User hasn't setup bridging
|
||||||
LOG_WARN,
|
|
||||||
sprintf(
|
|
||||||
"No Foreign_link to Facebook for the author of notice %d.",
|
|
||||||
$this->notice->id
|
|
||||||
),
|
|
||||||
__FILE__
|
|
||||||
);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,15 +173,6 @@ class Facebookclient
|
|||||||
// Otherwise we most likely have an access token
|
// Otherwise we most likely have an access token
|
||||||
return $this->sendGraph();
|
return $this->sendGraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
common_debug(
|
|
||||||
sprintf(
|
|
||||||
"Skipping notice %d - not bound for Facebook",
|
|
||||||
$this->notice->id,
|
|
||||||
__FILE__
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
505
plugins/GroupPrivateMessage/GroupPrivateMessagePlugin.php
Normal file
505
plugins/GroupPrivateMessage/GroupPrivateMessagePlugin.php
Normal file
@ -0,0 +1,505 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Private groups for StatusNet 0.9.x
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 Privacy
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Private groups
|
||||||
|
*
|
||||||
|
* This plugin allows users to send private messages to a group.
|
||||||
|
*
|
||||||
|
* @category Privacy
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GroupPrivateMessagePlugin extends Plugin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Database schema setup
|
||||||
|
*
|
||||||
|
* @see Schema
|
||||||
|
* @see ColumnDef
|
||||||
|
*
|
||||||
|
* @return boolean hook value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onCheckSchema()
|
||||||
|
{
|
||||||
|
$schema = Schema::get();
|
||||||
|
|
||||||
|
// For storing user-submitted flags on profiles
|
||||||
|
|
||||||
|
$schema->ensureTable('group_privacy_settings',
|
||||||
|
array(new ColumnDef('group_id',
|
||||||
|
'integer',
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
'PRI'),
|
||||||
|
new ColumnDef('allow_privacy',
|
||||||
|
'integer'),
|
||||||
|
new ColumnDef('allow_sender',
|
||||||
|
'integer'),
|
||||||
|
new ColumnDef('created',
|
||||||
|
'datetime'),
|
||||||
|
new ColumnDef('modified',
|
||||||
|
'timestamp')));
|
||||||
|
|
||||||
|
$schema->ensureTable('group_message',
|
||||||
|
array(new ColumnDef('id',
|
||||||
|
'char',
|
||||||
|
36,
|
||||||
|
false,
|
||||||
|
'PRI'),
|
||||||
|
new ColumnDef('uri',
|
||||||
|
'varchar',
|
||||||
|
255,
|
||||||
|
false,
|
||||||
|
'UNI'),
|
||||||
|
new ColumnDef('from_profile',
|
||||||
|
'integer',
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
'MUL'),
|
||||||
|
new ColumnDef('to_group',
|
||||||
|
'integer',
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
'MUL'),
|
||||||
|
new ColumnDef('content',
|
||||||
|
'text'),
|
||||||
|
new ColumnDef('rendered',
|
||||||
|
'text'),
|
||||||
|
new ColumnDef('url',
|
||||||
|
'varchar',
|
||||||
|
255,
|
||||||
|
false,
|
||||||
|
'UNI'),
|
||||||
|
new ColumnDef('created',
|
||||||
|
'datetime')));
|
||||||
|
|
||||||
|
$schema->ensureTable('group_message_profile',
|
||||||
|
array(new ColumnDef('to_profile',
|
||||||
|
'integer',
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
'PRI'),
|
||||||
|
new ColumnDef('group_message_id',
|
||||||
|
'char',
|
||||||
|
36,
|
||||||
|
false,
|
||||||
|
'PRI'),
|
||||||
|
new ColumnDef('created',
|
||||||
|
'datetime')));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load related modules when needed
|
||||||
|
*
|
||||||
|
* @param string $cls Name of the class to be loaded
|
||||||
|
*
|
||||||
|
* @return boolean hook value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onAutoload($cls)
|
||||||
|
{
|
||||||
|
$dir = dirname(__FILE__);
|
||||||
|
|
||||||
|
switch ($cls)
|
||||||
|
{
|
||||||
|
case 'GroupinboxAction':
|
||||||
|
case 'ShowgroupmessageAction':
|
||||||
|
case 'NewgroupmessageAction':
|
||||||
|
include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
|
||||||
|
return false;
|
||||||
|
case 'Group_privacy_settings':
|
||||||
|
case 'Group_message':
|
||||||
|
case 'Group_message_profile':
|
||||||
|
include_once $dir . '/'.$cls.'.php';
|
||||||
|
return false;
|
||||||
|
case 'GroupMessageCommand':
|
||||||
|
case 'GroupMessageList':
|
||||||
|
case 'GroupMessageListItem':
|
||||||
|
case 'GroupMessageForm':
|
||||||
|
include_once $dir . '/'.strtolower($cls).'.php';
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map URLs to actions
|
||||||
|
*
|
||||||
|
* @param Net_URL_Mapper $m path-to-action mapper
|
||||||
|
*
|
||||||
|
* @return boolean hook value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onRouterInitialized($m)
|
||||||
|
{
|
||||||
|
$m->connect('group/:nickname/inbox',
|
||||||
|
array('action' => 'groupinbox'),
|
||||||
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
|
$m->connect('group/message/:id',
|
||||||
|
array('action' => 'showgroupmessage'),
|
||||||
|
array('id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'));
|
||||||
|
|
||||||
|
$m->connect('group/:nickname/message/new',
|
||||||
|
array('action' => 'newgroupmessage'),
|
||||||
|
array('nickname' => Nickname::DISPLAY_FMT));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add group inbox to the menu
|
||||||
|
*
|
||||||
|
* @param Action $action The current action handler. Use this to
|
||||||
|
* do any output.
|
||||||
|
*
|
||||||
|
* @return boolean hook value; true means continue processing, false means stop.
|
||||||
|
*
|
||||||
|
* @see Action
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onEndGroupGroupNav($groupnav)
|
||||||
|
{
|
||||||
|
$action = $groupnav->action;
|
||||||
|
$group = $groupnav->group;
|
||||||
|
|
||||||
|
$action->menuItem(common_local_url('groupinbox',
|
||||||
|
array('nickname' => $group->nickname)),
|
||||||
|
_m('Inbox'),
|
||||||
|
_m('Private messages for this group'),
|
||||||
|
$action->trimmed('action') == 'groupinbox',
|
||||||
|
'nav_group_inbox');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create default group privacy settings at group create time
|
||||||
|
*
|
||||||
|
* @param User_group $group Group that was just created
|
||||||
|
*
|
||||||
|
* @result boolean hook value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onEndGroupSave($group)
|
||||||
|
{
|
||||||
|
$gps = new Group_privacy_settings();
|
||||||
|
|
||||||
|
$gps->group_id = $group->id;
|
||||||
|
$gps->allow_privacy = Group_privacy_settings::SOMETIMES;
|
||||||
|
$gps->allow_sender = Group_privacy_settings::MEMBER;
|
||||||
|
$gps->created = common_sql_now();
|
||||||
|
$gps->modified = $gps->created;
|
||||||
|
|
||||||
|
// This will throw an exception on error
|
||||||
|
|
||||||
|
$gps->insert();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show group privacy controls on group edit form
|
||||||
|
*
|
||||||
|
* @param GroupEditForm $form form being shown
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onEndGroupEditFormData($form)
|
||||||
|
{
|
||||||
|
$gps = null;
|
||||||
|
|
||||||
|
if (!empty($form->group)) {
|
||||||
|
$gps = Group_privacy_settings::staticGet('group_id', $form->group->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->out->elementStart('li');
|
||||||
|
$form->out->dropdown('allow_privacy',
|
||||||
|
_('Private messages'),
|
||||||
|
array(Group_privacy_settings::SOMETIMES => _('Sometimes'),
|
||||||
|
Group_privacy_settings::ALWAYS => _('Always'),
|
||||||
|
Group_privacy_settings::NEVER => _('Never')),
|
||||||
|
_('Whether to allow private messages to this group'),
|
||||||
|
false,
|
||||||
|
(empty($gps)) ? Group_privacy_settings::SOMETIMES : $gps->allow_privacy);
|
||||||
|
$form->out->elementEnd('li');
|
||||||
|
$form->out->elementStart('li');
|
||||||
|
$form->out->dropdown('allow_sender',
|
||||||
|
_('Private sender'),
|
||||||
|
array(Group_privacy_settings::EVERYONE => _('Everyone'),
|
||||||
|
Group_privacy_settings::MEMBER => _('Member'),
|
||||||
|
Group_privacy_settings::ADMIN => _('Admin')),
|
||||||
|
_('Who can send private messages to the group'),
|
||||||
|
false,
|
||||||
|
(empty($gps)) ? Group_privacy_settings::MEMBER : $gps->allow_sender);
|
||||||
|
$form->out->elementEnd('li');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEndGroupSaveForm($action)
|
||||||
|
{
|
||||||
|
$gps = null;
|
||||||
|
|
||||||
|
if (!empty($action->group)) {
|
||||||
|
$gps = Group_privacy_settings::staticGet('group_id', $action->group->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$orig = null;
|
||||||
|
|
||||||
|
if (empty($gps)) {
|
||||||
|
$gps = new Group_privacy_settings();
|
||||||
|
$gps->group_id = $action->group->id;
|
||||||
|
} else {
|
||||||
|
$orig = clone($gps);
|
||||||
|
}
|
||||||
|
|
||||||
|
$gps->allow_privacy = $action->trimmed('allow_privacy');
|
||||||
|
$gps->allow_sender = $action->trimmed('allow_sender');
|
||||||
|
|
||||||
|
if (empty($orig)) {
|
||||||
|
$gps->created = common_sql_now();
|
||||||
|
$gps->insert();
|
||||||
|
} else {
|
||||||
|
$gps->update($orig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overload 'd' command to send private messages to groups.
|
||||||
|
*
|
||||||
|
* 'd !group word word word' will send the private message
|
||||||
|
* 'word word word' to the group 'group'.
|
||||||
|
*
|
||||||
|
* @param string $cmd Command being run
|
||||||
|
* @param string $arg Rest of the message (including address)
|
||||||
|
* @param User $user User sending the message
|
||||||
|
* @param Command &$result The resulting command object to be run.
|
||||||
|
*
|
||||||
|
* @return boolean hook value
|
||||||
|
*/
|
||||||
|
function onStartIntepretCommand($cmd, $arg, $user, &$result)
|
||||||
|
{
|
||||||
|
if ($cmd == 'd' || $cmd == 'dm') {
|
||||||
|
|
||||||
|
$this->debug('Got a d command');
|
||||||
|
|
||||||
|
// Break off the first word as the address
|
||||||
|
|
||||||
|
$pieces = explode(' ', $arg, 2);
|
||||||
|
|
||||||
|
if (count($pieces) == 1) {
|
||||||
|
$pieces[] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
list($addr, $msg) = $pieces;
|
||||||
|
|
||||||
|
if (!empty($addr) && $addr[0] == '!') {
|
||||||
|
$result = new GroupMessageCommand($user, substr($addr, 1), $msg);
|
||||||
|
Event::handle('EndInterpretCommand', array($cmd, $arg, $user, $result));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To add a "Message" button to the group profile page
|
||||||
|
*
|
||||||
|
* @param Action $action The showgroup action being shown
|
||||||
|
* @param User_group $group The current group
|
||||||
|
*
|
||||||
|
* @return boolean hook value
|
||||||
|
*/
|
||||||
|
function onEndGroupActionsList($action, $group)
|
||||||
|
{
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
if (empty($cur)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Group_privacy_settings::ensurePost($cur, $group);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$action->elementStart('li', 'entity_send-a-message');
|
||||||
|
$action->element('a', array('href' => common_local_url('newgroupmessage', array('nickname' => $group->nickname)),
|
||||||
|
'title' => _('Send a direct message to this group')),
|
||||||
|
_('Message'));
|
||||||
|
// $form = new GroupMessageForm($action, $group);
|
||||||
|
// $form->hidden = true;
|
||||||
|
// $form->show();
|
||||||
|
$action->elementEnd('li');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When saving a notice, check its groups. If any of them has
|
||||||
|
* privacy == always, force a group private message to all mentioned groups.
|
||||||
|
* If any of the groups disallows private messages, skip it.
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onStartNoticeSave(&$notice) {
|
||||||
|
|
||||||
|
// Look for group tags
|
||||||
|
// FIXME: won't work for remote groups
|
||||||
|
// @fixme if Notice::saveNew is refactored so we can just pull its list
|
||||||
|
// of groups between processing and saving, make use of it
|
||||||
|
|
||||||
|
$count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
|
||||||
|
strtolower($notice->content),
|
||||||
|
$match);
|
||||||
|
|
||||||
|
$groups = array();
|
||||||
|
$ignored = array();
|
||||||
|
|
||||||
|
$forcePrivate = false;
|
||||||
|
|
||||||
|
if ($count > 0) {
|
||||||
|
|
||||||
|
/* Add them to the database */
|
||||||
|
|
||||||
|
foreach (array_unique($match[1]) as $nickname) {
|
||||||
|
|
||||||
|
$group = User_group::getForNickname($nickname, $profile);
|
||||||
|
|
||||||
|
if (empty($group)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gps = Group_privacy_settings::forGroup($group);
|
||||||
|
|
||||||
|
switch ($gps->allow_privacy) {
|
||||||
|
case Group_privacy_settings::ALWAYS:
|
||||||
|
$forcePrivate = true;
|
||||||
|
// fall through
|
||||||
|
case Group_privacy_settings::SOMETIMES:
|
||||||
|
$groups[] = $group;
|
||||||
|
break;
|
||||||
|
case Group_privacy_settings::NEVER:
|
||||||
|
$ignored[] = $group;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($forcePrivate) {
|
||||||
|
|
||||||
|
foreach ($ignored as $group) {
|
||||||
|
common_log(LOG_NOTICE,
|
||||||
|
"Notice forced to group direct message ".
|
||||||
|
"but group ".$group->nickname." does not allow them.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$user = User::staticGet('id', $notice->profile_id);
|
||||||
|
|
||||||
|
if (empty($user)) {
|
||||||
|
common_log(LOG_WARNING,
|
||||||
|
"Notice forced to group direct message ".
|
||||||
|
"but profile ".$notice->profile_id." is not a local user.");
|
||||||
|
} else {
|
||||||
|
foreach ($groups as $group) {
|
||||||
|
Group_message::send($user, $group, $notice->content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't save the notice!
|
||||||
|
// FIXME: this is probably cheating.
|
||||||
|
throw new ClientException(sprintf(_('Forced notice to private group message.')),
|
||||||
|
200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an indicator that the group is (essentially) private on the group page
|
||||||
|
*
|
||||||
|
* @param Action $action The action being shown
|
||||||
|
* @param User_group $group The group being shown
|
||||||
|
*
|
||||||
|
* @return boolean hook value
|
||||||
|
*/
|
||||||
|
|
||||||
|
function onEndGroupProfileElements($action, $group)
|
||||||
|
{
|
||||||
|
$gps = Group_privacy_settings::forGroup($group);
|
||||||
|
|
||||||
|
if ($gps->allow_privacy == Group_privacy_settings::ALWAYS) {
|
||||||
|
$action->element('p', 'privategroupindicator', _('Private'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onStartShowExportData($action)
|
||||||
|
{
|
||||||
|
if ($action instanceof ShowgroupAction) {
|
||||||
|
$gps = Group_privacy_settings::forGroup($action->group);
|
||||||
|
|
||||||
|
if ($gps->allow_privacy == Group_privacy_settings::ALWAYS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPluginVersion(&$versions)
|
||||||
|
{
|
||||||
|
$versions[] = array('name' => 'GroupPrivateMessage',
|
||||||
|
'version' => STATUSNET_VERSION,
|
||||||
|
'author' => 'Evan Prodromou',
|
||||||
|
'homepage' => 'http://status.net/wiki/Plugin:GroupPrivateMessage',
|
||||||
|
'rawdescription' =>
|
||||||
|
_m('Allow posting DMs to a group.'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
208
plugins/GroupPrivateMessage/Group_message.php
Normal file
208
plugins/GroupPrivateMessage/Group_message.php
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Data class for group direct messages
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* @category Data
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class for group direct messages
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see DB_DataObject
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Group_message extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
public $__table = 'group_message'; // table name
|
||||||
|
public $id; // char(36) primary_key not_null
|
||||||
|
public $uri; // varchar(255)
|
||||||
|
public $from_profile; // int
|
||||||
|
public $to_group; // int
|
||||||
|
public $content;
|
||||||
|
public $rendered;
|
||||||
|
public $url;
|
||||||
|
public $created;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an instance by key
|
||||||
|
*
|
||||||
|
* This is a utility method to get a single instance with a given key value.
|
||||||
|
*
|
||||||
|
* @param string $k Key to use to lookup (usually 'user_id' for this class)
|
||||||
|
* @param mixed $v Value to lookup
|
||||||
|
*
|
||||||
|
* @return Group_message object found, or null for no hits
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function staticGet($k, $v=null)
|
||||||
|
{
|
||||||
|
return Memcached_DataObject::staticGet('Group_message', $k, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return table definition for DB_DataObject
|
||||||
|
*
|
||||||
|
* DB_DataObject needs to know something about the table to manipulate
|
||||||
|
* instances. This method provides all the DB_DataObject needs to know.
|
||||||
|
*
|
||||||
|
* @return array array of column definitions
|
||||||
|
*/
|
||||||
|
function table()
|
||||||
|
{
|
||||||
|
return array('id' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'uri' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'from_profile' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'to_group' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'content' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'rendered' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'url' => DB_DATAOBJECT_STR,
|
||||||
|
'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return key definitions for DB_DataObject
|
||||||
|
*
|
||||||
|
* DB_DataObject needs to know about keys that the table has, since it
|
||||||
|
* won't appear in StatusNet's own keys list. In most cases, this will
|
||||||
|
* simply reference your keyTypes() function.
|
||||||
|
*
|
||||||
|
* @return array list of key field names
|
||||||
|
*/
|
||||||
|
function keys()
|
||||||
|
{
|
||||||
|
return array_keys($this->keyTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return key definitions for Memcached_DataObject
|
||||||
|
*
|
||||||
|
* @return array associative array of key definitions, field name to type:
|
||||||
|
* 'K' for primary key: for compound keys, add an entry for each component;
|
||||||
|
* 'U' for unique keys: compound keys are not well supported here.
|
||||||
|
*/
|
||||||
|
function keyTypes()
|
||||||
|
{
|
||||||
|
return array('id' => 'K', 'uri' => 'U');
|
||||||
|
}
|
||||||
|
|
||||||
|
static function send($user, $group, $text)
|
||||||
|
{
|
||||||
|
if (!$user->hasRight(Right::NEWMESSAGE)) {
|
||||||
|
// XXX: maybe break this out into a separate right
|
||||||
|
throw new Exception(sprintf(_('User %s not allowed to send private messages.'),
|
||||||
|
$user->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
Group_privacy_settings::ensurePost($user, $group);
|
||||||
|
|
||||||
|
$text = $user->shortenLinks($text);
|
||||||
|
|
||||||
|
// We use the same limits as for 'regular' private messages.
|
||||||
|
|
||||||
|
if (Message::contentTooLong($text)) {
|
||||||
|
throw new Exception(sprintf(_m('That\'s too long. Maximum message size is %d character.',
|
||||||
|
'That\'s too long. Maximum message size is %d characters.',
|
||||||
|
Message::maxContent()),
|
||||||
|
Message::maxContent()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid! Let's do this thing!
|
||||||
|
|
||||||
|
$gm = new Group_message();
|
||||||
|
|
||||||
|
$gm->id = UUID::gen();
|
||||||
|
$gm->uri = common_local_url('showgroupmessage', array('id' => $gm->id));
|
||||||
|
$gm->from_profile = $user->id;
|
||||||
|
$gm->to_group = $group->id;
|
||||||
|
$gm->content = $text; // XXX: is this cool?!
|
||||||
|
$gm->rendered = common_render_text($text);
|
||||||
|
$gm->url = $gm->uri;
|
||||||
|
$gm->created = common_sql_now();
|
||||||
|
|
||||||
|
// This throws a conniption if there's a problem
|
||||||
|
|
||||||
|
$gm->insert();
|
||||||
|
|
||||||
|
$gm->distribute();
|
||||||
|
|
||||||
|
return $gm;
|
||||||
|
}
|
||||||
|
|
||||||
|
function distribute()
|
||||||
|
{
|
||||||
|
$group = User_group::staticGet('id', $this->to_group);
|
||||||
|
|
||||||
|
$member = $group->getMembers();
|
||||||
|
|
||||||
|
while ($member->fetch()) {
|
||||||
|
Group_message_profile::send($this, $member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getGroup()
|
||||||
|
{
|
||||||
|
$group = User_group::staticGet('id', $this->to_group);
|
||||||
|
if (empty($group)) {
|
||||||
|
throw new ServerException(_('No group for group message'));
|
||||||
|
}
|
||||||
|
return $group;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSender()
|
||||||
|
{
|
||||||
|
$sender = Profile::staticGet('id', $this->from_profile);
|
||||||
|
if (empty($sender)) {
|
||||||
|
throw new ServerException(_('No sender for group message'));
|
||||||
|
}
|
||||||
|
return $sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function forGroup($group, $offset, $limit)
|
||||||
|
{
|
||||||
|
// XXX: cache
|
||||||
|
$gm = new Group_message();
|
||||||
|
|
||||||
|
$gm->to_group = $group->id;
|
||||||
|
$gm->orderBy('created DESC');
|
||||||
|
$gm->limit($offset, $limit);
|
||||||
|
|
||||||
|
$gm->find();
|
||||||
|
|
||||||
|
return $gm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
189
plugins/GroupPrivateMessage/Group_message_profile.php
Normal file
189
plugins/GroupPrivateMessage/Group_message_profile.php
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Who received a group message
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* @category Data
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
require_once INSTALLDIR . '/classes/Memcached_DataObject.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class for group direct messages for users
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see DB_DataObject
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Group_message_profile extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
public $__table = 'group_message_profile'; // table name
|
||||||
|
public $to_profile; // int
|
||||||
|
public $group_message_id; // char(36) primary_key not_null
|
||||||
|
public $created;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an instance by key
|
||||||
|
*
|
||||||
|
* This is a utility method to get a single instance with a given key value.
|
||||||
|
*
|
||||||
|
* @param string $k Key to use to lookup (usually 'user_id' for this class)
|
||||||
|
* @param mixed $v Value to lookup
|
||||||
|
*
|
||||||
|
* @return Group_message object found, or null for no hits
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function staticGet($k, $v=null)
|
||||||
|
{
|
||||||
|
return Memcached_DataObject::staticGet('Group_message_profile', $k, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return table definition for DB_DataObject
|
||||||
|
*
|
||||||
|
* DB_DataObject needs to know something about the table to manipulate
|
||||||
|
* instances. This method provides all the DB_DataObject needs to know.
|
||||||
|
*
|
||||||
|
* @return array array of column definitions
|
||||||
|
*/
|
||||||
|
function table()
|
||||||
|
{
|
||||||
|
return array('to_profile' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'group_message_id' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return key definitions for DB_DataObject
|
||||||
|
*
|
||||||
|
* DB_DataObject needs to know about keys that the table has, since it
|
||||||
|
* won't appear in StatusNet's own keys list. In most cases, this will
|
||||||
|
* simply reference your keyTypes() function.
|
||||||
|
*
|
||||||
|
* @return array list of key field names
|
||||||
|
*/
|
||||||
|
function keys()
|
||||||
|
{
|
||||||
|
return array_keys($this->keyTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return key definitions for Memcached_DataObject
|
||||||
|
*
|
||||||
|
* @return array associative array of key definitions, field name to type:
|
||||||
|
* 'K' for primary key: for compound keys, add an entry for each component;
|
||||||
|
* 'U' for unique keys: compound keys are not well supported here.
|
||||||
|
*/
|
||||||
|
function keyTypes()
|
||||||
|
{
|
||||||
|
return array('to_profile' => 'K', 'group_message_id' => 'K');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No sequence keys in this table.
|
||||||
|
*/
|
||||||
|
function sequenceKey()
|
||||||
|
{
|
||||||
|
return array(false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function send($gm, $profile)
|
||||||
|
{
|
||||||
|
$gmp = new Group_message_profile();
|
||||||
|
|
||||||
|
$gmp->group_message_id = $gm->id;
|
||||||
|
$gmp->to_profile = $profile->id;
|
||||||
|
$gmp->created = common_sql_now();
|
||||||
|
|
||||||
|
$gmp->insert();
|
||||||
|
|
||||||
|
$gmp->notify();
|
||||||
|
|
||||||
|
return $gmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function notify()
|
||||||
|
{
|
||||||
|
// XXX: add more here
|
||||||
|
$this->notifyByMail();
|
||||||
|
}
|
||||||
|
|
||||||
|
function notifyByMail()
|
||||||
|
{
|
||||||
|
$to = User::staticGet('id', $this->to_profile);
|
||||||
|
|
||||||
|
if (empty($to) || is_null($to->email) || !$to->emailnotifymsg) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gm = Group_message::staticGet('id', $this->group_message_id);
|
||||||
|
|
||||||
|
$from_profile = Profile::staticGet('id', $gm->from_profile);
|
||||||
|
|
||||||
|
$group = $gm->getGroup();
|
||||||
|
|
||||||
|
common_switch_locale($to->language);
|
||||||
|
|
||||||
|
// TRANS: Subject for direct-message notification email.
|
||||||
|
// TRANS: %s is the sending user's nickname.
|
||||||
|
$subject = sprintf(_('New private message from %s to group %s'), $from->nickname, $group->nickname);
|
||||||
|
|
||||||
|
$from_profile = $from->getProfile();
|
||||||
|
|
||||||
|
// TRANS: Body for direct-message notification email.
|
||||||
|
// TRANS: %1$s is the sending user's long name, %2$s is the sending user's nickname,
|
||||||
|
// TRANS: %3$s is the message content, %4$s a URL to the message,
|
||||||
|
// TRANS: %5$s is the StatusNet sitename.
|
||||||
|
$body = sprintf(_("%1\$s (%2\$s) sent a private message to group %3\$s:\n\n".
|
||||||
|
"------------------------------------------------------\n".
|
||||||
|
"%4\$s\n".
|
||||||
|
"------------------------------------------------------\n\n".
|
||||||
|
"You can reply to their message here:\n\n".
|
||||||
|
"%5\$s\n\n".
|
||||||
|
"Don't reply to this email; it won't get to them.\n\n".
|
||||||
|
"With kind regards,\n".
|
||||||
|
"%6\$s\n"),
|
||||||
|
$from_profile->getBestName(),
|
||||||
|
$from->nickname,
|
||||||
|
$group->nickname,
|
||||||
|
$this->content,
|
||||||
|
common_local_url('newmessage', array('to' => $from->id)),
|
||||||
|
common_config('site', 'name'));
|
||||||
|
|
||||||
|
$headers = _mail_prepare_headers('message', $to->nickname, $from->nickname);
|
||||||
|
|
||||||
|
common_switch_locale();
|
||||||
|
|
||||||
|
return mail_to_user($to, $subject, $body, $headers);
|
||||||
|
}
|
||||||
|
}
|
201
plugins/GroupPrivateMessage/Group_privacy_settings.php
Normal file
201
plugins/GroupPrivateMessage/Group_privacy_settings.php
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Data class for group privacy settings
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* @category Data
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, 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')) {
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class for group privacy
|
||||||
|
*
|
||||||
|
* Stores admin preferences about the group.
|
||||||
|
*
|
||||||
|
* @category Action
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
|
||||||
|
* @link http://status.net/
|
||||||
|
*
|
||||||
|
* @see DB_DataObject
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Group_privacy_settings extends Memcached_DataObject
|
||||||
|
{
|
||||||
|
public $__table = 'group_privacy_settings';
|
||||||
|
/** ID of the group. */
|
||||||
|
public $group_id;
|
||||||
|
/** When to allow privacy: always, sometimes, or never. */
|
||||||
|
public $allow_privacy;
|
||||||
|
/** Who can send private messages: everyone, member, admin */
|
||||||
|
public $allow_sender;
|
||||||
|
/** row creation timestamp */
|
||||||
|
public $created;
|
||||||
|
/** Last-modified timestamp */
|
||||||
|
public $modified;
|
||||||
|
|
||||||
|
/** NEVER is */
|
||||||
|
|
||||||
|
const SOMETIMES = -1;
|
||||||
|
const NEVER = 0;
|
||||||
|
const ALWAYS = 1;
|
||||||
|
|
||||||
|
/** These are bit-mappy, as a hedge against the future. */
|
||||||
|
|
||||||
|
const EVERYONE = 1;
|
||||||
|
const MEMBER = 2;
|
||||||
|
const ADMIN = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an instance by key
|
||||||
|
*
|
||||||
|
* This is a utility method to get a single instance with a given key value.
|
||||||
|
*
|
||||||
|
* @param string $k Key to use to lookup (usually 'user_id' for this class)
|
||||||
|
* @param mixed $v Value to lookup
|
||||||
|
*
|
||||||
|
* @return User_greeting_count object found, or null for no hits
|
||||||
|
*/
|
||||||
|
|
||||||
|
function staticGet($k, $v=null)
|
||||||
|
{
|
||||||
|
return Memcached_DataObject::staticGet('Group_privacy_settings', $k, $v);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return table definition for DB_DataObject
|
||||||
|
*
|
||||||
|
* DB_DataObject needs to know something about the table to manipulate
|
||||||
|
* instances. This method provides all the DB_DataObject needs to know.
|
||||||
|
*
|
||||||
|
* @return array array of column definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
function table()
|
||||||
|
{
|
||||||
|
return array('group_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'allow_privacy' => DB_DATAOBJECT_INT,
|
||||||
|
'allow_sender' => DB_DATAOBJECT_INT,
|
||||||
|
'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL,
|
||||||
|
'modified' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return key definitions for DB_DataObject
|
||||||
|
*
|
||||||
|
* DB_DataObject needs to know about keys that the table has, since it
|
||||||
|
* won't appear in StatusNet's own keys list. In most cases, this will
|
||||||
|
* simply reference your keyTypes() function.
|
||||||
|
*
|
||||||
|
* @return array list of key field names
|
||||||
|
*/
|
||||||
|
|
||||||
|
function keys()
|
||||||
|
{
|
||||||
|
return array_keys($this->keyTypes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return key definitions for Memcached_DataObject
|
||||||
|
*
|
||||||
|
* @return array associative array of key definitions, field name to type:
|
||||||
|
* 'K' for primary key: for compound keys, add an entry for each component;
|
||||||
|
* 'U' for unique keys: compound keys are not well supported here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function keyTypes()
|
||||||
|
{
|
||||||
|
return array('group_id' => 'K');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic formula for non-autoincrementing integer primary keys
|
||||||
|
*
|
||||||
|
* @return array magic three-false array that stops auto-incrementing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function sequenceKey()
|
||||||
|
{
|
||||||
|
return array(false, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function forGroup($group)
|
||||||
|
{
|
||||||
|
$gps = Group_privacy_settings::staticGet('group_id', $group->id);
|
||||||
|
|
||||||
|
if (empty($gps)) {
|
||||||
|
// make a fake one with defaults
|
||||||
|
$gps = new Group_privacy_settings();
|
||||||
|
$gps->allow_privacy = Group_privacy_settings::SOMETIMES;
|
||||||
|
$gps->allow_sender = Group_privacy_settings::MEMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $gps;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensurePost($user, $group)
|
||||||
|
{
|
||||||
|
$gps = self::forGroup($group);
|
||||||
|
|
||||||
|
if ($gps->allow_privacy == Group_privacy_settings::NEVER) {
|
||||||
|
throw new Exception(sprintf(_('Group %s does not allow private messages.'),
|
||||||
|
$group->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($gps->allow_sender) {
|
||||||
|
case Group_privacy_settings::EVERYONE:
|
||||||
|
$profile = $user->getProfile();
|
||||||
|
if (Group_block::isBlocked($group, $profile)) {
|
||||||
|
throw new Exception(sprintf(_('User %s is blocked from group %s.'),
|
||||||
|
$user->nickname,
|
||||||
|
$group->nickname));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Group_privacy_settings::MEMBER:
|
||||||
|
if (!$user->isMember($group)) {
|
||||||
|
throw new Exception(sprintf(_('User %s is not a member of group %s.'),
|
||||||
|
$user->nickname,
|
||||||
|
$group->nickname));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Group_privacy_settings::ADMIN:
|
||||||
|
if (!$user->isAdmin($group)) {
|
||||||
|
throw new Exception(sprintf(_('User %s is not an administrator of group %s.'),
|
||||||
|
$user->nickname,
|
||||||
|
$group->nickname));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception(sprintf(_('Unknown privacy settings for group %s.'),
|
||||||
|
$group->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
208
plugins/GroupPrivateMessage/groupinbox.php
Normal file
208
plugins/GroupPrivateMessage/groupinbox.php
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* List of private messages to this group
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a list of private messages to this group
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GroupinboxAction extends GroupDesignAction
|
||||||
|
{
|
||||||
|
var $gm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For initializing members of the class.
|
||||||
|
*
|
||||||
|
* @param array $argarray misc. arguments
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
function prepare($argarray)
|
||||||
|
{
|
||||||
|
parent::prepare($argarray);
|
||||||
|
|
||||||
|
$cur = common_current_user();
|
||||||
|
|
||||||
|
if (empty($cur)) {
|
||||||
|
throw new ClientException(_('Only for logged-in users'), 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$nicknameArg = $this->trimmed('nickname');
|
||||||
|
|
||||||
|
$nickname = common_canonical_nickname($nicknameArg);
|
||||||
|
|
||||||
|
if ($nickname != $nicknameArg) {
|
||||||
|
$url = common_local_url('groupinbox', array('nickname' => $nickname));
|
||||||
|
common_redirect($url);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$localGroup = Local_group::staticGet('nickname', $nickname);
|
||||||
|
|
||||||
|
if (empty($localGroup)) {
|
||||||
|
throw new ClientException(_('No such group'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->group = User_group::staticGet('id', $localGroup->group_id);
|
||||||
|
|
||||||
|
if (empty($this->group)) {
|
||||||
|
throw new ClientException(_('No such group'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$cur->isMember($this->group)) {
|
||||||
|
throw new ClientException(_('Only for members'), 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->page = $this->trimmed('page');
|
||||||
|
|
||||||
|
if (!$this->page) {
|
||||||
|
$this->page = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->gm = Group_message::forGroup($this->group,
|
||||||
|
($this->page - 1) * MESSAGES_PER_PAGE,
|
||||||
|
MESSAGES_PER_PAGE + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLocalNav()
|
||||||
|
{
|
||||||
|
$nav = new GroupNav($this, $this->group);
|
||||||
|
$nav->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNoticeForm()
|
||||||
|
{
|
||||||
|
$form = new GroupMessageForm($this, $this->group);
|
||||||
|
$form->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$gml = new GroupMessageList($this, $this->gm);
|
||||||
|
$cnt = $gml->show();
|
||||||
|
|
||||||
|
if ($cnt == 0) {
|
||||||
|
$this->element('p', 'guide', _m('This group has not received any private messages.'));
|
||||||
|
}
|
||||||
|
$this->pagination($this->page > 1,
|
||||||
|
$cnt > MESSAGES_PER_PAGE,
|
||||||
|
$this->page,
|
||||||
|
'groupinbox',
|
||||||
|
array('nickname' => $this->group->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler method
|
||||||
|
*
|
||||||
|
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function handle($argarray=null)
|
||||||
|
{
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if read only.
|
||||||
|
*
|
||||||
|
* MAY override
|
||||||
|
*
|
||||||
|
* @param array $args other arguments
|
||||||
|
*
|
||||||
|
* @return boolean is read only action?
|
||||||
|
*/
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*
|
||||||
|
* @return string page title, with page number
|
||||||
|
*/
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
$base = $this->group->getFancyName();
|
||||||
|
|
||||||
|
if ($this->page == 1) {
|
||||||
|
return sprintf(_('%s group inbox'), $base);
|
||||||
|
} else {
|
||||||
|
// TRANS: Page title for any but first group page.
|
||||||
|
// TRANS: %1$s is a group name, $2$s is a page number.
|
||||||
|
return sprintf(_('%1$s group inbox, page %2$d'),
|
||||||
|
$base,
|
||||||
|
$this->page);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the page notice
|
||||||
|
*
|
||||||
|
* Shows instructions for the page
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showPageNotice()
|
||||||
|
{
|
||||||
|
$instr = $this->getInstructions();
|
||||||
|
$output = common_markup_to_html($instr);
|
||||||
|
|
||||||
|
$this->elementStart('div', 'instructions');
|
||||||
|
$this->raw($output);
|
||||||
|
$this->elementEnd('div');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instructions for using this page
|
||||||
|
*
|
||||||
|
* @return string localised instructions for using the page
|
||||||
|
*/
|
||||||
|
function getInstructions()
|
||||||
|
{
|
||||||
|
// TRANS: Instructions for user inbox page.
|
||||||
|
return _m('This is the group inbox, which lists all incoming private messages for this group.');
|
||||||
|
}
|
||||||
|
}
|
85
plugins/GroupPrivateMessage/groupmessagecommand.php
Normal file
85
plugins/GroupPrivateMessage/groupmessagecommand.php
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Command object for messages to groups
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 Command
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command object for messages to groups
|
||||||
|
*
|
||||||
|
* @category General
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GroupMessageCommand extends Command
|
||||||
|
{
|
||||||
|
/** User sending the message. */
|
||||||
|
var $user;
|
||||||
|
/** Nickname of the group they're sending to. */
|
||||||
|
var $nickname;
|
||||||
|
/** Text of the message. */
|
||||||
|
var $text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param User $user User sending the message
|
||||||
|
* @param string $nickname Nickname of the group
|
||||||
|
* @param string $text Text of message
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($user, $nickname, $text)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->nickname = $nickname;
|
||||||
|
$this->text = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handle($channel)
|
||||||
|
{
|
||||||
|
// Throws a command exception if group not found
|
||||||
|
$group = $this->getGroup($this->nickname);
|
||||||
|
|
||||||
|
$gm = Group_message::send($this->user, $group, $this->text);
|
||||||
|
|
||||||
|
$channel->output($this->user,
|
||||||
|
sprintf(_('Direct message to group %s sent.'),
|
||||||
|
$group->nickname));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
166
plugins/GroupPrivateMessage/groupmessageform.php
Normal file
166
plugins/GroupPrivateMessage/groupmessageform.php
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Form for posting a group message
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for posting a group message
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class GroupMessageForm extends Form
|
||||||
|
{
|
||||||
|
var $group;
|
||||||
|
var $content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param HTMLOutputter $out Output context
|
||||||
|
* @param User_group $group Group to post to
|
||||||
|
*
|
||||||
|
* @todo add a drop-down list to post to any group
|
||||||
|
*/
|
||||||
|
|
||||||
|
function __construct($out, $group, $content=null)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
|
||||||
|
$this->group = $group;
|
||||||
|
$this->content = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action for the form
|
||||||
|
*/
|
||||||
|
function action()
|
||||||
|
{
|
||||||
|
return common_local_url('newgroupmessage',
|
||||||
|
array('nickname' => $this->group->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legend for the form
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
function formLegend()
|
||||||
|
{
|
||||||
|
$this->out->element('legend',
|
||||||
|
null,
|
||||||
|
sprintf(_('Message to %s'), $this->group->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* id for the form
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
function id()
|
||||||
|
{
|
||||||
|
return 'form_notice-group-message';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class for the form
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formClass()
|
||||||
|
{
|
||||||
|
return 'form_notice';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry data
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formData()
|
||||||
|
{
|
||||||
|
$this->out->element('label', array('for' => 'notice_data-text',
|
||||||
|
'id' => 'notice_data-text-label'),
|
||||||
|
sprintf(_('Direct message to %s'), $this->group->nickname));
|
||||||
|
|
||||||
|
$this->out->element('textarea', array('id' => 'notice_data-text',
|
||||||
|
'cols' => 35,
|
||||||
|
'rows' => 4,
|
||||||
|
'name' => 'content'),
|
||||||
|
($this->content) ? $this->content : '');
|
||||||
|
|
||||||
|
$contentLimit = Message::maxContent();
|
||||||
|
|
||||||
|
if ($contentLimit > 0) {
|
||||||
|
$this->out->elementStart('dl', 'form_note');
|
||||||
|
$this->out->element('dt', null, _('Available characters'));
|
||||||
|
$this->out->element('dd', array('id' => 'notice_text-count'),
|
||||||
|
$contentLimit);
|
||||||
|
$this->out->elementEnd('dl');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Legend for the form
|
||||||
|
*
|
||||||
|
* @param
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
|
||||||
|
function formActions()
|
||||||
|
{
|
||||||
|
$this->out->element('input', array('id' => 'notice_action-submit',
|
||||||
|
'class' => 'submit',
|
||||||
|
'name' => 'message_send',
|
||||||
|
'type' => 'submit',
|
||||||
|
'value' => _m('Send button for sending notice', 'Send')));
|
||||||
|
}
|
||||||
|
}
|
90
plugins/GroupPrivateMessage/groupmessagelist.php
Normal file
90
plugins/GroupPrivateMessage/groupmessagelist.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Widget for showing list of group messages
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget for showing list of group messages
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
class GroupMessageList extends Widget
|
||||||
|
{
|
||||||
|
var $gm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param HTMLOutputter $out output context
|
||||||
|
* @param Group_message $gm Group message stream
|
||||||
|
*/
|
||||||
|
function __construct($out, $gm)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
$this->gm = $gm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the list
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$this->out->elementStart('ul', 'notices messages group-messages');
|
||||||
|
|
||||||
|
$cnt = 0;
|
||||||
|
|
||||||
|
while ($this->gm->fetch() && $cnt <= MESSAGES_PER_PAGE) {
|
||||||
|
|
||||||
|
$cnt++;
|
||||||
|
|
||||||
|
if ($cnt > MESSAGES_PER_PAGE) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$gmli = new GroupMessageListItem($this->out, $this->gm);
|
||||||
|
$gmli->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->out->elementEnd('ul');
|
||||||
|
|
||||||
|
return $cnt;
|
||||||
|
}
|
||||||
|
}
|
113
plugins/GroupPrivateMessage/groupmessagelistitem.php
Normal file
113
plugins/GroupPrivateMessage/groupmessagelistitem.php
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Widget for showing an individual group message
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Widget for showing a single group message
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
class GroupMessageListItem extends Widget
|
||||||
|
{
|
||||||
|
var $gm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* @param HTMLOutputter $out output context
|
||||||
|
* @param Group_message $gm Group message
|
||||||
|
*/
|
||||||
|
function __construct($out, $gm)
|
||||||
|
{
|
||||||
|
parent::__construct($out);
|
||||||
|
$this->gm = $gm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the item
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
function show()
|
||||||
|
{
|
||||||
|
$group = $this->gm->getGroup();
|
||||||
|
$sender = $this->gm->getSender();
|
||||||
|
|
||||||
|
$this->out->elementStart('li', array('class' => 'hentry notice message group-message',
|
||||||
|
'id' => 'message-' . $this->gm->id));
|
||||||
|
|
||||||
|
$this->out->elementStart('div', 'entry-title');
|
||||||
|
$this->out->elementStart('span', 'vcard author');
|
||||||
|
$this->out->elementStart('a',
|
||||||
|
array('href' => $sender->profileurl,
|
||||||
|
'class' => 'url'));
|
||||||
|
$avatar = $sender->getAvatar(AVATAR_STREAM_SIZE);
|
||||||
|
$this->out->element('img', array('src' => ($avatar) ?
|
||||||
|
$avatar->displayUrl() :
|
||||||
|
Avatar::defaultImage(AVATAR_STREAM_SIZE),
|
||||||
|
'width' => AVATAR_STREAM_SIZE,
|
||||||
|
'height' => AVATAR_STREAM_SIZE,
|
||||||
|
'class' => 'photo avatar',
|
||||||
|
'alt' => $sender->getBestName()));
|
||||||
|
$this->out->element('span',
|
||||||
|
array('class' => 'nickname fn'),
|
||||||
|
$sender->nickname);
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
$this->out->elementEnd('span');
|
||||||
|
|
||||||
|
$this->out->elementStart('p', array('class' => 'entry-content message-content'));
|
||||||
|
$this->out->raw($this->gm->rendered);
|
||||||
|
$this->out->elementEnd('p');
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
|
$this->out->elementStart('div', 'entry-content');
|
||||||
|
$this->out->elementStart('a', array('rel' => 'bookmark',
|
||||||
|
'class' => 'timestamp',
|
||||||
|
'href' => $this->gm->url));
|
||||||
|
$dt = common_date_iso8601($this->gm->created);
|
||||||
|
$this->out->element('abbr', array('class' => 'published',
|
||||||
|
'title' => $dt),
|
||||||
|
common_date_string($this->gm->created));
|
||||||
|
$this->out->elementEnd('a');
|
||||||
|
$this->out->elementEnd('div');
|
||||||
|
|
||||||
|
$this->out->elementEnd('li');
|
||||||
|
}
|
||||||
|
}
|
161
plugins/GroupPrivateMessage/newgroupmessage.php
Normal file
161
plugins/GroupPrivateMessage/newgroupmessage.php
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Action for adding a new group message
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 Cache
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action for adding a new group message
|
||||||
|
*
|
||||||
|
* @category Action
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class NewgroupmessageAction extends Action
|
||||||
|
{
|
||||||
|
var $group;
|
||||||
|
var $user;
|
||||||
|
var $text;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For initializing members of the class.
|
||||||
|
*
|
||||||
|
* @param array $argarray misc. arguments
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($argarray)
|
||||||
|
{
|
||||||
|
parent::prepare($argarray);
|
||||||
|
|
||||||
|
$this->user = common_current_user();
|
||||||
|
|
||||||
|
if (empty($this->user)) {
|
||||||
|
throw new ClientException(_('Must be logged in.'), 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->user->hasRight(Right::NEWMESSAGE)) {
|
||||||
|
throw new Exception(sprintf(_('User %s not allowed to send private messages.'),
|
||||||
|
$this->user->nickname));
|
||||||
|
}
|
||||||
|
|
||||||
|
$nicknameArg = $this->trimmed('nickname');
|
||||||
|
|
||||||
|
$nickname = common_canonical_nickname($nicknameArg);
|
||||||
|
|
||||||
|
if ($nickname != $nicknameArg) {
|
||||||
|
$url = common_local_url('newgroupmessage', array('nickname' => $nickname));
|
||||||
|
common_redirect($url, 301);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$localGroup = Local_group::staticGet('nickname', $nickname);
|
||||||
|
|
||||||
|
if (empty($localGroup)) {
|
||||||
|
throw new ClientException(_('No such group'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->group = User_group::staticGet('id', $localGroup->group_id);
|
||||||
|
|
||||||
|
if (empty($this->group)) {
|
||||||
|
throw new ClientException(_('No such group'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This throws an exception on error
|
||||||
|
|
||||||
|
Group_privacy_settings::ensurePost($this->user, $this->group);
|
||||||
|
|
||||||
|
// If we're posted to, check session token and get text
|
||||||
|
|
||||||
|
if ($this->isPost()) {
|
||||||
|
$this->checkSessionToken();
|
||||||
|
$this->text = $this->trimmed('content');
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler method
|
||||||
|
*
|
||||||
|
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($argarray=null)
|
||||||
|
{
|
||||||
|
if ($this->isPost()) {
|
||||||
|
$this->sendNewMessage();
|
||||||
|
} else {
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showNoticeForm()
|
||||||
|
{
|
||||||
|
$form = new GroupMessageForm($this, $this->group);
|
||||||
|
$form->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendNewMessage()
|
||||||
|
{
|
||||||
|
$gm = Group_message::send($this->user, $this->group, $this->text);
|
||||||
|
|
||||||
|
if ($this->boolean('ajax')) {
|
||||||
|
$this->startHTML('text/xml;charset=utf-8');
|
||||||
|
$this->elementStart('head');
|
||||||
|
$this->element('title', null, _('Message sent'));
|
||||||
|
$this->elementEnd('head');
|
||||||
|
$this->elementStart('body');
|
||||||
|
$this->element('p',
|
||||||
|
array('id' => 'command_result'),
|
||||||
|
sprintf(_('Direct message to %s sent.'),
|
||||||
|
$this->group->nickname));
|
||||||
|
$this->elementEnd('body');
|
||||||
|
$this->elementEnd('html');
|
||||||
|
} else {
|
||||||
|
common_redirect($gm->url, 303);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return sprintf(_('New message to group %s'), $this->group->nickname);
|
||||||
|
}
|
||||||
|
}
|
188
plugins/GroupPrivateMessage/showgroupmessage.php
Normal file
188
plugins/GroupPrivateMessage/showgroupmessage.php
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* StatusNet - the distributed open-source microblogging tool
|
||||||
|
* Copyright (C) 2011, StatusNet, Inc.
|
||||||
|
*
|
||||||
|
* Show a single group message
|
||||||
|
*
|
||||||
|
* PHP version 5
|
||||||
|
*
|
||||||
|
* 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 GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!defined('STATUSNET')) {
|
||||||
|
// This check helps protect against security problems;
|
||||||
|
// your code file can't be executed directly from the web.
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a single private group message
|
||||||
|
*
|
||||||
|
* @category GroupPrivateMessage
|
||||||
|
* @package StatusNet
|
||||||
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
* @copyright 2011 StatusNet, Inc.
|
||||||
|
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
|
||||||
|
* @link http://status.net/
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ShowgroupmessageAction extends Action
|
||||||
|
{
|
||||||
|
var $gm;
|
||||||
|
var $group;
|
||||||
|
var $sender;
|
||||||
|
var $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For initializing members of the class.
|
||||||
|
*
|
||||||
|
* @param array $argarray misc. arguments
|
||||||
|
*
|
||||||
|
* @return boolean true
|
||||||
|
*/
|
||||||
|
|
||||||
|
function prepare($argarray)
|
||||||
|
{
|
||||||
|
parent::prepare($argarray);
|
||||||
|
|
||||||
|
$this->user = common_current_user();
|
||||||
|
|
||||||
|
if (empty($this->user)) {
|
||||||
|
throw new ClientException(_('Only logged-in users can view private messages.'),
|
||||||
|
403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$id = $this->trimmed('id');
|
||||||
|
|
||||||
|
$this->gm = Group_message::staticGet('id', $id);
|
||||||
|
|
||||||
|
if (empty($this->gm)) {
|
||||||
|
throw new ClientException(_('No such message'), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->group = User_group::staticGet('id', $this->gm->to_group);
|
||||||
|
|
||||||
|
if (empty($this->group)) {
|
||||||
|
throw new ServerException(_('Group not found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->user->isMember($this->group)) {
|
||||||
|
throw new ClientException(_('Cannot read message.'), 403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->sender = Profile::staticGet('id', $this->gm->from_profile);
|
||||||
|
|
||||||
|
if (empty($this->sender)) {
|
||||||
|
throw new ServerException(_('No sender found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler method
|
||||||
|
*
|
||||||
|
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
|
||||||
|
function handle($argarray=null)
|
||||||
|
{
|
||||||
|
$this->showPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the page
|
||||||
|
*/
|
||||||
|
|
||||||
|
function title()
|
||||||
|
{
|
||||||
|
return sprintf(_('Message from %1$s to group %2$s on %3$s'),
|
||||||
|
$this->sender->nickname,
|
||||||
|
$this->group->nickname,
|
||||||
|
common_exact_date($this->gm->created));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the content area.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function showContent()
|
||||||
|
{
|
||||||
|
$this->elementStart('ul', 'notices messages');
|
||||||
|
$gmli = new GroupMessageListItem($this, $this->gm);
|
||||||
|
$gmli->show();
|
||||||
|
$this->elementEnd('ul');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if read only.
|
||||||
|
*
|
||||||
|
* MAY override
|
||||||
|
*
|
||||||
|
* @param array $args other arguments
|
||||||
|
*
|
||||||
|
* @return boolean is read only action?
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isReadOnly($args)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return last modified, if applicable.
|
||||||
|
*
|
||||||
|
* MAY override
|
||||||
|
*
|
||||||
|
* @return string last modified http header
|
||||||
|
*/
|
||||||
|
function lastModified()
|
||||||
|
{
|
||||||
|
return max(strtotime($this->group->modified),
|
||||||
|
strtotime($this->sender->modified),
|
||||||
|
strtotime($this->gm->modified));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return etag, if applicable.
|
||||||
|
*
|
||||||
|
* MAY override
|
||||||
|
*
|
||||||
|
* @return string etag http header
|
||||||
|
*/
|
||||||
|
function etag()
|
||||||
|
{
|
||||||
|
$avatar = $this->sender->getAvatar(AVATAR_STREAM_SIZE);
|
||||||
|
|
||||||
|
$avtime = ($avatar) ? strtotime($avatar->modified) : 0;
|
||||||
|
|
||||||
|
return 'W/"' . implode(':', array($this->arg('action'),
|
||||||
|
common_user_cache_hash(),
|
||||||
|
common_language(),
|
||||||
|
$this->gm->id,
|
||||||
|
strtotime($this->sender->modified),
|
||||||
|
strtotime($this->group->modified),
|
||||||
|
$avtime)) . '"';
|
||||||
|
}
|
||||||
|
}
|
@ -40,8 +40,8 @@ class InfiniteScrollPlugin extends Plugin
|
|||||||
|
|
||||||
function onEndShowScripts($action)
|
function onEndShowScripts($action)
|
||||||
{
|
{
|
||||||
$action->script('plugins/InfiniteScroll/jquery.infinitescroll.js');
|
$action->script($this->path('jquery.infinitescroll.js'));
|
||||||
$action->script('plugins/InfiniteScroll/infinitescroll.js');
|
$action->script($this->path('infinitescroll.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPluginVersion(&$versions)
|
function onPluginVersion(&$versions)
|
||||||
|
@ -51,7 +51,7 @@ class LinkPreviewPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
if ($user && common_config('attachments', 'process_links')) {
|
if ($user && common_config('attachments', 'process_links')) {
|
||||||
$action->script('plugins/LinkPreview/linkpreview.min.js');
|
$action->script($this->path('linkpreview.min.js'));
|
||||||
$data = json_encode(array(
|
$data = json_encode(array(
|
||||||
'api' => common_local_url('oembedproxy'),
|
'api' => common_local_url('oembedproxy'),
|
||||||
'width' => common_config('attachments', 'thumbwidth'),
|
'width' => common_config('attachments', 'thumbwidth'),
|
||||||
|
@ -129,7 +129,7 @@ class MapstractionPlugin extends Plugin
|
|||||||
break;
|
break;
|
||||||
case 'openlayers':
|
case 'openlayers':
|
||||||
// Use our included stripped & minified OpenLayers.
|
// Use our included stripped & minified OpenLayers.
|
||||||
$action->script(common_path('plugins/Mapstraction/OpenLayers/OpenLayers.js'));
|
$action->script($this->path('OpenLayers/OpenLayers.js'));
|
||||||
break;
|
break;
|
||||||
case 'yahoo':
|
case 'yahoo':
|
||||||
$action->script(sprintf('http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=%s',
|
$action->script(sprintf('http://api.maps.yahoo.com/ajaxymap?v=3.8&appid=%s',
|
||||||
@ -145,13 +145,13 @@ class MapstractionPlugin extends Plugin
|
|||||||
//
|
//
|
||||||
// Note that OpenLayers.js needs to be separate, or it won't
|
// Note that OpenLayers.js needs to be separate, or it won't
|
||||||
// be able to find its UI images and styles.
|
// be able to find its UI images and styles.
|
||||||
$action->script(common_path('plugins/Mapstraction/usermap-mxn-openlayers.min.js'));
|
$action->script($this->path('usermap-mxn-openlayers.min.js'));
|
||||||
} else {
|
} else {
|
||||||
$action->script(sprintf('%s?(%s)',
|
$action->script(sprintf('%s?(%s)',
|
||||||
common_path('plugins/Mapstraction/js/mxn.js'),
|
$this->path('js/mxn.js'),
|
||||||
$this->provider));
|
$this->provider));
|
||||||
|
|
||||||
$action->script(common_path('plugins/Mapstraction/usermap.js'));
|
$action->script($this->path('usermap.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$action->inlineScript(sprintf('var _provider = "%s";', $this->provider));
|
$action->inlineScript(sprintf('var _provider = "%s";', $this->provider));
|
||||||
|
@ -89,7 +89,7 @@ class MeteorPlugin extends RealtimePlugin
|
|||||||
{
|
{
|
||||||
$scripts = parent::_getScripts();
|
$scripts = parent::_getScripts();
|
||||||
$scripts[] = 'http://'.$this->webserver.(($this->webport == 80) ? '':':'.$this->webport).'/meteor.js';
|
$scripts[] = 'http://'.$this->webserver.(($this->webport == 80) ? '':':'.$this->webport).'/meteor.js';
|
||||||
$scripts[] = common_path('plugins/Meteor/meteorupdater.min.js');
|
$scripts[] = $this->path('meteorupdater.min.js');
|
||||||
return $scripts;
|
return $scripts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,13 +241,13 @@ class MobileProfilePlugin extends WAP20Plugin
|
|||||||
if (file_exists(Theme::file('css/mp-screen.css'))) {
|
if (file_exists(Theme::file('css/mp-screen.css'))) {
|
||||||
$action->cssLink('css/mp-screen.css', null, 'screen');
|
$action->cssLink('css/mp-screen.css', null, 'screen');
|
||||||
} else {
|
} else {
|
||||||
$action->cssLink('plugins/MobileProfile/mp-screen.css',null,'screen');
|
$action->cssLink($this->path('mp-screen.css'),null,'screen');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists(Theme::file('css/mp-handheld.css'))) {
|
if (file_exists(Theme::file('css/mp-handheld.css'))) {
|
||||||
$action->cssLink('css/mp-handheld.css', null, 'handheld');
|
$action->cssLink('css/mp-handheld.css', null, 'handheld');
|
||||||
} else {
|
} else {
|
||||||
$action->cssLink('plugins/MobileProfile/mp-handheld.css',null,'handheld');
|
$action->cssLink($this->path('mp-handheld.css'),null,'handheld');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow other plugins to load their styles.
|
// Allow other plugins to load their styles.
|
||||||
|
@ -51,13 +51,13 @@ class ModPlusPlugin extends Plugin
|
|||||||
{
|
{
|
||||||
$user = common_current_user();
|
$user = common_current_user();
|
||||||
if ($user) {
|
if ($user) {
|
||||||
$action->script('plugins/ModPlus/modplus.js');
|
$action->script($this->path('modplus.js'));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowStatusNetStyles($action) {
|
function onEndShowStatusNetStyles($action) {
|
||||||
$action->cssLink('plugins/ModPlus/modplus.css');
|
$action->cssLink($this->path('modplus.css'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,12 +326,12 @@ class NewMenuPlugin extends Plugin
|
|||||||
|
|
||||||
function onEndShowStyles($action)
|
function onEndShowStyles($action)
|
||||||
{
|
{
|
||||||
if (($this->showCSS ||
|
if (($this->loadCSS ||
|
||||||
in_array(common_config('site', 'theme'),
|
in_array(common_config('site', 'theme'),
|
||||||
array('default', 'identica', 'h4ck3r'))) &&
|
array('default', 'identica', 'h4ck3r'))) &&
|
||||||
($action instanceof AccountSettingsAction ||
|
($action instanceof AccountSettingsAction ||
|
||||||
$action instanceof ConnectSettingsAction)) {
|
$action instanceof ConnectSettingsAction)) {
|
||||||
$action->cssLink(common_path('plugins/NewMenu/newmenu.css'));
|
$action->cssLink($this->path('newmenu.css'));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,12 @@ border-radius-topright:7px;
|
|||||||
border-radius-topright:0;
|
border-radius-topright:0;
|
||||||
-moz-border-radius-topright:0;
|
-moz-border-radius-topright:0;
|
||||||
-webkit-border-top-right-radius:0;
|
-webkit-border-top-right-radius:0;
|
||||||
|
min-height: 360px;
|
||||||
}
|
}
|
||||||
body[id$=settings] #aside_primary {
|
body[id$=settings] #aside_primary {
|
||||||
display:none;
|
float: right;
|
||||||
|
width: 17.25%;
|
||||||
|
margin-right: 10.45%;
|
||||||
|
margin-top: 6px;
|
||||||
|
min-height: 0px;
|
||||||
}
|
}
|
||||||
|
@ -419,12 +419,12 @@ class OStatusPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowStatusNetStyles($action) {
|
function onEndShowStatusNetStyles($action) {
|
||||||
$action->cssLink('plugins/OStatus/theme/base/css/ostatus.css');
|
$action->cssLink($this->path('theme/base/css/ostatus.css'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndShowStatusNetScripts($action) {
|
function onEndShowStatusNetScripts($action) {
|
||||||
$action->script('plugins/OStatus/js/ostatus.js');
|
$action->script($this->path('js/ostatus.js'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1112,7 +1112,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
return $url;
|
return $url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return common_path('plugins/OStatus/images/96px-Feed-icon.svg.png');
|
|
||||||
|
return Plugin::staticPath('OStatus', 'images/96px-Feed-icon.svg.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1781,12 +1782,14 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
$oprofile = Ostatus_profile::ensureWebfinger($rest);
|
$oprofile = Ostatus_profile::ensureWebfinger($rest);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
common_log(LOG_WARNING,
|
throw new ServerException("Unrecognized URI protocol for profile: $protocol ($uri)");
|
||||||
"Unrecognized URI protocol for profile: $protocol ($uri)");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw new ServerException("No URI protocol for profile: ($uri)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $oprofile;
|
return $oprofile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,8 +116,9 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
function onEndShowStatusNetStyles($action)
|
function onEndShowStatusNetStyles($action)
|
||||||
{
|
{
|
||||||
$action->cssLink('plugins/Realtime/realtimeupdate.css',
|
$action->cssLink(Plugin::staticPath('Realtime', 'realtimeupdate.css'),
|
||||||
null, 'screen, projection, tv');
|
null,
|
||||||
|
'screen, projection, tv');
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,7 +323,7 @@ class RealtimePlugin extends Plugin
|
|||||||
|
|
||||||
function _getScripts()
|
function _getScripts()
|
||||||
{
|
{
|
||||||
return array('plugins/Realtime/realtimeupdate.min.js');
|
return array(Plugin::staticPath('Realtime', 'realtimeupdate.min.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,7 @@ class ShareNoticePlugin extends Plugin
|
|||||||
);
|
);
|
||||||
|
|
||||||
function onEndShowStatusNetStyles($action) {
|
function onEndShowStatusNetStyles($action) {
|
||||||
$action->cssLink('plugins/ShareNotice/css/sharenotice.css');
|
$action->cssLink($this->path('css/sharenotice.css'));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ class TabFocusPlugin extends Plugin
|
|||||||
|
|
||||||
function onEndShowScripts($action)
|
function onEndShowScripts($action)
|
||||||
{
|
{
|
||||||
$action->script('plugins/TabFocus/tabfocus.js');
|
$action->script($this->path('tabfocus.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPluginVersion(&$versions)
|
function onPluginVersion(&$versions)
|
||||||
|
@ -39,6 +39,10 @@ if (!defined('STATUSNET')) {
|
|||||||
*
|
*
|
||||||
* Converts the notice form in browser to a rich-text editor.
|
* Converts the notice form in browser to a rich-text editor.
|
||||||
*
|
*
|
||||||
|
* FIXME: this plugin DOES NOT load its static files from the configured
|
||||||
|
* plugin server if one exists. There are cross-server permissions errors
|
||||||
|
* if you try to do that (something about window.tinymce).
|
||||||
|
*
|
||||||
* @category WYSIWYG
|
* @category WYSIWYG
|
||||||
* @package StatusNet
|
* @package StatusNet
|
||||||
* @author Evan Prodromou <evan@status.net>
|
* @author Evan Prodromou <evan@status.net>
|
||||||
|
@ -45,7 +45,7 @@ function add_twitter_user($twitter_id, $screen_name)
|
|||||||
$fuser = new Foreign_user();
|
$fuser = new Foreign_user();
|
||||||
|
|
||||||
$fuser->nickname = $screen_name;
|
$fuser->nickname = $screen_name;
|
||||||
$fuser->uri = 'http://twitter.com/#!/' . $screen_name;
|
$fuser->uri = 'http://twitter.com/' . $screen_name;
|
||||||
$fuser->id = $twitter_id;
|
$fuser->id = $twitter_id;
|
||||||
$fuser->service = TWITTER_SERVICE;
|
$fuser->service = TWITTER_SERVICE;
|
||||||
$fuser->created = common_sql_now();
|
$fuser->created = common_sql_now();
|
||||||
@ -173,6 +173,7 @@ function broadcast_twitter($notice)
|
|||||||
|
|
||||||
// Don't bother with basic auth, since it's no longer allowed
|
// Don't bother with basic auth, since it's no longer allowed
|
||||||
if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) {
|
if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) {
|
||||||
|
if (is_twitter_bound($notice, $flink)) {
|
||||||
if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) {
|
if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) {
|
||||||
$retweet = retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of));
|
$retweet = retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of));
|
||||||
if (is_object($retweet)) {
|
if (is_object($retweet)) {
|
||||||
@ -183,10 +184,11 @@ function broadcast_twitter($notice)
|
|||||||
// this or can discard safely.
|
// this or can discard safely.
|
||||||
return $retweet;
|
return $retweet;
|
||||||
}
|
}
|
||||||
} else if (is_twitter_bound($notice, $flink)) {
|
} else {
|
||||||
return broadcast_oauth($notice, $flink);
|
return broadcast_oauth($notice, $flink);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ class TwitterImport
|
|||||||
function ensureProfile($user)
|
function ensureProfile($user)
|
||||||
{
|
{
|
||||||
// check to see if there's already a profile for this user
|
// check to see if there's already a profile for this user
|
||||||
$profileurl = 'http://twitter.com/#!/' . $user->screen_name;
|
$profileurl = 'http://twitter.com/' . $user->screen_name;
|
||||||
$profile = $this->getProfileByUrl($user->screen_name, $profileurl);
|
$profile = $this->getProfileByUrl($user->screen_name, $profileurl);
|
||||||
|
|
||||||
if (!empty($profile)) {
|
if (!empty($profile)) {
|
||||||
|
@ -83,7 +83,7 @@ class TwitterloginAction extends Action
|
|||||||
$this->elementStart('a', array('href' => common_local_url('twitterauthorization',
|
$this->elementStart('a', array('href' => common_local_url('twitterauthorization',
|
||||||
null,
|
null,
|
||||||
array('signin' => true))));
|
array('signin' => true))));
|
||||||
$this->element('img', array('src' => common_path('plugins/TwitterBridge/Sign-in-with-Twitter-lighter.png'),
|
$this->element('img', array('src' => Plugin::staticPath('TwitterBridge', 'Sign-in-with-Twitter-lighter.png'),
|
||||||
'alt' => _m('Sign in with Twitter')));
|
'alt' => _m('Sign in with Twitter')));
|
||||||
$this->elementEnd('a');
|
$this->elementEnd('a');
|
||||||
}
|
}
|
||||||
|
@ -176,12 +176,12 @@ class YammeradminpanelAction extends AdminPanelAction
|
|||||||
function showStylesheets()
|
function showStylesheets()
|
||||||
{
|
{
|
||||||
parent::showStylesheets();
|
parent::showStylesheets();
|
||||||
$this->cssLink('plugins/YammerImport/css/admin.css', null, 'screen, projection, tv');
|
$this->cssLink(Plugin::staticPath('YammerImport', 'css/admin.css'), null, 'screen, projection, tv');
|
||||||
}
|
}
|
||||||
|
|
||||||
function showScripts()
|
function showScripts()
|
||||||
{
|
{
|
||||||
parent::showScripts();
|
parent::showScripts();
|
||||||
$this->script('plugins/YammerImport/js/yammer-admin.js');
|
$this->script(Plugin::staticPath('YammerImport', 'js/yammer-admin.js'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user