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
|
||||
- $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.
|
||||
restore: whether users can restore their profiles from backup files. Defaults
|
||||
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
|
||||
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_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
|
||||
=======
|
||||
|
||||
|
@ -177,116 +177,121 @@ class EditgroupAction extends GroupDesignAction
|
||||
return;
|
||||
}
|
||||
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$description = $this->trimmed('description');
|
||||
$location = $this->trimmed('location');
|
||||
$aliasstring = $this->trimmed('aliases');
|
||||
if (Event::handle('StartGroupSaveForm', array($this))) {
|
||||
|
||||
if ($this->nicknameExists($nickname)) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
} else if (!User_group::allowedNickname($nickname)) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
return;
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage,
|
||||
array('allowed_schemes' =>
|
||||
array('http', 'https')))) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Full name is too long (maximum 255 characters).'));
|
||||
return;
|
||||
} else if (User_group::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$description = $this->trimmed('description');
|
||||
$location = $this->trimmed('location');
|
||||
$aliasstring = $this->trimmed('aliases');
|
||||
|
||||
if ($this->nicknameExists($nickname)) {
|
||||
// TRANS: Group edit form validation error.
|
||||
_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()),
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
} else if (!User_group::allowedNickname($nickname)) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
return;
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage,
|
||||
array('allowed_schemes' =>
|
||||
array('http', 'https')))) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Full name is too long (maximum 255 characters).'));
|
||||
return;
|
||||
} else if (User_group::descriptionTooLong($description)) {
|
||||
$this->showForm(sprintf(
|
||||
// TRANS: Group edit form validation error.
|
||||
_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()),
|
||||
User_group::maxDescription()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($aliasstring)) {
|
||||
$aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
|
||||
} else {
|
||||
$aliases = array();
|
||||
}
|
||||
|
||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||
// TRANS: Group edit form validation error.
|
||||
// TRANS: %d is the maximum number of allowed aliases.
|
||||
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($aliases as $alias) {
|
||||
if (!Nickname::isValid($alias)) {
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
||||
return;
|
||||
}
|
||||
if ($this->nicknameExists($alias)) {
|
||||
|
||||
if (!empty($aliasstring)) {
|
||||
$aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
|
||||
} else {
|
||||
$aliases = array();
|
||||
}
|
||||
|
||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
|
||||
$alias));
|
||||
// TRANS: %d is the maximum number of allowed aliases.
|
||||
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
return;
|
||||
}
|
||||
// XXX assumes alphanum nicknames
|
||||
if (strcmp($alias, $nickname) == 0) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Alias can\'t be the same as nickname.'));
|
||||
return;
|
||||
|
||||
foreach ($aliases as $alias) {
|
||||
if (!Nickname::isValid($alias)) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
||||
return;
|
||||
}
|
||||
if ($this->nicknameExists($alias)) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
|
||||
$alias));
|
||||
return;
|
||||
}
|
||||
// XXX assumes alphanum nicknames
|
||||
if (strcmp($alias, $nickname) == 0) {
|
||||
// TRANS: Group edit form validation error.
|
||||
$this->showForm(_('Alias can\'t be the same as nickname.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$this->group->query('BEGIN');
|
||||
|
||||
$orig = clone($this->group);
|
||||
|
||||
$this->group->nickname = $nickname;
|
||||
$this->group->fullname = $fullname;
|
||||
$this->group->homepage = $homepage;
|
||||
$this->group->description = $description;
|
||||
$this->group->location = $location;
|
||||
$this->group->mainpage = common_local_url('showgroup', array('nickname' => $nickname));
|
||||
|
||||
$result = $this->group->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($this->group, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed when editing a group fails.
|
||||
$this->serverError(_('Could not update group.'));
|
||||
}
|
||||
|
||||
$result = $this->group->setAliases($aliases);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server error displayed when group aliases could not be added.
|
||||
$this->serverError(_('Could not create aliases.'));
|
||||
}
|
||||
|
||||
if ($nickname != $orig->nickname) {
|
||||
common_log(LOG_INFO, "Saving local group info.");
|
||||
$local = Local_group::staticGet('group_id', $this->group->id);
|
||||
$local->setNickname($nickname);
|
||||
}
|
||||
|
||||
$this->group->query('COMMIT');
|
||||
|
||||
Event::handle('EndGroupSaveForm', array($this));
|
||||
}
|
||||
|
||||
$this->group->query('BEGIN');
|
||||
|
||||
$orig = clone($this->group);
|
||||
|
||||
$this->group->nickname = $nickname;
|
||||
$this->group->fullname = $fullname;
|
||||
$this->group->homepage = $homepage;
|
||||
$this->group->description = $description;
|
||||
$this->group->location = $location;
|
||||
$this->group->mainpage = common_local_url('showgroup', array('nickname' => $nickname));
|
||||
|
||||
$result = $this->group->update($orig);
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($this->group, 'UPDATE', __FILE__);
|
||||
// TRANS: Server error displayed when editing a group fails.
|
||||
$this->serverError(_('Could not update group.'));
|
||||
}
|
||||
|
||||
$result = $this->group->setAliases($aliases);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server error displayed when group aliases could not be added.
|
||||
$this->serverError(_('Could not create aliases.'));
|
||||
}
|
||||
|
||||
if ($nickname != $orig->nickname) {
|
||||
common_log(LOG_INFO, "Saving local group info.");
|
||||
$local = Local_group::staticGet('group_id', $this->group->id);
|
||||
$local->setNickname($nickname);
|
||||
}
|
||||
|
||||
$this->group->query('COMMIT');
|
||||
|
||||
if ($this->group->nickname != $orig->nickname) {
|
||||
common_redirect(common_local_url('editgroup',
|
||||
array('nickname' => $nickname)),
|
||||
|
@ -90,18 +90,9 @@ class InboxAction extends MailboxAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
function getMessageList($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.');
|
||||
}
|
||||
}
|
||||
|
||||
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,103 +120,109 @@ class NewgroupAction extends Action
|
||||
|
||||
function trySave()
|
||||
{
|
||||
try {
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
} catch (NicknameException $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
}
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$description = $this->trimmed('description');
|
||||
$location = $this->trimmed('location');
|
||||
$aliasstring = $this->trimmed('aliases');
|
||||
if (Event::handle('StartGroupSaveForm', array($this))) {
|
||||
try {
|
||||
$nickname = Nickname::normalize($this->trimmed('nickname'));
|
||||
} catch (NicknameException $e) {
|
||||
$this->showForm($e->getMessage());
|
||||
}
|
||||
$fullname = $this->trimmed('fullname');
|
||||
$homepage = $this->trimmed('homepage');
|
||||
$description = $this->trimmed('description');
|
||||
$location = $this->trimmed('location');
|
||||
$aliasstring = $this->trimmed('aliases');
|
||||
|
||||
if ($this->nicknameExists($nickname)) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
} else if (!User_group::allowedNickname($nickname)) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
return;
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage,
|
||||
array('allowed_schemes' =>
|
||||
array('http', 'https')))) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Full name is too long (maximum 255 characters).'));
|
||||
return;
|
||||
} else if (User_group::descriptionTooLong($description)) {
|
||||
// TRANS: Group create form validation error.
|
||||
// TRANS: %d is the maximum number of allowed characters.
|
||||
$this->showForm(sprintf(_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()),
|
||||
User_group::maxDescription()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($aliasstring)) {
|
||||
$aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
|
||||
} else {
|
||||
$aliases = array();
|
||||
}
|
||||
|
||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||
// TRANS: Group create form validation error.
|
||||
// TRANS: %d is the maximum number of allowed aliases.
|
||||
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($aliases as $alias) {
|
||||
if (!Nickname::isValid($alias)) {
|
||||
if ($this->nicknameExists($nickname)) {
|
||||
// TRANS: Group create form validation error.
|
||||
// TRANS: %s is the invalid alias.
|
||||
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
||||
$this->showForm(_('Nickname already in use. Try another one.'));
|
||||
return;
|
||||
}
|
||||
if ($this->nicknameExists($alias)) {
|
||||
// TRANS: Group create form validation error. %s is the already used alias.
|
||||
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
|
||||
$alias));
|
||||
return;
|
||||
}
|
||||
// XXX assumes alphanum nicknames
|
||||
if (strcmp($alias, $nickname) == 0) {
|
||||
} else if (!User_group::allowedNickname($nickname)) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Alias cannot be the same as nickname.'));
|
||||
$this->showForm(_('Not a valid nickname.'));
|
||||
return;
|
||||
} else if (!is_null($homepage) && (strlen($homepage) > 0) &&
|
||||
!Validate::uri($homepage,
|
||||
array('allowed_schemes' =>
|
||||
array('http', 'https')))) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Homepage is not a valid URL.'));
|
||||
return;
|
||||
} else if (!is_null($fullname) && mb_strlen($fullname) > 255) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Full name is too long (maximum 255 characters).'));
|
||||
return;
|
||||
} else if (User_group::descriptionTooLong($description)) {
|
||||
// TRANS: Group create form validation error.
|
||||
// TRANS: %d is the maximum number of allowed characters.
|
||||
$this->showForm(sprintf(_m('Description is too long (maximum %d character).',
|
||||
'Description is too long (maximum %d characters).',
|
||||
User_group::maxDescription()),
|
||||
User_group::maxDescription()));
|
||||
return;
|
||||
} else if (!is_null($location) && mb_strlen($location) > 255) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Location is too long (maximum 255 characters).'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($aliasstring)) {
|
||||
$aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
|
||||
} else {
|
||||
$aliases = array();
|
||||
}
|
||||
|
||||
if (count($aliases) > common_config('group', 'maxaliases')) {
|
||||
// TRANS: Group create form validation error.
|
||||
// TRANS: %d is the maximum number of allowed aliases.
|
||||
$this->showForm(sprintf(_m('Too many aliases! Maximum %d allowed.',
|
||||
'Too many aliases! Maximum %d allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($aliases as $alias) {
|
||||
if (!Nickname::isValid($alias)) {
|
||||
// TRANS: Group create form validation error.
|
||||
// TRANS: %s is the invalid alias.
|
||||
$this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
|
||||
return;
|
||||
}
|
||||
if ($this->nicknameExists($alias)) {
|
||||
// TRANS: Group create form validation error. %s is the already used alias.
|
||||
$this->showForm(sprintf(_('Alias "%s" already in use. Try another one.'),
|
||||
$alias));
|
||||
return;
|
||||
}
|
||||
// XXX assumes alphanum nicknames
|
||||
if (strcmp($alias, $nickname) == 0) {
|
||||
// TRANS: Group create form validation error.
|
||||
$this->showForm(_('Alias cannot be the same as nickname.'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
// Checked in prepare() above
|
||||
|
||||
assert(!is_null($cur));
|
||||
|
||||
$group = User_group::register(array('nickname' => $nickname,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'description' => $description,
|
||||
'location' => $location,
|
||||
'aliases' => $aliases,
|
||||
'userid' => $cur->id,
|
||||
'local' => true));
|
||||
|
||||
$this->group = $group;
|
||||
|
||||
Event::handle('EndGroupSaveForm', array($this));
|
||||
|
||||
common_redirect($group->homeUrl(), 303);
|
||||
}
|
||||
|
||||
$cur = common_current_user();
|
||||
|
||||
// Checked in prepare() above
|
||||
|
||||
assert(!is_null($cur));
|
||||
|
||||
$group = User_group::register(array('nickname' => $nickname,
|
||||
'fullname' => $fullname,
|
||||
'homepage' => $homepage,
|
||||
'description' => $description,
|
||||
'location' => $location,
|
||||
'aliases' => $aliases,
|
||||
'userid' => $cur->id,
|
||||
'local' => true));
|
||||
|
||||
common_redirect($group->homeUrl(), 303);
|
||||
}
|
||||
|
||||
function nicknameExists($nickname)
|
||||
|
@ -88,21 +88,9 @@ class OutboxAction extends MailboxAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
function getMessageList($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.');
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
$this->showGroupProfile();
|
||||
$this->showGroupActions();
|
||||
$this->showGroupNotices();
|
||||
}
|
||||
|
||||
@ -216,112 +217,123 @@ class ShowgroupAction extends GroupDesignAction
|
||||
$this->elementStart('div', array('id' => 'i',
|
||||
'class' => 'entity_profile vcard author'));
|
||||
|
||||
// TRANS: Group profile header (h2). Text hidden by default.
|
||||
$this->element('h2', null, _('Group profile'));
|
||||
if (Event::handle('StartGroupProfileElements', array($this, $this->group))) {
|
||||
|
||||
$this->elementStart('dl', 'entity_depiction');
|
||||
// TRANS: Label for group avatar (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Avatar'));
|
||||
$this->elementStart('dd');
|
||||
// TRANS: Group profile header (h2). Text hidden by default.
|
||||
$this->element('h2', null, _('Group profile'));
|
||||
|
||||
$logo = ($this->group->homepage_logo) ?
|
||||
$this->group->homepage_logo : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
||||
|
||||
$this->element('img', array('src' => $logo,
|
||||
'class' => 'photo avatar',
|
||||
'width' => AVATAR_PROFILE_SIZE,
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $this->group->nickname));
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
$this->elementStart('dl', 'entity_nickname');
|
||||
// TRANS: Label for group nickname (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Nickname'));
|
||||
$this->elementStart('dd');
|
||||
$hasFN = ($this->group->fullname) ? 'nickname url uid' : 'fn org nickname url uid';
|
||||
$this->element('a', array('href' => $this->group->homeUrl(),
|
||||
'rel' => 'me', 'class' => $hasFN),
|
||||
$this->group->nickname);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
|
||||
if ($this->group->fullname) {
|
||||
$this->elementStart('dl', 'entity_fn');
|
||||
// TRANS: Label for full group name (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Full name'));
|
||||
$this->elementStart('dl', 'entity_depiction');
|
||||
// TRANS: Label for group avatar (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Avatar'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('span', 'fn org', $this->group->fullname);
|
||||
|
||||
$logo = ($this->group->homepage_logo) ?
|
||||
$this->group->homepage_logo : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
|
||||
|
||||
$this->element('img', array('src' => $logo,
|
||||
'class' => 'photo avatar',
|
||||
'width' => AVATAR_PROFILE_SIZE,
|
||||
'height' => AVATAR_PROFILE_SIZE,
|
||||
'alt' => $this->group->nickname));
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if ($this->group->location) {
|
||||
$this->elementStart('dl', 'entity_location');
|
||||
// TRANS: Label for group location (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Location'));
|
||||
$this->element('dd', 'label', $this->group->location);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if ($this->group->homepage) {
|
||||
$this->elementStart('dl', 'entity_url');
|
||||
// TRANS: Label for group URL (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('URL'));
|
||||
$this->elementStart('dl', 'entity_nickname');
|
||||
// TRANS: Label for group nickname (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Nickname'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $this->group->homepage,
|
||||
'rel' => 'me', 'class' => 'url'),
|
||||
$this->group->homepage);
|
||||
$hasFN = ($this->group->fullname) ? 'nickname url uid' : 'fn org nickname url uid';
|
||||
$this->element('a', array('href' => $this->group->homeUrl(),
|
||||
'rel' => 'me', 'class' => $hasFN),
|
||||
$this->group->nickname);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if ($this->group->description) {
|
||||
$this->elementStart('dl', 'entity_note');
|
||||
// TRANS: Label for group description or group note (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Note'));
|
||||
$this->element('dd', 'note', $this->group->description);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if (common_config('group', 'maxaliases') > 0) {
|
||||
$aliases = $this->group->getAliases();
|
||||
|
||||
if (!empty($aliases)) {
|
||||
$this->elementStart('dl', 'entity_aliases');
|
||||
// TRANS: Label for group aliases (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Aliases'));
|
||||
$this->element('dd', 'aliases', implode(' ', $aliases));
|
||||
if ($this->group->fullname) {
|
||||
$this->elementStart('dl', 'entity_fn');
|
||||
// TRANS: Label for full group name (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Full name'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('span', 'fn org', $this->group->fullname);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if ($this->group->location) {
|
||||
$this->elementStart('dl', 'entity_location');
|
||||
// TRANS: Label for group location (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Location'));
|
||||
$this->element('dd', 'label', $this->group->location);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if ($this->group->homepage) {
|
||||
$this->elementStart('dl', 'entity_url');
|
||||
// TRANS: Label for group URL (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('URL'));
|
||||
$this->elementStart('dd');
|
||||
$this->element('a', array('href' => $this->group->homepage,
|
||||
'rel' => 'me', 'class' => 'url'),
|
||||
$this->group->homepage);
|
||||
$this->elementEnd('dd');
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if ($this->group->description) {
|
||||
$this->elementStart('dl', 'entity_note');
|
||||
// TRANS: Label for group description or group note (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Note'));
|
||||
$this->element('dd', 'note', $this->group->description);
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
|
||||
if (common_config('group', 'maxaliases') > 0) {
|
||||
$aliases = $this->group->getAliases();
|
||||
|
||||
if (!empty($aliases)) {
|
||||
$this->elementStart('dl', 'entity_aliases');
|
||||
// TRANS: Label for group aliases (dt). Text hidden by default.
|
||||
$this->element('dt', null, _('Aliases'));
|
||||
$this->element('dd', 'aliases', implode(' ', $aliases));
|
||||
$this->elementEnd('dl');
|
||||
}
|
||||
}
|
||||
|
||||
Event::handle('EndGroupProfileElements', array($this, $this->group));
|
||||
}
|
||||
|
||||
$this->elementEnd('div');
|
||||
}
|
||||
|
||||
function showGroupActions()
|
||||
{
|
||||
$cur = common_current_user();
|
||||
$this->elementStart('div', 'entity_actions');
|
||||
// TRANS: Group actions header (h2). Text hidden by default.
|
||||
$this->element('h2', null, _('Group actions'));
|
||||
$this->elementStart('ul');
|
||||
$this->elementStart('li', 'entity_subscribe');
|
||||
if (Event::handle('StartGroupSubscribe', array($this, $this->group))) {
|
||||
if ($cur) {
|
||||
if ($cur->isMember($this->group)) {
|
||||
$lf = new LeaveForm($this, $this->group);
|
||||
$lf->show();
|
||||
} else if (!Group_block::isBlocked($this->group, $cur->getProfile())) {
|
||||
$jf = new JoinForm($this, $this->group);
|
||||
$jf->show();
|
||||
if (Event::handle('StartGroupActionsList', array($this, $this->group))) {
|
||||
$this->elementStart('li', 'entity_subscribe');
|
||||
if (Event::handle('StartGroupSubscribe', array($this, $this->group))) {
|
||||
if ($cur) {
|
||||
if ($cur->isMember($this->group)) {
|
||||
$lf = new LeaveForm($this, $this->group);
|
||||
$lf->show();
|
||||
} else if (!Group_block::isBlocked($this->group, $cur->getProfile())) {
|
||||
$jf = new JoinForm($this, $this->group);
|
||||
$jf->show();
|
||||
}
|
||||
}
|
||||
Event::handle('EndGroupSubscribe', array($this, $this->group));
|
||||
}
|
||||
Event::handle('EndGroupSubscribe', array($this, $this->group));
|
||||
}
|
||||
$this->elementEnd('li');
|
||||
if ($cur && $cur->hasRight(Right::DELETEGROUP)) {
|
||||
$this->elementStart('li', 'entity_delete');
|
||||
$df = new DeleteGroupForm($this, $this->group);
|
||||
$df->show();
|
||||
$this->elementEnd('li');
|
||||
if ($cur && $cur->hasRight(Right::DELETEGROUP)) {
|
||||
$this->elementStart('li', 'entity_delete');
|
||||
$df = new DeleteGroupForm($this, $this->group);
|
||||
$df->show();
|
||||
$this->elementEnd('li');
|
||||
}
|
||||
Event::handle('EndGroupActionsList', array($this, $this->group));
|
||||
}
|
||||
$this->elementEnd('ul');
|
||||
$this->elementEnd('div');
|
||||
|
@ -30,20 +30,17 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
require_once INSTALLDIR.'/lib/mailbox.php';
|
||||
|
||||
/**
|
||||
* Show a single message
|
||||
*
|
||||
* // XXX: It is totally weird how this works!
|
||||
*
|
||||
* @category Personal
|
||||
* @package StatusNet
|
||||
* @author Evan Prodromou <evan@status.net>
|
||||
* @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
|
||||
* @link http://status.net/
|
||||
*/
|
||||
class ShowmessageAction extends MailboxAction
|
||||
|
||||
class ShowmessageAction extends Action
|
||||
{
|
||||
/**
|
||||
* Message object to show
|
||||
@ -82,22 +79,20 @@ class ShowmessageAction extends MailboxAction
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
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();
|
||||
} 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;
|
||||
}
|
||||
$this->showPage();
|
||||
}
|
||||
|
||||
function title()
|
||||
@ -121,12 +116,38 @@ class ShowmessageAction extends MailboxAction
|
||||
}
|
||||
}
|
||||
|
||||
function getMessages()
|
||||
|
||||
function showContent()
|
||||
{
|
||||
$message = new Message();
|
||||
$message->id = $this->message->id;
|
||||
$message->find();
|
||||
return $message;
|
||||
$this->elementStart('ul', 'notices messages');
|
||||
$ml = new ShowMessageListItem($this, $this->message, $this->user);
|
||||
$ml->show();
|
||||
$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()
|
||||
@ -140,46 +161,4 @@ class ShowmessageAction extends MailboxAction
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
$this->query($query);
|
||||
/**
|
||||
* Get the attachments for a particlar notice.
|
||||
*
|
||||
* @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();
|
||||
while ($this->fetch()) {
|
||||
$att[] = clone($this);
|
||||
while ($file->fetch()) {
|
||||
$att[] = clone($file);
|
||||
}
|
||||
$this->free();
|
||||
return $att;
|
||||
}
|
||||
|
||||
|
@ -340,6 +340,7 @@ class Memcached_DataObject extends Safe_DataObject
|
||||
$start = microtime(true);
|
||||
$result = null;
|
||||
if (Event::handle('StartDBQuery', array($this, $string, &$result))) {
|
||||
common_perf_counter('query', $string);
|
||||
$result = parent::_query($string);
|
||||
Event::handle('EndDBQuery', array($this, $string, &$result));
|
||||
}
|
||||
|
@ -446,7 +446,10 @@ class Notice extends Memcached_DataObject
|
||||
function blowOnInsert($conversation = false)
|
||||
{
|
||||
self::blow('profile:notice_ids:%d', $this->profile_id);
|
||||
self::blow('public');
|
||||
|
||||
if ($this->isPublic()) {
|
||||
self::blow('public');
|
||||
}
|
||||
|
||||
// XXX: Before we were blowing the casche only if the notice id
|
||||
// was not the root of the conversation. What to do now?
|
||||
@ -481,7 +484,10 @@ class Notice extends Memcached_DataObject
|
||||
$this->blowOnInsert();
|
||||
|
||||
self::blow('profile:notice_ids:%d;last', $this->profile_id);
|
||||
self::blow('public;last');
|
||||
|
||||
if ($this->isPublic()) {
|
||||
self::blow('public;last');
|
||||
}
|
||||
}
|
||||
|
||||
/** save all urls in the notice to the db
|
||||
@ -958,7 +964,7 @@ class Notice extends Memcached_DataObject
|
||||
$groups = array();
|
||||
|
||||
/* 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),
|
||||
$match);
|
||||
if (!$count) {
|
||||
@ -2107,4 +2113,14 @@ class Notice extends Memcached_DataObject
|
||||
$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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Activity Streams <activity:actor> element.
|
||||
|
@ -156,6 +156,13 @@ class Session extends Memcached_DataObject
|
||||
$session->selectAdd();
|
||||
$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();
|
||||
|
||||
while ($session->fetch()) {
|
||||
|
@ -512,64 +512,70 @@ class User_group extends Memcached_DataObject
|
||||
$group->mainpage = $mainpage;
|
||||
$group->created = common_sql_now();
|
||||
|
||||
$result = $group->insert();
|
||||
if (Event::handle('StartGroupSave', array(&$group))) {
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($group, 'INSERT', __FILE__);
|
||||
// TRANS: Server exception thrown when creating a group failed.
|
||||
throw new ServerException(_('Could not create group.'));
|
||||
}
|
||||
|
||||
if (!isset($uri) || empty($uri)) {
|
||||
$orig = clone($group);
|
||||
$group->uri = common_local_url('groupbyid', array('id' => $group->id));
|
||||
$result = $group->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($group, 'UPDATE', __FILE__);
|
||||
// TRANS: Server exception thrown when updating a group URI failed.
|
||||
throw new ServerException(_('Could not set group URI.'));
|
||||
}
|
||||
}
|
||||
|
||||
$result = $group->setAliases($aliases);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server exception thrown when creating group aliases failed.
|
||||
throw new ServerException(_('Could not create aliases.'));
|
||||
}
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $group->id;
|
||||
$member->profile_id = $userid;
|
||||
$member->is_admin = 1;
|
||||
$member->created = $group->created;
|
||||
|
||||
$result = $member->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'INSERT', __FILE__);
|
||||
// TRANS: Server exception thrown when setting group membership failed.
|
||||
throw new ServerException(_('Could not set group membership.'));
|
||||
}
|
||||
|
||||
if ($local) {
|
||||
$local_group = new Local_group();
|
||||
|
||||
$local_group->group_id = $group->id;
|
||||
$local_group->nickname = $nickname;
|
||||
$local_group->created = common_sql_now();
|
||||
|
||||
$result = $local_group->insert();
|
||||
$result = $group->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($local_group, 'INSERT', __FILE__);
|
||||
// TRANS: Server exception thrown when saving local group information failed.
|
||||
throw new ServerException(_('Could not save local group info.'));
|
||||
common_log_db_error($group, 'INSERT', __FILE__);
|
||||
// TRANS: Server exception thrown when creating a group failed.
|
||||
throw new ServerException(_('Could not create group.'));
|
||||
}
|
||||
|
||||
if (!isset($uri) || empty($uri)) {
|
||||
$orig = clone($group);
|
||||
$group->uri = common_local_url('groupbyid', array('id' => $group->id));
|
||||
$result = $group->update($orig);
|
||||
if (!$result) {
|
||||
common_log_db_error($group, 'UPDATE', __FILE__);
|
||||
// TRANS: Server exception thrown when updating a group URI failed.
|
||||
throw new ServerException(_('Could not set group URI.'));
|
||||
}
|
||||
}
|
||||
|
||||
$result = $group->setAliases($aliases);
|
||||
|
||||
if (!$result) {
|
||||
// TRANS: Server exception thrown when creating group aliases failed.
|
||||
throw new ServerException(_('Could not create aliases.'));
|
||||
}
|
||||
|
||||
$member = new Group_member();
|
||||
|
||||
$member->group_id = $group->id;
|
||||
$member->profile_id = $userid;
|
||||
$member->is_admin = 1;
|
||||
$member->created = $group->created;
|
||||
|
||||
$result = $member->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($member, 'INSERT', __FILE__);
|
||||
// TRANS: Server exception thrown when setting group membership failed.
|
||||
throw new ServerException(_('Could not set group membership.'));
|
||||
}
|
||||
|
||||
if ($local) {
|
||||
$local_group = new Local_group();
|
||||
|
||||
$local_group->group_id = $group->id;
|
||||
$local_group->nickname = $nickname;
|
||||
$local_group->created = common_sql_now();
|
||||
|
||||
$result = $local_group->insert();
|
||||
|
||||
if (!$result) {
|
||||
common_log_db_error($local_group, 'INSERT', __FILE__);
|
||||
// TRANS: Server exception thrown when saving local group information failed.
|
||||
throw new ServerException(_('Could not save local group info.'));
|
||||
}
|
||||
}
|
||||
|
||||
$group->query('COMMIT');
|
||||
|
||||
Event::handle('EndGroupSave', array($group));
|
||||
}
|
||||
|
||||
$group->query('COMMIT');
|
||||
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);
|
||||
$_perfCounters = array();
|
||||
|
||||
define('INSTALLDIR', dirname(__FILE__));
|
||||
define('STATUSNET', true);
|
||||
@ -45,6 +46,8 @@ define('LACONICA', true); // compatibility
|
||||
|
||||
require_once INSTALLDIR . '/lib/common.php';
|
||||
|
||||
register_shutdown_function('common_log_perf_counters');
|
||||
|
||||
$user = null;
|
||||
$action = null;
|
||||
|
||||
|
1435
js/jquery.form.js
1435
js/jquery.form.js
File diff suppressed because it is too large
Load Diff
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) {
|
||||
$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) {
|
||||
|
@ -263,8 +263,7 @@ class ApiAction extends Action
|
||||
? Design::url($design->backgroundimage) : '';
|
||||
|
||||
$twitter_user['profile_background_tile']
|
||||
= empty($design->disposition)
|
||||
? '' : ($design->disposition & BACKGROUND_TILE) ? 'true' : 'false';
|
||||
= (bool)($design->disposition & BACKGROUND_TILE);
|
||||
|
||||
$twitter_user['statuses_count'] = $profile->noticeCount();
|
||||
|
||||
@ -1236,9 +1235,12 @@ class ApiAction extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
function clientError($msg, $code = 400, $format = 'xml')
|
||||
function clientError($msg, $code = 400, $format = null)
|
||||
{
|
||||
$action = $this->trimmed('action');
|
||||
if ($format === null) {
|
||||
$format = $this->format;
|
||||
}
|
||||
|
||||
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');
|
||||
if ($content_type === null) {
|
||||
$content_type = $this->format;
|
||||
}
|
||||
|
||||
common_debug("Server error '$code' on '$action': $msg", __FILE__);
|
||||
|
||||
|
@ -91,8 +91,16 @@ class AtomGroupNoticeFeed extends AtomNoticeFeed
|
||||
|
||||
$ao = ActivityObject::fromGroup($group);
|
||||
|
||||
$this->addAuthorRaw($ao->asString('author').
|
||||
$ao->asString('activity:subject'));
|
||||
$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')
|
||||
);
|
||||
|
||||
$this->addLink($group->homeUrl());
|
||||
}
|
||||
|
@ -59,9 +59,29 @@ class AtomUserNoticeFeed extends AtomNoticeFeed
|
||||
parent::__construct($cur, $indent);
|
||||
$this->user = $user;
|
||||
if (!empty($user)) {
|
||||
|
||||
$profile = $user->getProfile();
|
||||
|
||||
$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'));
|
||||
|
||||
$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.
|
||||
|
@ -76,8 +76,7 @@ class AttachmentList extends Widget
|
||||
*/
|
||||
function show()
|
||||
{
|
||||
$atts = new File;
|
||||
$att = $atts->getAttachments($this->notice->id);
|
||||
$att = File::getAttachments($this->notice->id);
|
||||
if (empty($att)) return 0;
|
||||
$this->showListStart();
|
||||
|
||||
|
@ -164,6 +164,7 @@ class Cache
|
||||
{
|
||||
$value = false;
|
||||
|
||||
common_perf_counter('Cache::get', $key);
|
||||
if (Event::handle('StartCacheGet', array(&$key, &$value))) {
|
||||
if (array_key_exists($key, $this->_items)) {
|
||||
$value = unserialize($this->_items[$key]);
|
||||
@ -188,6 +189,7 @@ class Cache
|
||||
{
|
||||
$success = false;
|
||||
|
||||
common_perf_counter('Cache::set', $key);
|
||||
if (Event::handle('StartCacheSet', array(&$key, &$value, &$flag,
|
||||
&$expiry, &$success))) {
|
||||
|
||||
@ -214,6 +216,7 @@ class Cache
|
||||
function increment($key, $step=1)
|
||||
{
|
||||
$value = false;
|
||||
common_perf_counter('Cache::increment', $key);
|
||||
if (Event::handle('StartCacheIncrement', array(&$key, &$step, &$value))) {
|
||||
// Fallback is not guaranteed to be atomic,
|
||||
// and may original expiry value.
|
||||
@ -239,6 +242,7 @@ class Cache
|
||||
{
|
||||
$success = false;
|
||||
|
||||
common_perf_counter('Cache::delete', $key);
|
||||
if (Event::handle('StartCacheDelete', array(&$key, &$success))) {
|
||||
if (array_key_exists($key, $this->_items)) {
|
||||
unset($this->_items[$key]);
|
||||
|
@ -25,252 +25,287 @@ class CommandInterpreter
|
||||
{
|
||||
function handle_command($user, $text)
|
||||
{
|
||||
# XXX: localise
|
||||
// XXX: localise
|
||||
|
||||
$text = preg_replace('/\s+/', ' ', trim($text));
|
||||
list($cmd, $arg) = $this->split_arg($text);
|
||||
|
||||
# We try to support all the same commands as Twitter, see
|
||||
# http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
|
||||
# There are a few compatibility commands from earlier versions of
|
||||
# StatusNet
|
||||
// We try to support all the same commands as Twitter, see
|
||||
// http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands
|
||||
// There are a few compatibility commands from earlier versions of
|
||||
// StatusNet
|
||||
|
||||
switch(strtolower($cmd)) {
|
||||
case 'help':
|
||||
if ($arg) {
|
||||
return null;
|
||||
}
|
||||
return new HelpCommand($user);
|
||||
case 'login':
|
||||
if ($arg) {
|
||||
return null;
|
||||
} else {
|
||||
return new LoginCommand($user);
|
||||
}
|
||||
case 'lose':
|
||||
if ($arg) {
|
||||
$cmd = strtolower($cmd);
|
||||
|
||||
if (Event::handle('StartIntepretCommand', array($cmd, $arg, $user, &$result))) {
|
||||
switch($cmd) {
|
||||
case 'help':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
}
|
||||
$result = new HelpCommand($user);
|
||||
break;
|
||||
case 'login':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new LoginCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'lose':
|
||||
if ($arg) {
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new LoseCommand($user, $other);
|
||||
}
|
||||
} else {
|
||||
$result = null;
|
||||
}
|
||||
break;
|
||||
case 'subscribers':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new SubscribersCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'subscriptions':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new SubscriptionsCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'groups':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new GroupsCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'on':
|
||||
if ($arg) {
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new OnCommand($user, $other);
|
||||
}
|
||||
} else {
|
||||
$result = new OnCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'off':
|
||||
if ($arg) {
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new OffCommand($user, $other);
|
||||
}
|
||||
} else {
|
||||
$result = new OffCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'stop':
|
||||
case 'quit':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new OffCommand($user);
|
||||
}
|
||||
break;
|
||||
case 'join':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
$result = null;
|
||||
} else {
|
||||
return new LoseCommand($user, $other);
|
||||
$result = new JoinCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'drop':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
case 'subscribers':
|
||||
if ($arg) {
|
||||
return null;
|
||||
} else {
|
||||
return new SubscribersCommand($user);
|
||||
}
|
||||
case 'subscriptions':
|
||||
if ($arg) {
|
||||
return null;
|
||||
} else {
|
||||
return new SubscriptionsCommand($user);
|
||||
}
|
||||
case 'groups':
|
||||
if ($arg) {
|
||||
return null;
|
||||
} else {
|
||||
return new GroupsCommand($user);
|
||||
}
|
||||
case 'on':
|
||||
if ($arg) {
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
$result = null;
|
||||
} else {
|
||||
return new OnCommand($user, $other);
|
||||
$result = new DropCommand($user, $other);
|
||||
}
|
||||
} else {
|
||||
return new OnCommand($user);
|
||||
}
|
||||
case 'off':
|
||||
if ($arg) {
|
||||
break;
|
||||
case 'follow':
|
||||
case 'sub':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
$result = null;
|
||||
} else {
|
||||
return new OffCommand($user, $other);
|
||||
$result = new SubCommand($user, $other);
|
||||
}
|
||||
} else {
|
||||
return new OffCommand($user);
|
||||
break;
|
||||
case 'leave':
|
||||
case 'unsub':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new UnsubCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'get':
|
||||
case 'last':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new GetCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
case 'dm':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if (!$extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new MessageCommand($user, $other, $extra);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
case 'reply':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if (!$extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new ReplyCommand($user, $other, $extra);
|
||||
}
|
||||
break;
|
||||
case 'repeat':
|
||||
case 'rp':
|
||||
case 'rt':
|
||||
case 'rd':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new RepeatCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'whois':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new WhoisCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'fav':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new FavCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'nudge':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new NudgeCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'stats':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
}
|
||||
$result = new StatsCommand($user);
|
||||
break;
|
||||
case 'invite':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else {
|
||||
$result = new InviteCommand($user, $other);
|
||||
}
|
||||
break;
|
||||
case 'track':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($word, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else if ($word == 'off') {
|
||||
$result = new TrackOffCommand($user);
|
||||
} else {
|
||||
$result = new TrackCommand($user, $word);
|
||||
}
|
||||
break;
|
||||
case 'untrack':
|
||||
if (!$arg) {
|
||||
$result = null;
|
||||
}
|
||||
list($word, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
$result = null;
|
||||
} else if ($word == 'all') {
|
||||
$result = new TrackOffCommand($user);
|
||||
} else {
|
||||
$result = new UntrackCommand($user, $word);
|
||||
}
|
||||
break;
|
||||
case 'tracks':
|
||||
case 'tracking':
|
||||
if ($arg) {
|
||||
$result = null;
|
||||
}
|
||||
$result = new TrackingCommand($user);
|
||||
break;
|
||||
default:
|
||||
$result = false;
|
||||
}
|
||||
case 'stop':
|
||||
case 'quit':
|
||||
if ($arg) {
|
||||
return null;
|
||||
} else {
|
||||
return new OffCommand($user);
|
||||
}
|
||||
case 'join':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new JoinCommand($user, $other);
|
||||
}
|
||||
case 'drop':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new DropCommand($user, $other);
|
||||
}
|
||||
case 'follow':
|
||||
case 'sub':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new SubCommand($user, $other);
|
||||
}
|
||||
case 'leave':
|
||||
case 'unsub':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new UnsubCommand($user, $other);
|
||||
}
|
||||
case 'get':
|
||||
case 'last':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new GetCommand($user, $other);
|
||||
}
|
||||
case 'd':
|
||||
case 'dm':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if (!$extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new MessageCommand($user, $other, $extra);
|
||||
}
|
||||
case 'r':
|
||||
case 'reply':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if (!$extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new ReplyCommand($user, $other, $extra);
|
||||
}
|
||||
case 'repeat':
|
||||
case 'rp':
|
||||
case 'rt':
|
||||
case 'rd':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new RepeatCommand($user, $other);
|
||||
}
|
||||
case 'whois':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new WhoisCommand($user, $other);
|
||||
}
|
||||
case 'fav':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new FavCommand($user, $other);
|
||||
}
|
||||
case 'nudge':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new NudgeCommand($user, $other);
|
||||
}
|
||||
case 'stats':
|
||||
if ($arg) {
|
||||
return null;
|
||||
}
|
||||
return new StatsCommand($user);
|
||||
case 'invite':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($other, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else {
|
||||
return new InviteCommand($user, $other);
|
||||
}
|
||||
case 'track':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($word, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else if ($word == 'off') {
|
||||
return new TrackOffCommand($user);
|
||||
} else {
|
||||
return new TrackCommand($user, $word);
|
||||
}
|
||||
case 'untrack':
|
||||
if (!$arg) {
|
||||
return null;
|
||||
}
|
||||
list($word, $extra) = $this->split_arg($arg);
|
||||
if ($extra) {
|
||||
return null;
|
||||
} else if ($word == 'all') {
|
||||
return new TrackOffCommand($user);
|
||||
} else {
|
||||
return new UntrackCommand($user, $word);
|
||||
}
|
||||
case 'tracks':
|
||||
case 'tracking':
|
||||
if ($arg) {
|
||||
return null;
|
||||
}
|
||||
return new TrackingCommand($user);
|
||||
default:
|
||||
return 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; }
|
||||
|
||||
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('LACONICA_VERSION', STATUSNET_VERSION); // compatibility
|
||||
@ -36,6 +36,7 @@ define('AVATAR_MINI_SIZE', 24);
|
||||
|
||||
define('NOTICES_PER_PAGE', 20);
|
||||
define('PROFILES_PER_PAGE', 20);
|
||||
define('MESSAGES_PER_PAGE', 20);
|
||||
|
||||
define('FOREIGN_NOTICE_SEND', 1);
|
||||
define('FOREIGN_NOTICE_RECV', 2);
|
||||
|
@ -39,6 +39,8 @@ $default =
|
||||
'logo' => null,
|
||||
'ssllogo' => null,
|
||||
'logdebug' => false,
|
||||
'logperf' => false, // Enable to dump performance counters to syslog
|
||||
'logperf_detail' => false, // Enable to dump every counter hit
|
||||
'fancy' => false,
|
||||
'locale_path' => INSTALLDIR.'/locale',
|
||||
'language' => 'en',
|
||||
@ -269,8 +271,9 @@ $default =
|
||||
'search' =>
|
||||
array('type' => 'fulltext'),
|
||||
'sessions' =>
|
||||
array('handle' => false, // whether to handle sessions ourselves
|
||||
'debug' => false), // debugging output for sessions
|
||||
array('handle' => false, // whether to handle sessions ourselves
|
||||
'debug' => false, // debugging output for sessions
|
||||
'gc_limit' => 1000), // max sessions to expire at a time
|
||||
'design' =>
|
||||
array('backgroundcolor' => null, // null -> 'use theme default'
|
||||
'contentcolor' => null,
|
||||
@ -311,6 +314,9 @@ $default =
|
||||
'RSSCloud' => null,
|
||||
'OpenID' => null),
|
||||
'locale_path' => false, // Set to a path to use *instead of* each plugin's own locale subdirectories
|
||||
'server' => null,
|
||||
'sslserver' => null,
|
||||
'path' => null,
|
||||
),
|
||||
'admin' =>
|
||||
array('panels' => array('design', 'site', 'user', 'paths', 'access', 'sessions', 'sitenotice', 'license')),
|
||||
|
@ -139,51 +139,54 @@ class GroupEditForm extends Form
|
||||
}
|
||||
|
||||
$this->out->elementStart('ul', 'form_data');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->hidden('groupid', $id);
|
||||
$this->out->input('nickname', _('Nickname'),
|
||||
($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces.'));
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('fullname', _('Full name'),
|
||||
($this->out->arg('fullname')) ? $this->out->arg('fullname') : $fullname);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('homepage', _('Homepage'),
|
||||
($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
|
||||
_('URL of the homepage or blog of the group or topic.'));
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$desclimit = User_group::maxDescription();
|
||||
if ($desclimit == 0) {
|
||||
$descinstr = _('Describe the group or topic');
|
||||
} else {
|
||||
$descinstr = sprintf(_m('Describe the group or topic in %d character or less.',
|
||||
'Describe the group or topic in %d characters or less.',
|
||||
$desclimit),
|
||||
$desclimit);
|
||||
}
|
||||
$this->out->textarea('description', _('Description'),
|
||||
($this->out->arg('description')) ? $this->out->arg('description') : $description,
|
||||
$descinstr);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('location', _('Location'),
|
||||
($this->out->arg('location')) ? $this->out->arg('location') : $location,
|
||||
_('Location for the group, if any, like "City, State (or Region), Country".'));
|
||||
$this->out->elementEnd('li');
|
||||
if (common_config('group', 'maxaliases') > 0) {
|
||||
$aliases = (empty($this->group)) ? array() : $this->group->getAliases();
|
||||
if (Event::handle('StartGroupEditFormData', array($this))) {
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('aliases', _('Aliases'),
|
||||
($this->out->arg('aliases')) ? $this->out->arg('aliases') :
|
||||
(!empty($aliases)) ? implode(' ', $aliases) : '',
|
||||
sprintf(_m('Extra nicknames for the group, separated with commas or spaces. Maximum %d alias allowed.',
|
||||
'Extra nicknames for the group, separated with commas or spaces. Maximum %d aliases allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));;
|
||||
$this->out->hidden('groupid', $id);
|
||||
$this->out->input('nickname', _('Nickname'),
|
||||
($this->out->arg('nickname')) ? $this->out->arg('nickname') : $nickname,
|
||||
_('1-64 lowercase letters or numbers, no punctuation or spaces'));
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('fullname', _('Full name'),
|
||||
($this->out->arg('fullname')) ? $this->out->arg('fullname') : $fullname);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('homepage', _('Homepage'),
|
||||
($this->out->arg('homepage')) ? $this->out->arg('homepage') : $homepage,
|
||||
_('URL of the homepage or blog of the group or topic.'));
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$desclimit = User_group::maxDescription();
|
||||
if ($desclimit == 0) {
|
||||
$descinstr = _('Describe the group or topic');
|
||||
} else {
|
||||
$descinstr = sprintf(_m('Describe the group or topic in %d character or less',
|
||||
'Describe the group or topic in %d characters or less',
|
||||
$desclimit),
|
||||
$desclimit);
|
||||
}
|
||||
$this->out->textarea('description', _('Description'),
|
||||
($this->out->arg('description')) ? $this->out->arg('description') : $description,
|
||||
$descinstr);
|
||||
$this->out->elementEnd('li');
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('location', _('Location'),
|
||||
($this->out->arg('location')) ? $this->out->arg('location') : $location,
|
||||
_('Location for the group, if any, like "City, State (or Region), Country".'));
|
||||
$this->out->elementEnd('li');
|
||||
if (common_config('group', 'maxaliases') > 0) {
|
||||
$aliases = (empty($this->group)) ? array() : $this->group->getAliases();
|
||||
$this->out->elementStart('li');
|
||||
$this->out->input('aliases', _('Aliases'),
|
||||
($this->out->arg('aliases')) ? $this->out->arg('aliases') :
|
||||
(!empty($aliases)) ? implode(' ', $aliases) : '',
|
||||
sprintf(_m('Extra nicknames for the group, separated with commas or spaces. Maximum %d alias allowed.',
|
||||
'Extra nicknames for the group, separated with commas or spaces. Maximum %d aliases allowed.',
|
||||
common_config('group', 'maxaliases')),
|
||||
common_config('group', 'maxaliases')));;
|
||||
$this->out->elementEnd('li');
|
||||
}
|
||||
Event::handle('EndGroupEditFormData', array($this));
|
||||
}
|
||||
$this->out->elementEnd('ul');
|
||||
}
|
||||
|
161
lib/mailbox.php
161
lib/mailbox.php
@ -31,8 +31,6 @@ if (!defined('STATUSNET') && !defined('LACONICA')) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
define('MESSAGES_PER_PAGE', 20);
|
||||
|
||||
/**
|
||||
* common superclass for direct messages inbox and outbox
|
||||
*
|
||||
@ -111,32 +109,22 @@ class MailboxAction extends CurrentUserDesignAction
|
||||
$message = $this->getMessages();
|
||||
|
||||
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) {
|
||||
$cnt++;
|
||||
$ml = $this->getMessageList($message);
|
||||
|
||||
if ($cnt > MESSAGES_PER_PAGE) {
|
||||
break;
|
||||
}
|
||||
$cnt = $ml->show();
|
||||
|
||||
$this->showMessage($message);
|
||||
}
|
||||
|
||||
$this->elementEnd('ul');
|
||||
|
||||
$this->pagination($this->page > 1, $cnt > MESSAGES_PER_PAGE,
|
||||
$this->page, $this->trimmed('action'),
|
||||
$this->pagination($this->page > 1,
|
||||
$cnt > MESSAGES_PER_PAGE,
|
||||
$this->page,
|
||||
$this->trimmed('action'),
|
||||
array('nickname' => $this->user->nickname));
|
||||
$this->elementEnd('div');
|
||||
$message->free();
|
||||
unset($message);
|
||||
}
|
||||
else {
|
||||
$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.'));
|
||||
} else {
|
||||
$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.'));
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,95 +133,11 @@ class MailboxAction extends CurrentUserDesignAction
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
function getMessageList($message)
|
||||
{
|
||||
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
|
||||
*
|
||||
@ -252,44 +156,6 @@ class MailboxAction extends CurrentUserDesignAction
|
||||
$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
|
||||
*
|
||||
@ -302,5 +168,4 @@ class MailboxAction extends CurrentUserDesignAction
|
||||
{
|
||||
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();
|
||||
}
|
@ -110,11 +110,16 @@ class Plugin
|
||||
{
|
||||
$this->log(LOG_DEBUG, $msg);
|
||||
}
|
||||
|
||||
function name()
|
||||
{
|
||||
$cls = get_class($this);
|
||||
return mb_substr($cls, 0, -6);
|
||||
}
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
{
|
||||
$cls = get_class($this);
|
||||
$name = mb_substr($cls, 0, -6);
|
||||
$name = $this->name();
|
||||
|
||||
$versions[] = array('name' => $name,
|
||||
// TRANS: Displayed as version information for a plugin if no version information was found.
|
||||
@ -122,4 +127,39 @@ class Plugin
|
||||
|
||||
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);
|
||||
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){
|
||||
if (common_logged_in()) {
|
||||
$action->script('plugins/Autocomplete/jquery-autocomplete/jquery.autocomplete.pack.js');
|
||||
$action->script('plugins/Autocomplete/Autocomplete.js');
|
||||
$action->script($this->path('jquery-autocomplete/jquery.autocomplete.pack.js'));
|
||||
$action->script($this->path('Autocomplete.js'));
|
||||
}
|
||||
}
|
||||
|
||||
function onEndShowStatusNetStyles($action)
|
||||
{
|
||||
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',
|
||||
array('width' => 300,
|
||||
'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',
|
||||
array('width' => 180,
|
||||
'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',
|
||||
array('width' => 160,
|
||||
'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',
|
||||
array('width' => 728,
|
||||
'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)
|
||||
{
|
||||
$action->cssLink('plugins/Bookmark/bookmark.css');
|
||||
$action->cssLink($this->path('bookmark.css'));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -107,6 +107,6 @@ class BookmarkpopupAction extends NewbookmarkAction
|
||||
function 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){
|
||||
$action->inlineScript('var Notice_maxContent = ' . Notice::maxContent());
|
||||
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){
|
||||
if (common_logged_in()) {
|
||||
$action->script('plugins/DirectionDetector/jquery.DirectionDetector.js');
|
||||
$action->script($this->path('jquery.DirectionDetector.js'));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
* @category Pugin
|
||||
* @package StatusNet
|
||||
* @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
|
||||
* @link http://status.net/
|
||||
*/
|
||||
@ -47,8 +47,9 @@ define("FACEBOOK_SERVICE", 2);
|
||||
*/
|
||||
class FacebookBridgePlugin extends Plugin
|
||||
{
|
||||
public $appId = null; // Facebook application ID
|
||||
public $secret = null; // Facebook application secret
|
||||
public $appId; // Facebook application ID
|
||||
public $secret; // Facebook application secret
|
||||
|
||||
public $facebook = null; // Facebook application instance
|
||||
public $dir = null; // Facebook plugin dir
|
||||
|
||||
@ -61,6 +62,28 @@ class FacebookBridgePlugin extends Plugin
|
||||
*/
|
||||
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->appId,
|
||||
$this->secret
|
||||
|
@ -89,10 +89,7 @@ class FacebookloginAction extends Action
|
||||
);
|
||||
|
||||
$attrs = array(
|
||||
'src' => common_path(
|
||||
'plugins/FacebookBridge/images/login-button.png',
|
||||
true
|
||||
),
|
||||
'src' => Plugin::staticPath('FacebookBridge', 'images/login-button.png'),
|
||||
'alt' => 'Login with Facebook',
|
||||
'title' => 'Login with Facebook'
|
||||
);
|
||||
|
@ -115,14 +115,7 @@ class Facebookclient
|
||||
function isFacebookBound() {
|
||||
|
||||
if (empty($this->flink)) {
|
||||
common_log(
|
||||
LOG_WARN,
|
||||
sprintf(
|
||||
"No Foreign_link to Facebook for the author of notice %d.",
|
||||
$this->notice->id
|
||||
),
|
||||
__FILE__
|
||||
);
|
||||
// User hasn't setup bridging
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -180,15 +173,6 @@ class Facebookclient
|
||||
// Otherwise we most likely have an access token
|
||||
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)
|
||||
{
|
||||
$action->script('plugins/InfiniteScroll/jquery.infinitescroll.js');
|
||||
$action->script('plugins/InfiniteScroll/infinitescroll.js');
|
||||
$action->script($this->path('jquery.infinitescroll.js'));
|
||||
$action->script($this->path('infinitescroll.js'));
|
||||
}
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
|
@ -51,7 +51,7 @@ class LinkPreviewPlugin extends Plugin
|
||||
{
|
||||
$user = common_current_user();
|
||||
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(
|
||||
'api' => common_local_url('oembedproxy'),
|
||||
'width' => common_config('attachments', 'thumbwidth'),
|
||||
|
@ -129,7 +129,7 @@ class MapstractionPlugin extends Plugin
|
||||
break;
|
||||
case 'openlayers':
|
||||
// Use our included stripped & minified OpenLayers.
|
||||
$action->script(common_path('plugins/Mapstraction/OpenLayers/OpenLayers.js'));
|
||||
$action->script($this->path('OpenLayers/OpenLayers.js'));
|
||||
break;
|
||||
case 'yahoo':
|
||||
$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
|
||||
// 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 {
|
||||
$action->script(sprintf('%s?(%s)',
|
||||
common_path('plugins/Mapstraction/js/mxn.js'),
|
||||
$this->path('js/mxn.js'),
|
||||
$this->provider));
|
||||
|
||||
$action->script(common_path('plugins/Mapstraction/usermap.js'));
|
||||
$action->script($this->path('usermap.js'));
|
||||
}
|
||||
|
||||
$action->inlineScript(sprintf('var _provider = "%s";', $this->provider));
|
||||
|
@ -89,7 +89,7 @@ class MeteorPlugin extends RealtimePlugin
|
||||
{
|
||||
$scripts = parent::_getScripts();
|
||||
$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;
|
||||
}
|
||||
|
||||
|
@ -241,13 +241,13 @@ class MobileProfilePlugin extends WAP20Plugin
|
||||
if (file_exists(Theme::file('css/mp-screen.css'))) {
|
||||
$action->cssLink('css/mp-screen.css', null, 'screen');
|
||||
} 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'))) {
|
||||
$action->cssLink('css/mp-handheld.css', null, 'handheld');
|
||||
} 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.
|
||||
|
@ -51,13 +51,13 @@ class ModPlusPlugin extends Plugin
|
||||
{
|
||||
$user = common_current_user();
|
||||
if ($user) {
|
||||
$action->script('plugins/ModPlus/modplus.js');
|
||||
$action->script($this->path('modplus.js'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function onEndShowStatusNetStyles($action) {
|
||||
$action->cssLink('plugins/ModPlus/modplus.css');
|
||||
$action->cssLink($this->path('modplus.css'));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -326,12 +326,12 @@ class NewMenuPlugin extends Plugin
|
||||
|
||||
function onEndShowStyles($action)
|
||||
{
|
||||
if (($this->showCSS ||
|
||||
if (($this->loadCSS ||
|
||||
in_array(common_config('site', 'theme'),
|
||||
array('default', 'identica', 'h4ck3r'))) &&
|
||||
($action instanceof AccountSettingsAction ||
|
||||
$action instanceof ConnectSettingsAction)) {
|
||||
$action->cssLink(common_path('plugins/NewMenu/newmenu.css'));
|
||||
$action->cssLink($this->path('newmenu.css'));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -41,7 +41,12 @@ border-radius-topright:7px;
|
||||
border-radius-topright:0;
|
||||
-moz-border-radius-topright:0;
|
||||
-webkit-border-top-right-radius:0;
|
||||
min-height: 360px;
|
||||
}
|
||||
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) {
|
||||
$action->cssLink('plugins/OStatus/theme/base/css/ostatus.css');
|
||||
$action->cssLink($this->path('theme/base/css/ostatus.css'));
|
||||
return true;
|
||||
}
|
||||
|
||||
function onEndShowStatusNetScripts($action) {
|
||||
$action->script('plugins/OStatus/js/ostatus.js');
|
||||
$action->script($this->path('js/ostatus.js'));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1112,7 +1112,8 @@ class Ostatus_profile extends Memcached_DataObject
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
common_log(LOG_WARNING,
|
||||
"Unrecognized URI protocol for profile: $protocol ($uri)");
|
||||
throw new ServerException("Unrecognized URI protocol for profile: $protocol ($uri)");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
throw new ServerException("No URI protocol for profile: ($uri)");
|
||||
}
|
||||
}
|
||||
|
||||
return $oprofile;
|
||||
}
|
||||
|
||||
|
@ -116,8 +116,9 @@ class RealtimePlugin extends Plugin
|
||||
|
||||
function onEndShowStatusNetStyles($action)
|
||||
{
|
||||
$action->cssLink('plugins/Realtime/realtimeupdate.css',
|
||||
null, 'screen, projection, tv');
|
||||
$action->cssLink(Plugin::staticPath('Realtime', 'realtimeupdate.css'),
|
||||
null,
|
||||
'screen, projection, tv');
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -322,7 +323,7 @@ class RealtimePlugin extends Plugin
|
||||
|
||||
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) {
|
||||
$action->cssLink('plugins/ShareNotice/css/sharenotice.css');
|
||||
$action->cssLink($this->path('css/sharenotice.css'));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ class TabFocusPlugin extends Plugin
|
||||
|
||||
function onEndShowScripts($action)
|
||||
{
|
||||
$action->script('plugins/TabFocus/tabfocus.js');
|
||||
$action->script($this->path('tabfocus.js'));
|
||||
}
|
||||
|
||||
function onPluginVersion(&$versions)
|
||||
|
@ -38,6 +38,10 @@ if (!defined('STATUSNET')) {
|
||||
* Use TinyMCE library to allow rich text editing in the browser
|
||||
*
|
||||
* 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
|
||||
* @package StatusNet
|
||||
|
@ -45,7 +45,7 @@ function add_twitter_user($twitter_id, $screen_name)
|
||||
$fuser = new Foreign_user();
|
||||
|
||||
$fuser->nickname = $screen_name;
|
||||
$fuser->uri = 'http://twitter.com/#!/' . $screen_name;
|
||||
$fuser->uri = 'http://twitter.com/' . $screen_name;
|
||||
$fuser->id = $twitter_id;
|
||||
$fuser->service = TWITTER_SERVICE;
|
||||
$fuser->created = common_sql_now();
|
||||
@ -173,18 +173,20 @@ function broadcast_twitter($notice)
|
||||
|
||||
// Don't bother with basic auth, since it's no longer allowed
|
||||
if (!empty($flink) && TwitterOAuthClient::isPackedToken($flink->credentials)) {
|
||||
if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) {
|
||||
$retweet = retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of));
|
||||
if (is_object($retweet)) {
|
||||
Notice_to_status::saveNew($notice->id, twitter_id($retweet));
|
||||
return true;
|
||||
if (is_twitter_bound($notice, $flink)) {
|
||||
if (!empty($notice->repeat_of) && is_twitter_notice($notice->repeat_of)) {
|
||||
$retweet = retweet_notice($flink, Notice::staticGet('id', $notice->repeat_of));
|
||||
if (is_object($retweet)) {
|
||||
Notice_to_status::saveNew($notice->id, twitter_id($retweet));
|
||||
return true;
|
||||
} else {
|
||||
// Our error processing will have decided if we need to requeue
|
||||
// this or can discard safely.
|
||||
return $retweet;
|
||||
}
|
||||
} else {
|
||||
// Our error processing will have decided if we need to requeue
|
||||
// this or can discard safely.
|
||||
return $retweet;
|
||||
return broadcast_oauth($notice, $flink);
|
||||
}
|
||||
} else if (is_twitter_bound($notice, $flink)) {
|
||||
return broadcast_oauth($notice, $flink);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,7 @@ class TwitterImport
|
||||
function ensureProfile($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);
|
||||
|
||||
if (!empty($profile)) {
|
||||
|
@ -83,7 +83,7 @@ class TwitterloginAction extends Action
|
||||
$this->elementStart('a', array('href' => common_local_url('twitterauthorization',
|
||||
null,
|
||||
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')));
|
||||
$this->elementEnd('a');
|
||||
}
|
||||
|
@ -176,12 +176,12 @@ class YammeradminpanelAction extends AdminPanelAction
|
||||
function 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()
|
||||
{
|
||||
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