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
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 ($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(
- // 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 (Event::handle('StartGroupSaveForm', array($this))) {
- if (!empty($aliasstring)) {
- $aliases = array_map('common_canonical_nickname', array_unique(preg_split('/[\s,]+/', $aliasstring)));
- } else {
- $aliases = array();
- }
+ $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 (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)) {
+ if ($this->nicknameExists($nickname)) {
// TRANS: Group edit form validation error.
- $this->showForm(sprintf(_('Invalid alias: "%s"'), $alias));
+ $this->showForm(_('Nickname already in use. Try another one.'));
return;
- }
- if ($this->nicknameExists($alias)) {
+ } 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(sprintf(_('Alias "%s" already in use. Try another one.'),
- $alias));
+ $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;
}
- // XXX assumes alphanum nicknames
- if (strcmp($alias, $nickname) == 0) {
+
+ 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(_('Alias can\'t be the same as nickname.'));
+ // 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;
}
- }
- $this->group->query('BEGIN');
+ 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);
+ $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));
+ $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);
+ $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.'));
- }
+ 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);
+ $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 (!$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);
- }
+ 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');
+ $this->group->query('COMMIT');
+
+ Event::handle('EndGroupSaveForm', array($this));
+ }
if ($this->group->nickname != $orig->nickname) {
common_redirect(common_local_url('editgroup',
}
}
- /**
- * 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);
}
/**
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();
+ }
+}
\ No newline at end of file
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 ($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;
- }
+ 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');
- 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));
+ } 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;
}
- // XXX assumes alphanum nicknames
- if (strcmp($alias, $nickname) == 0) {
+
+ 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.
- $this->showForm(_('Alias cannot be the same as nickname.'));
+ // 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;
}
- }
- $cur = common_current_user();
+ 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
+ // Checked in prepare() above
- assert(!is_null($cur));
+ 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));
+ $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);
+ $this->group = $group;
+
+ Event::handle('EndGroupSaveForm', array($this));
+
+ common_redirect($group->homeUrl(), 303);
+ }
}
function nicknameExists($nickname)
}
}
- /**
- * 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);
}
/**
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();
+ }
+}
\ No newline at end of file
function showContent()
{
$this->showGroupProfile();
+ $this->showGroupActions();
$this->showGroupNotices();
}
$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_depiction');
+ // TRANS: Label for group avatar (dt). Text hidden by default.
+ $this->element('dt', null, _('Avatar'));
+ $this->elementStart('dd');
- $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');
+ $logo = ($this->group->homepage_logo) ?
+ $this->group->homepage_logo : User_group::defaultLogo(AVATAR_PROFILE_SIZE);
- 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->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 ($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 (common_config('group', 'maxaliases') > 0) {
- $aliases = $this->group->getAliases();
+ 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 (!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->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');
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
$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()
}
}
- function getMessages()
- {
- $message = new Message();
- $message->id = $this->message->id;
- $message->find();
- return $message;
- }
- function getMessageProfile()
+ function showContent()
{
- if ($this->user->id == $this->message->from_profile) {
- return $this->message->getTo();
- } else if ($this->user->id == $this->message->to_profile) {
- return $this->message->getFrom();
- } else {
- // This shouldn't happen
- return null;
- }
+ $this->elementStart('ul', 'notices messages');
+ $ml = new ShowMessageListItem($this, $this->message, $this->user);
+ $ml->show();
+ $this->elementEnd('ul');
}
- /**
- * Don't show local navigation
- *
- * @return void
- */
- function showLocalNavBlock()
- {
- }
-
- /**
- * Don't show page notice
- *
- * @return void
- */
- function showPageNoticeBlock()
+ function isReadOnly($args)
{
+ return true;
}
/**
*
* @return void
*/
- function showAside()
- {
+
+ function showAside() {
}
+}
- /**
- * Don't show any instructions
- *
- * @return string
- */
- function getInstructions()
+class ShowMessageListItem extends MessageListItem
+{
+ var $user;
+
+ function __construct($out, $message, $user)
{
- return '';
+ parent::__construct($out, $message);
+ $this->user = $user;
}
- function isReadOnly($args)
+ function getMessageProfile()
{
- return true;
+ if ($this->user->id == $this->message->from_profile) {
+ return $this->message->getTo();
+ } else if ($this->user->id == $this->message->to_profile) {
+ return $this->message->getFrom();
+ } else {
+ // This shouldn't happen
+ return null;
+ }
}
}
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?
$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
$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) {
$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));
+ }
+ }
}
$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.'));
- }
+ $result = $group->insert();
- 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.'));
+ common_log_db_error($group, 'INSERT', __FILE__);
+ // TRANS: Server exception thrown when creating a group failed.
+ throw new ServerException(_('Could not create group.'));
}
- }
- $result = $group->setAliases($aliases);
+ 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.'));
+ }
+ }
- if (!$result) {
- // TRANS: Server exception thrown when creating group aliases failed.
- throw new ServerException(_('Could not create aliases.'));
- }
+ $result = $group->setAliases($aliases);
- $member = new Group_member();
+ if (!$result) {
+ // TRANS: Server exception thrown when creating group aliases failed.
+ throw new ServerException(_('Could not create aliases.'));
+ }
- $member->group_id = $group->id;
- $member->profile_id = $userid;
- $member->is_admin = 1;
- $member->created = $group->created;
+ $member = new Group_member();
- $result = $member->insert();
+ $member->group_id = $group->id;
+ $member->profile_id = $userid;
+ $member->is_admin = 1;
+ $member->created = $group->created;
- 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.'));
- }
+ $result = $member->insert();
- if ($local) {
- $local_group = new Local_group();
+ 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.'));
+ }
- $local_group->group_id = $group->id;
- $local_group->nickname = $nickname;
- $local_group->created = common_sql_now();
+ if ($local) {
+ $local_group = new Local_group();
- $result = $local_group->insert();
+ $local_group->group_id = $group->id;
+ $local_group->nickname = $nickname;
+ $local_group->created = common_sql_now();
- 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.'));
+ $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;
}
? 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();
{
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);
- }
- 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;
+ 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;
}
- return new TrackingCommand($user);
- default:
- return false;
+
+ Event::handle('EndInterpretCommand', array($cmd, $arg, $user, $result));
}
+
+ return $result;
}
/**
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', 'beta1'); // '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
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);
}
$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->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('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->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');
}
exit(1);
}
-define('MESSAGES_PER_PAGE', 20);
-
/**
* common superclass for direct messages inbox and outbox
*
$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++;
-
- if ($cnt > MESSAGES_PER_PAGE) {
- break;
- }
- $this->showMessage($message);
- }
+ $ml = $this->getMessageList($message);
- $this->elementEnd('ul');
+ $cnt = $ml->show();
- $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.'));
}
}
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
*
$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
*
{
return true;
}
-
}
--- /dev/null
+<?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);
+}
--- /dev/null
+<?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();
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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;
+ }
+
+}
--- /dev/null
+<?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);
+ }
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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.');
+ }
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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')));
+ }
+}
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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');
+ }
+}
--- /dev/null
+<?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);
+ }
+}
--- /dev/null
+<?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)) . '"';
+ }
+}