]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/GroupPrivateMessage/GroupPrivateMessagePlugin.php
Merge branch '1.0.x' of gitorious.org:statusnet/mainline into 1.0.x
[quix0rs-gnu-social.git] / plugins / GroupPrivateMessage / GroupPrivateMessagePlugin.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2011, StatusNet, Inc.
5  *
6  * Private groups for StatusNet 0.9.x
7  *
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  Privacy
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2011 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 /**
38  * Private groups
39  *
40  * This plugin allows users to send private messages to a group.
41  *
42  * @category  Privacy
43  * @package   StatusNet
44  * @author    Evan Prodromou <evan@status.net>
45  * @copyright 2011 StatusNet, Inc.
46  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
47  * @link      http://status.net/
48  */
49
50 class GroupPrivateMessagePlugin extends Plugin
51 {
52     /**
53      * Database schema setup
54      *
55      * @see Schema
56      * @see ColumnDef
57      *
58      * @return boolean hook value
59      */
60
61     function onCheckSchema()
62     {
63         $schema = Schema::get();
64
65         // For storing user-submitted flags on profiles
66
67         $schema->ensureTable('group_privacy_settings',
68                              array(new ColumnDef('group_id',
69                                                  'integer',
70                                                  null,
71                                                  false,
72                                                  'PRI'),
73                                    new ColumnDef('allow_privacy',
74                                                  'integer'),
75                                    new ColumnDef('allow_sender',
76                                                  'integer'),
77                                    new ColumnDef('created',
78                                                  'datetime'),
79                                    new ColumnDef('modified',
80                                                  'timestamp')));
81                              
82         $schema->ensureTable('group_message',
83                              array(new ColumnDef('id',
84                                                  'char',
85                                                  36,
86                                                  false,
87                                                  'PRI'),
88                                    new ColumnDef('uri',
89                                                  'varchar',
90                                                  255,
91                                                  false,
92                                                  'UNI'),
93                                    new ColumnDef('from_profile',
94                                                  'integer',
95                                                  null,
96                                                  false,
97                                                  'MUL'),
98                                    new ColumnDef('to_group',
99                                                  'integer',
100                                                  null,
101                                                  false,
102                                                  'MUL'),
103                                    new ColumnDef('content',
104                                                  'text'),
105                                    new ColumnDef('rendered',
106                                                  'text'),
107                                    new ColumnDef('url',
108                                                  'varchar',
109                                                  255,
110                                                  false,
111                                                  'UNI'),
112                                    new ColumnDef('created',
113                                                  'datetime')));
114
115         $schema->ensureTable('group_message_profile',
116                              array(new ColumnDef('to_profile',
117                                                  'integer',
118                                                  null,
119                                                  false,
120                                                  'PRI'),
121                                    new ColumnDef('group_message_id',
122                                                  'char',
123                                                  36,
124                                                  false,
125                                                  'PRI'),
126                                    new ColumnDef('created',
127                                                  'datetime')));
128
129         return true;
130     }
131
132     /**
133      * Load related modules when needed
134      *
135      * @param string $cls Name of the class to be loaded
136      *
137      * @return boolean hook value
138      */
139
140     function onAutoload($cls)
141     {
142         $dir = dirname(__FILE__);
143
144         switch ($cls)
145         {
146         case 'GroupinboxAction':
147         case 'ShowgroupmessageAction':
148         case 'NewgroupmessageAction':
149             include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
150             return false;
151         case 'Group_privacy_settings':
152         case 'Group_message':
153         case 'Group_message_profile':
154             include_once $dir . '/'.$cls.'.php';
155             return false;
156         case 'GroupMessageCommand':
157         case 'GroupMessageList':
158         case 'GroupMessageListItem':
159         case 'GroupMessageForm':
160             include_once $dir . '/'.strtolower($cls).'.php';
161             return false;
162         default:
163             return true;
164         }
165     }
166
167     /**
168      * Map URLs to actions
169      *
170      * @param Net_URL_Mapper $m path-to-action mapper
171      *
172      * @return boolean hook value
173      */
174
175     function onRouterInitialized($m)
176     {
177         $m->connect('group/:nickname/inbox',
178                     array('action' => 'groupinbox'),
179                     array('nickname' => Nickname::DISPLAY_FMT));
180
181         $m->connect('group/message/:id',
182                     array('action' => 'showgroupmessage'),
183                     array('id' => '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'));
184
185         $m->connect('group/:nickname/message/new',
186                     array('action' => 'newgroupmessage'),
187                     array('nickname' => Nickname::DISPLAY_FMT));
188
189         return true;
190     }
191
192     /**
193      * Add group inbox to the menu
194      *
195      * @param Action $action The current action handler. Use this to
196      *                       do any output.
197      *
198      * @return boolean hook value; true means continue processing, false means stop.
199      *
200      * @see Action
201      */
202
203     function onEndGroupGroupNav($groupnav)
204     {
205         $action = $groupnav->action;
206         $group  = $groupnav->group;
207
208         $action->menuItem(common_local_url('groupinbox',
209                                            array('nickname' => $group->nickname)),
210                           _m('MENU','Inbox'),
211                           _m('Private messages for this group.'),
212                           $action->trimmed('action') == 'groupinbox',
213                           'nav_group_inbox');
214         return true;
215     }
216
217     /**
218      * Create default group privacy settings at group create time
219      *
220      * @param User_group $group Group that was just created
221      *
222      * @result boolean hook value
223      */
224
225     function onEndGroupSave($group)
226     {
227         $gps = new Group_privacy_settings();
228
229         $gps->group_id      = $group->id;
230         $gps->allow_privacy = Group_privacy_settings::SOMETIMES;
231         $gps->allow_sender  = Group_privacy_settings::MEMBER;
232         $gps->created       = common_sql_now();
233         $gps->modified      = $gps->created;
234
235         // This will throw an exception on error
236
237         $gps->insert();
238
239         return true;
240     }
241
242     /**
243      * Show group privacy controls on group edit form
244      *
245      * @param GroupEditForm $form form being shown
246      */
247
248     function onEndGroupEditFormData($form)
249     {
250         $gps = null;
251
252         if (!empty($form->group)) {
253             $gps = Group_privacy_settings::staticGet('group_id', $form->group->id);
254         }
255
256         $form->out->elementStart('li');
257         $form->out->dropdown('allow_privacy',
258                              _m('Private messages'),
259                              array(Group_privacy_settings::SOMETIMES => _m('Sometimes'),
260                                    Group_privacy_settings::ALWAYS => _m('Always'),
261                                    Group_privacy_settings::NEVER => _m('Never')),
262                              _m('Whether to allow private messages to this group.'),
263                              false,
264                              (empty($gps)) ? Group_privacy_settings::SOMETIMES : $gps->allow_privacy);
265         $form->out->elementEnd('li');
266         $form->out->elementStart('li');
267         $form->out->dropdown('allow_sender',
268                              _m('Private senders'),
269                              array(Group_privacy_settings::EVERYONE => _m('Everyone'),
270                                    Group_privacy_settings::MEMBER => _m('Member'),
271                                    Group_privacy_settings::ADMIN => _m('Admin')),
272                              _m('Who can send private messages to the group.'),
273                              false,
274                              (empty($gps)) ? Group_privacy_settings::MEMBER : $gps->allow_sender);
275         $form->out->elementEnd('li');
276         return true;
277     }
278
279     function onEndGroupSaveForm($action)
280     {
281         $gps = null;
282
283         if (!empty($action->group)) {
284             $gps = Group_privacy_settings::staticGet('group_id', $action->group->id);
285         }
286
287         $orig = null;
288
289         if (empty($gps)) {
290             $gps = new Group_privacy_settings();
291             $gps->group_id = $action->group->id;
292         } else {
293             $orig = clone($gps);
294         }
295         
296         $gps->allow_privacy = $action->trimmed('allow_privacy');
297         $gps->allow_sender  = $action->trimmed('allow_sender');
298
299         if (empty($orig)) {
300             $gps->created = common_sql_now();
301             $gps->insert();
302         } else {
303             $gps->update($orig);
304         }
305         
306         return true;
307     }
308
309     /**
310      * Overload 'd' command to send private messages to groups.
311      * 
312      * 'd !group word word word' will send the private message
313      * 'word word word' to the group 'group'.
314      * 
315      * @param string  $cmd     Command being run
316      * @param string  $arg     Rest of the message (including address)
317      * @param User    $user    User sending the message
318      * @param Command &$result The resulting command object to be run.
319      * 
320      * @return boolean hook value
321      */
322     function onStartIntepretCommand($cmd, $arg, $user, &$result)
323     {
324         if ($cmd == 'd' || $cmd == 'dm') {
325
326             $this->debug('Got a d command');
327
328             // Break off the first word as the address
329
330             $pieces = explode(' ', $arg, 2);
331
332             if (count($pieces) == 1) {
333                 $pieces[] = null;
334             }
335
336             list($addr, $msg) = $pieces;
337
338             if (!empty($addr) && $addr[0] == '!') {
339                 $result = new GroupMessageCommand($user, substr($addr, 1), $msg);
340                 Event::handle('EndInterpretCommand', array($cmd, $arg, $user, $result));
341                 return false;
342             }
343         }
344
345         return true;
346     }
347
348     /**
349      * To add a "Message" button to the group profile page
350      *
351      * @param Widget     $widget The showgroup action being shown
352      * @param User_group $group  The current group
353      * 
354      * @return boolean hook value
355      */
356     function onEndGroupActionsList($widget, $group)
357     {
358         $cur = common_current_user();
359         $action = $widget->out;
360
361         if (empty($cur)) {
362             return true;
363         }
364
365         try {
366             Group_privacy_settings::ensurePost($cur, $group);
367         } catch (Exception $e) {
368             return true;
369         }
370
371         $action->elementStart('li', 'entity_send-a-message');
372         $action->element('a', array('href' => common_local_url('newgroupmessage', array('nickname' => $group->nickname)),
373                                     'title' => _m('Send a direct message to this group.')),
374                          _m('Message'));
375         // $form = new GroupMessageForm($action, $group);
376         // $form->hidden = true;
377         // $form->show();
378         $action->elementEnd('li');
379         return true;
380     }
381
382     /**
383      * When saving a notice, check its groups. If any of them has
384      * privacy == always, force a group private message to all mentioned groups.
385      * If any of the groups disallows private messages, skip it.
386      *
387      * @param 
388      *
389      */
390
391     function onStartNoticeSave(&$notice) {
392
393         // Look for group tags
394         // FIXME: won't work for remote groups
395         // @fixme if Notice::saveNew is refactored so we can just pull its list
396         // of groups between processing and saving, make use of it
397
398         $count = preg_match_all('/(?:^|\s)!(' . Nickname::DISPLAY_FMT . ')/',
399                                 strtolower($notice->content),
400                                 $match);
401
402         $groups = array();
403         $ignored = array();
404
405         $forcePrivate = false;
406         $profile = $notice->getProfile();
407
408         if ($count > 0) {
409
410             /* Add them to the database */
411
412             foreach (array_unique($match[1]) as $nickname) {
413
414                 $group = User_group::getForNickname($nickname, $profile);
415
416                 if (empty($group)) {
417                     continue;
418                 }
419
420                 $gps = Group_privacy_settings::forGroup($group);
421
422                 switch ($gps->allow_privacy) {
423                 case Group_privacy_settings::ALWAYS:
424                     $forcePrivate = true;
425                     // fall through
426                 case Group_privacy_settings::SOMETIMES:
427                     $groups[] = $group;
428                     break;
429                 case Group_privacy_settings::NEVER:
430                     $ignored[] = $group;
431                     break;
432                 }
433             }
434
435             if ($forcePrivate) {
436
437                 foreach ($ignored as $group) {
438                     common_log(LOG_NOTICE,
439                                "Notice forced to group direct message ".
440                                "but group ".$group->nickname." does not allow them.");
441                 }
442
443                 $user = User::staticGet('id', $notice->profile_id);
444
445                 if (empty($user)) {
446                     common_log(LOG_WARNING,
447                                "Notice forced to group direct message ".
448                                "but profile ".$notice->profile_id." is not a local user.");
449                 } else {
450                     foreach ($groups as $group) {
451                         Group_message::send($user, $group, $notice->content);
452                     }
453                 }
454
455                 // Don't save the notice!
456                 // FIXME: this is probably cheating.
457                 throw new ClientException(sprintf(_m('Forced notice to private group message.')),
458                                           200);
459             }
460         }
461         
462         return true;
463     }
464
465     /**
466      * Show an indicator that the group is (essentially) private on the group page
467      *
468      * @param Action     $action The action being shown
469      * @param User_group $group  The group being shown
470      *
471      * @return boolean hook value
472      */
473
474     function onEndGroupProfileElements($action, $group)
475     {
476         $gps = Group_privacy_settings::forGroup($group);
477         
478         if ($gps->allow_privacy == Group_privacy_settings::ALWAYS) {
479             $action->element('p', 'privategroupindicator', _m('Private'));
480         }
481
482         return true;
483     }
484
485     function onStartShowExportData($action)
486     {
487         if ($action instanceof ShowgroupAction) {
488             $gps = Group_privacy_settings::forGroup($action->group);
489         
490             if ($gps->allow_privacy == Group_privacy_settings::ALWAYS) {
491                 return false;
492             }
493         }
494         return true;
495     }
496
497     function onPluginVersion(&$versions)
498     {
499         $versions[] = array('name' => 'GroupPrivateMessage',
500                             'version' => STATUSNET_VERSION,
501                             'author' => 'Evan Prodromou',
502                             'homepage' => 'http://status.net/wiki/Plugin:GroupPrivateMessage',
503                             'rawdescription' =>
504                             _m('Allow posting private messages to groups.'));
505         return true;
506     }
507 }