invite.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <?php
  2. /*
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2008-2011, StatusNet, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. if (!defined('GNUSOCIAL')) { exit(1); }
  20. // @todo XXX: Add documentation.
  21. class InviteAction extends Action
  22. {
  23. var $mode = null;
  24. var $error = null;
  25. var $already = null;
  26. var $subbed = null;
  27. var $sent = null;
  28. function showNoticeForm()
  29. {
  30. return;
  31. }
  32. function isReadOnly($args)
  33. {
  34. return false;
  35. }
  36. function handle($args)
  37. {
  38. parent::handle($args);
  39. if (!common_config('invite', 'enabled')) {
  40. // TRANS: Client error displayed when trying to sent invites while they have been disabled.
  41. $this->clientError(_('Invites have been disabled.'));
  42. } else if (!common_logged_in()) {
  43. // TRANS: Client error displayed when trying to sent invites while not logged in.
  44. // TRANS: %s is the StatusNet site name.
  45. $this->clientError(sprintf(_('You must be logged in to invite other users to use %s.'),
  46. common_config('site', 'name')));
  47. return;
  48. } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  49. $this->sendInvitations();
  50. } else {
  51. $this->showForm();
  52. }
  53. }
  54. function sendInvitations()
  55. {
  56. if (Event::handle('StartSendInvitations', array(&$this))) {
  57. // CSRF protection
  58. $token = $this->trimmed('token');
  59. if (!$token || $token != common_session_token()) {
  60. // TRANS: Client error displayed when the session token does not match or is not given.
  61. $this->showForm(_('There was a problem with your session token. Try again, please.'));
  62. return;
  63. }
  64. $user = common_current_user();
  65. $profile = $user->getProfile();
  66. $bestname = $profile->getBestName();
  67. $sitename = common_config('site', 'name');
  68. $personal = $this->trimmed('personal');
  69. $addresses = explode("\n", $this->trimmed('addresses'));
  70. foreach ($addresses as $email) {
  71. $email = trim($email);
  72. $valid = null;
  73. try {
  74. if (Event::handle('StartValidateUserEmail', array(null, $email, &$valid))) {
  75. $valid = Validate::email($email, common_config('email', 'check_domain'));
  76. Event::handle('EndValidateUserEmail', array(null, $email, &$valid));
  77. }
  78. if ($valid) {
  79. if (Event::handle('StartValidateEmailInvite', array($user, $email, &$valid))) {
  80. $valid = true;
  81. Event::handle('EndValidateEmailInvite', array($user, $email, &$valid));
  82. }
  83. }
  84. if (!$valid) {
  85. // TRANS: Form validation message when providing an e-mail address that does not validate.
  86. // TRANS: %s is an invalid e-mail address.
  87. $this->showForm(sprintf(_('Invalid email address: %s.'), $email));
  88. return;
  89. }
  90. } catch (ClientException $e) {
  91. $this->showForm($e->getMessage());
  92. return;
  93. }
  94. }
  95. $this->already = array();
  96. $this->subbed = array();
  97. foreach ($addresses as $email) {
  98. $email = common_canonical_email($email);
  99. try {
  100. // If this user is already registered, subscribe to it!
  101. $other = Profile::getByEmail($email);
  102. if ($user->isSubscribed($other)) {
  103. $this->already[] = $other;
  104. } else {
  105. try {
  106. Subscription::ensureStart($profile, $other);
  107. $this->subbed[] = $other;
  108. } catch (Exception $e) {
  109. // subscription failed, but keep working
  110. common_debug('Invitation-based subscription failed: '.$e->getMessage());
  111. }
  112. }
  113. } catch (NoSuchUserException $e) {
  114. // If email was not known, let's send an invite!
  115. $this->sent[] = $email;
  116. $this->sendInvitation($email, $user, $personal);
  117. }
  118. }
  119. $this->mode = 'sent';
  120. $this->showPage();
  121. Event::handle('EndSendInvitations', array($this));
  122. }
  123. }
  124. function showScripts()
  125. {
  126. parent::showScripts();
  127. $this->autofocus('addresses');
  128. }
  129. function title()
  130. {
  131. if ($this->mode == 'sent') {
  132. // TRANS: Page title when invitations have been sent.
  133. return _('Invitations sent');
  134. } else {
  135. // TRANS: Page title when inviting potential users.
  136. return _('Invite new users');
  137. }
  138. }
  139. function showContent()
  140. {
  141. if ($this->mode == 'sent') {
  142. $this->showInvitationSuccess();
  143. } else {
  144. $this->showInviteForm();
  145. }
  146. }
  147. function showInvitationSuccess()
  148. {
  149. if (Event::handle('StartShowInvitationSuccess', array($this))) {
  150. if ($this->already) {
  151. // TRANS: Message displayed inviting users to use a StatusNet site while the inviting user
  152. // TRANS: is already subscribed to one or more users with the given e-mail address(es).
  153. // TRANS: Plural form is based on the number of reported already subscribed e-mail addresses.
  154. // TRANS: Followed by a bullet list.
  155. $this->element('p', null, _m('You are already subscribed to this user:',
  156. 'You are already subscribed to these users:',
  157. count($this->already)));
  158. $this->elementStart('ul');
  159. foreach ($this->already as $other) {
  160. // TRANS: Used as list item for already subscribed users (%1$s is nickname, %2$s is e-mail address).
  161. $this->element('li', null, sprintf(_m('INVITE','%1$s (%2$s)'), $other->nickname, $other->email));
  162. }
  163. $this->elementEnd('ul');
  164. }
  165. if ($this->subbed) {
  166. // TRANS: Message displayed inviting users to use a StatusNet site while the invited user
  167. // TRANS: already uses a this StatusNet site. Plural form is based on the number of
  168. // TRANS: reported already present people. Followed by a bullet list.
  169. $this->element('p', null, _m('This person is already a user and you were automatically subscribed:',
  170. 'These people are already users and you were automatically subscribed to them:',
  171. count($this->subbed)));
  172. $this->elementStart('ul');
  173. foreach ($this->subbed as $other) {
  174. // TRANS: Used as list item for already registered people (%1$s is nickname, %2$s is e-mail address).
  175. $this->element('li', null, sprintf(_m('INVITE','%1$s (%2$s)'), $other->nickname, $other->email));
  176. }
  177. $this->elementEnd('ul');
  178. }
  179. if ($this->sent) {
  180. // TRANS: Message displayed inviting users to use a StatusNet site. Plural form is
  181. // TRANS: based on the number of invitations sent. Followed by a bullet list of
  182. // TRANS: e-mail addresses to which invitations were sent.
  183. $this->element('p', null, _m('Invitation sent to the following person:',
  184. 'Invitations sent to the following people:',
  185. count($this->sent)));
  186. $this->elementStart('ul');
  187. foreach ($this->sent as $other) {
  188. $this->element('li', null, $other);
  189. }
  190. $this->elementEnd('ul');
  191. // TRANS: Generic message displayed after sending out one or more invitations to
  192. // TRANS: people to join a StatusNet site.
  193. $this->element('p', null, _('You will be notified when your invitees accept the invitation and register on the site. Thanks for growing the community!'));
  194. }
  195. Event::handle('EndShowInvitationSuccess', array($this));
  196. }
  197. }
  198. function showPageNotice()
  199. {
  200. if ($this->mode != 'sent') {
  201. if ($this->error) {
  202. $this->element('p', 'error', $this->error);
  203. } else {
  204. $this->elementStart('div', 'instructions');
  205. $this->element('p', null,
  206. // TRANS: Form instructions.
  207. _('Use this form to invite your friends and colleagues to use this service.'));
  208. $this->elementEnd('div');
  209. }
  210. }
  211. }
  212. function showForm($error=null)
  213. {
  214. $this->mode = 'form';
  215. $this->error = $error;
  216. $this->showPage();
  217. }
  218. function showInviteForm()
  219. {
  220. if (Event::handle('StartShowInviteForm', array($this))) {
  221. $form = new InviteForm($this);
  222. $form->show();
  223. Event::handle('EndShowInviteForm', array($this));
  224. }
  225. }
  226. function sendInvitation($email, $user, $personal)
  227. {
  228. $profile = $user->getProfile();
  229. $bestname = $profile->getBestName();
  230. $sitename = common_config('site', 'name');
  231. $invite = new Invitation();
  232. $invite->address = $email;
  233. $invite->address_type = 'email';
  234. $invite->code = common_confirmation_code(128);
  235. $invite->user_id = $user->id;
  236. $invite->created = common_sql_now();
  237. if (!$invite->insert()) {
  238. common_log_db_error($invite, 'INSERT', __FILE__);
  239. return false;
  240. }
  241. $confirmUrl = common_local_url('register', array('code' => $invite->code));
  242. $recipients = array($email);
  243. $headers['From'] = mail_notify_from();
  244. $headers['To'] = trim($email);
  245. $headers['Content-Type'] = 'text/html; charset=UTF-8';
  246. // TRANS: Subject for invitation email. Note that 'them' is correct as a gender-neutral
  247. // TRANS: singular 3rd-person pronoun in English. %1$s is the inviting user, $2$s is
  248. // TRANS: the StatusNet sitename.
  249. $headers['Subject'] = sprintf(_('%1$s has invited you to join them on %2$s'), $bestname, $sitename);
  250. $title = (empty($personal)) ? 'invite' : 'invitepersonal';
  251. // @todo FIXME: i18n issue.
  252. $inviteTemplate = DocFile::forTitle($title, DocFile::mailPaths());
  253. $body = $inviteTemplate->toHTML(array('inviter' => $bestname,
  254. 'inviterurl' => $profile->profileurl,
  255. 'confirmurl' => $confirmUrl,
  256. 'personal' => $personal));
  257. common_debug('Confirm URL is ' . common_local_url('register', array('code' => $invite->code)));
  258. mail_send($recipients, $headers, $body);
  259. }
  260. }