1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Elgg wire plugin |
4
|
|
|
* |
5
|
|
|
* Forked from Curverider's version |
6
|
|
|
* |
7
|
|
|
* JHU/APL Contributors: |
8
|
|
|
* Cash Costello |
9
|
|
|
* Clark Updike |
10
|
|
|
* John Norton |
11
|
|
|
* Max Thomas |
12
|
|
|
* Nathan Koterba |
13
|
|
|
*/ |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* The Wire initialization |
17
|
|
|
* |
18
|
|
|
* @return void |
19
|
|
|
*/ |
20
|
|
|
function thewire_init() { |
21
|
|
|
|
22
|
31 |
|
elgg_register_ajax_view('thewire/previous'); |
23
|
|
|
|
24
|
|
|
// add a site navigation item |
25
|
31 |
|
elgg_register_menu_item('site', [ |
26
|
31 |
|
'name' => 'thewire', |
27
|
31 |
|
'text' => elgg_echo('thewire'), |
28
|
31 |
|
'href' => 'thewire/all', |
29
|
|
|
]); |
30
|
|
|
|
31
|
|
|
// owner block menu |
32
|
31 |
|
elgg_register_plugin_hook_handler('register', 'menu:owner_block', 'thewire_owner_block_menu'); |
33
|
|
|
|
34
|
|
|
// remove edit and access and add thread, reply, view previous |
35
|
31 |
|
elgg_register_plugin_hook_handler('register', 'menu:entity', 'thewire_setup_entity_menu_items'); |
36
|
|
|
|
37
|
|
|
// Extend system CSS with our own styles, which are defined in the thewire/css view |
38
|
31 |
|
elgg_extend_view('elgg.css', 'thewire/css'); |
39
|
|
|
|
40
|
|
|
// Register a page handler, so we can have nice URLs |
41
|
31 |
|
elgg_register_page_handler('thewire', 'thewire_page_handler'); |
|
|
|
|
42
|
|
|
|
43
|
|
|
// Register a URL handler for thewire posts |
44
|
31 |
|
elgg_register_plugin_hook_handler('entity:url', 'object', 'thewire_set_url'); |
45
|
|
|
|
46
|
|
|
// Register for notifications |
47
|
31 |
|
elgg_register_notification_event('object', 'thewire'); |
48
|
31 |
|
elgg_register_plugin_hook_handler('prepare', 'notification:create:object:thewire', 'thewire_prepare_notification'); |
49
|
31 |
|
elgg_register_plugin_hook_handler('get', 'subscriptions', 'thewire_add_original_poster'); |
50
|
|
|
|
51
|
|
|
// allow to be liked |
52
|
31 |
|
elgg_register_plugin_hook_handler('likes:is_likable', 'object:thewire', 'Elgg\Values::getTrue'); |
53
|
|
|
|
54
|
31 |
|
elgg_register_plugin_hook_handler('unit_test', 'system', 'thewire_test'); |
55
|
31 |
|
} |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* The wire page handler |
59
|
|
|
* |
60
|
|
|
* Supports: |
61
|
|
|
* thewire/all View site wire posts |
62
|
|
|
* thewire/owner/<username> View this user's wire posts |
63
|
|
|
* thewire/following/<username> View the posts of those this user follows |
64
|
|
|
* thewire/reply/<guid> Reply to a post |
65
|
|
|
* thewire/view/<guid> View a post |
66
|
|
|
* thewire/thread/<id> View a conversation thread |
67
|
|
|
* thewire/tag/<tag> View wire posts tagged with <tag> |
68
|
|
|
* |
69
|
|
|
* @param array $page From the page_handler function |
70
|
|
|
* |
71
|
|
|
* @return bool |
72
|
|
|
*/ |
73
|
|
|
function thewire_page_handler($page) { |
74
|
|
|
|
75
|
|
|
if (!isset($page[0])) { |
76
|
|
|
$page = ['all']; |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
switch ($page[0]) { |
80
|
|
|
case "all": |
81
|
|
|
echo elgg_view_resource('thewire/everyone'); |
82
|
|
|
break; |
83
|
|
|
|
84
|
|
|
case "friends": |
85
|
|
|
echo elgg_view_resource('thewire/friends'); |
86
|
|
|
break; |
87
|
|
|
|
88
|
|
|
case "owner": |
89
|
|
|
echo elgg_view_resource('thewire/owner'); |
90
|
|
|
break; |
91
|
|
|
|
92
|
|
|
case "view": |
93
|
|
|
echo elgg_view_resource('thewire/view', [ |
94
|
|
|
'guid' => elgg_extract(1, $page), |
95
|
|
|
]); |
96
|
|
|
break; |
97
|
|
|
|
98
|
|
|
case "thread": |
99
|
|
|
echo elgg_view_resource('thewire/thread', [ |
100
|
|
|
'thread_id' => elgg_extract(1, $page), |
101
|
|
|
]); |
102
|
|
|
break; |
103
|
|
|
|
104
|
|
|
case "reply": |
105
|
|
|
echo elgg_view_resource('thewire/reply', [ |
106
|
|
|
'guid' => elgg_extract(1, $page), |
107
|
|
|
]); |
108
|
|
|
break; |
109
|
|
|
|
110
|
|
|
case "tag": |
111
|
|
|
echo elgg_view_resource('thewire/tag', [ |
112
|
|
|
'tag' => elgg_extract(1, $page), |
113
|
|
|
]); |
114
|
|
|
break; |
115
|
|
|
|
116
|
|
|
case "previous": |
117
|
|
|
echo elgg_view_resource('thewire/previous', [ |
118
|
|
|
'guid' => elgg_extract(1, $page), |
119
|
|
|
]); |
120
|
|
|
break; |
121
|
|
|
|
122
|
|
|
default: |
123
|
|
|
return false; |
124
|
|
|
} |
125
|
|
|
return true; |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
/** |
129
|
|
|
* Override the url for a wire post to return the thread |
130
|
|
|
* |
131
|
|
|
* @param string $hook 'entity:url' |
132
|
|
|
* @param string $type 'object' |
133
|
|
|
* @param string $url current return value |
134
|
|
|
* @param array $params supplied params |
135
|
|
|
* |
136
|
|
|
* @return void|string |
137
|
|
|
*/ |
138
|
|
|
function thewire_set_url($hook, $type, $url, $params) { |
139
|
|
|
|
140
|
3 |
|
$entity = elgg_extract('entity', $params); |
141
|
3 |
|
if (!$entity instanceof ElggWire) { |
142
|
3 |
|
return; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
return "thewire/view/{$entity->guid}"; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Prepare a notification message about a new wire post |
150
|
|
|
* |
151
|
|
|
* @param string $hook Hook name |
152
|
|
|
* @param string $type Hook type |
153
|
|
|
* @param Elgg\Notifications\Notification $notification The notification to prepare |
154
|
|
|
* @param array $params Hook parameters |
155
|
|
|
* |
156
|
|
|
* @return Elgg\Notifications\Notification |
157
|
|
|
*/ |
158
|
|
|
function thewire_prepare_notification($hook, $type, $notification, $params) { |
159
|
|
|
|
160
|
|
|
$entity = $params['event']->getObject(); |
161
|
|
|
$owner = $params['event']->getActor(); |
162
|
|
|
$recipient = $params['recipient']; |
|
|
|
|
163
|
|
|
$language = $params['language']; |
164
|
|
|
$method = $params['method']; |
|
|
|
|
165
|
|
|
$descr = $entity->description; |
166
|
|
|
|
167
|
|
|
$subject = elgg_echo('thewire:notify:subject', [$owner->name], $language); |
168
|
|
|
if ($entity->reply) { |
169
|
|
|
$parent = thewire_get_parent($entity->guid); |
170
|
|
|
if ($parent) { |
171
|
|
|
$parent_owner = $parent->getOwnerEntity(); |
172
|
|
|
$body = elgg_echo('thewire:notify:reply', [$owner->name, $parent_owner->name], $language); |
173
|
|
|
} |
174
|
|
|
} else { |
175
|
|
|
$body = elgg_echo('thewire:notify:post', [$owner->name], $language); |
176
|
|
|
} |
177
|
|
|
$body .= "\n\n" . $descr . "\n\n"; |
|
|
|
|
178
|
|
|
$body .= elgg_echo('thewire:notify:footer', [$entity->getURL()], $language); |
179
|
|
|
|
180
|
|
|
$notification->subject = $subject; |
181
|
|
|
$notification->body = $body; |
182
|
|
|
$notification->summary = elgg_echo('thewire:notify:summary', [$descr], $language); |
183
|
|
|
$notification->url = $entity->getURL(); |
184
|
|
|
|
185
|
|
|
return $notification; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
/** |
189
|
|
|
* Get an array of hashtags from a text string |
190
|
|
|
* |
191
|
|
|
* @param string $text The text of a post |
192
|
|
|
* |
193
|
|
|
* @return array |
194
|
|
|
*/ |
195
|
|
|
function thewire_get_hashtags($text) { |
196
|
|
|
// beginning of text or white space followed by hashtag |
197
|
|
|
// hashtag must begin with # and contain at least one character not digit, space, or punctuation |
198
|
|
|
$matches = []; |
199
|
|
|
preg_match_all('/(^|[^\w])#(\w*[^\s\d!-\/:-@]+\w*)/', $text, $matches); |
200
|
|
|
|
201
|
|
|
return $matches[2]; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
/** |
205
|
|
|
* Replace urls, hash tags, and @'s by links |
206
|
|
|
* |
207
|
|
|
* @param string $text The text of a post |
208
|
|
|
* |
209
|
|
|
* @return string |
210
|
|
|
*/ |
211
|
|
|
function thewire_filter($text) { |
212
|
|
|
$text = ' ' . $text; |
213
|
|
|
|
214
|
|
|
// email addresses |
215
|
|
|
$text = preg_replace( |
216
|
|
|
'/(^|[^\w])([\w\-\.]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})/i', |
217
|
|
|
'$1<a href="mailto:$2@$3">$2@$3</a>', |
218
|
|
|
$text); |
219
|
|
|
|
220
|
|
|
// links |
221
|
|
|
$text = parse_urls($text); |
222
|
|
|
|
223
|
|
|
// usernames |
224
|
|
|
$text = preg_replace( |
225
|
|
|
'/(^|[^\w])@([\p{L}\p{Nd}._]+)/u', |
226
|
|
|
'$1<a href="' . elgg_get_site_url() . 'thewire/owner/$2">@$2</a>', |
227
|
|
|
$text); |
228
|
|
|
|
229
|
|
|
// hashtags |
230
|
|
|
$text = preg_replace( |
231
|
|
|
'/(^|[^\w])#(\w*[^\s\d!-\/:-@]+\w*)/', |
232
|
|
|
'$1<a href="' . elgg_get_site_url() . 'thewire/tag/$2">#$2</a>', |
233
|
|
|
$text); |
234
|
|
|
|
235
|
|
|
return trim($text); |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
/** |
239
|
|
|
* Create a new wire post. |
240
|
|
|
* |
241
|
|
|
* @param string $text The post text |
242
|
|
|
* @param int $userid The user's guid |
243
|
|
|
* @param int $access_id Public/private etc |
244
|
|
|
* @param int $parent_guid Parent post guid (if any) |
245
|
|
|
* @param string $method The method (default: 'site') |
246
|
|
|
* |
247
|
|
|
* @return false|int |
248
|
|
|
*/ |
249
|
|
|
function thewire_save_post($text, $userid, $access_id, $parent_guid = 0, $method = "site") { |
250
|
|
|
|
251
|
|
|
$post = new ElggWire(); |
252
|
|
|
$post->owner_guid = $userid; |
253
|
|
|
$post->access_id = $access_id; |
254
|
|
|
|
255
|
|
|
// Character limit is now from config |
256
|
|
|
$limit = elgg_get_plugin_setting('limit', 'thewire'); |
257
|
|
|
if ($limit > 0) { |
258
|
|
|
$text = elgg_substr($text, 0, $limit); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
// no html tags allowed so we escape |
262
|
|
|
$post->description = htmlspecialchars($text, ENT_NOQUOTES | ENT_SUBSTITUTE, 'UTF-8'); |
263
|
|
|
|
264
|
|
|
$post->method = $method; //method: site, email, api, ... |
265
|
|
|
|
266
|
|
|
$tags = thewire_get_hashtags($text); |
267
|
|
|
if ($tags) { |
|
|
|
|
268
|
|
|
$post->tags = $tags; |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
// must do this before saving so notifications pick up that this is a reply |
272
|
|
|
if ($parent_guid) { |
273
|
|
|
$post->reply = true; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
$guid = $post->save(); |
277
|
|
|
if ($guid === false) { |
278
|
|
|
return false; |
279
|
|
|
} |
280
|
|
|
|
281
|
|
|
// set thread guid |
282
|
|
|
if ($parent_guid) { |
283
|
|
|
$post->addRelationship($parent_guid, 'parent'); |
284
|
|
|
|
285
|
|
|
// name conversation threads by guid of first post (works even if first post deleted) |
286
|
|
|
$parent_post = get_entity($parent_guid); |
287
|
|
|
$post->wire_thread = $parent_post->wire_thread; |
288
|
|
|
} else { |
289
|
|
|
// first post in this thread |
290
|
|
|
$post->wire_thread = $guid; |
|
|
|
|
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
elgg_create_river_item([ |
294
|
|
|
'view' => 'river/object/thewire/create', |
295
|
|
|
'action_type' => 'create', |
296
|
|
|
'subject_guid' => $post->owner_guid, |
297
|
|
|
'object_guid' => $post->guid, |
298
|
|
|
]); |
299
|
|
|
|
300
|
|
|
// let other plugins know we are setting a user status |
301
|
|
|
$params = [ |
302
|
|
|
'entity' => $post, |
303
|
|
|
'user' => $post->getOwnerEntity(), |
304
|
|
|
'message' => $post->description, |
305
|
|
|
'url' => $post->getURL(), |
306
|
|
|
'origin' => 'thewire', |
307
|
|
|
]; |
308
|
|
|
elgg_trigger_plugin_hook('status', 'user', $params); |
309
|
|
|
|
310
|
|
|
return $guid; |
|
|
|
|
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Add temporary subscription for original poster if not already registered to |
315
|
|
|
* receive a notification of reply |
316
|
|
|
* |
317
|
|
|
* @param string $hook Hook name |
318
|
|
|
* @param string $type Hook type |
319
|
|
|
* @param array $subscriptions Subscriptions for a notification event |
320
|
|
|
* @param array $params Parameters including the event |
321
|
|
|
* |
322
|
|
|
* @return void|array |
323
|
|
|
*/ |
324
|
|
|
function thewire_add_original_poster($hook, $type, $subscriptions, $params) { |
325
|
2 |
|
$event = elgg_extract('event', $params); |
326
|
2 |
|
$entity = $event->getObject(); |
327
|
2 |
|
if (!($entity instanceof ElggWire)) { |
328
|
2 |
|
return; |
329
|
|
|
} |
330
|
|
|
|
331
|
|
|
$parents = $entity->getEntitiesFromRelationship([ |
332
|
|
|
'type' => 'object', |
333
|
|
|
'subtype' => 'thewire', |
334
|
|
|
'relationship' => 'parent', |
335
|
|
|
]); |
336
|
|
|
if (empty($parents)) { |
337
|
|
|
return; |
338
|
|
|
} |
339
|
|
|
|
340
|
|
|
/* @var $parent ElggWire */ |
341
|
|
|
$parent = $parents[0]; |
342
|
|
|
// do not add a subscription if reply was to self |
343
|
|
|
if ($parent->getOwnerGUID() === $entity->getOwnerGUID()) { |
344
|
|
|
return; |
345
|
|
|
} |
346
|
|
|
|
347
|
|
|
if (array_key_exists($parent->getOwnerGUID(), $subscriptions)) { |
348
|
|
|
// already in the list |
349
|
|
|
return; |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/* @var $parent_owner ElggUser */ |
353
|
|
|
$parent_owner = $parent->getOwnerEntity(); |
354
|
|
|
$personal_methods = $parent_owner->getNotificationSettings(); |
355
|
|
|
$methods = []; |
356
|
|
|
foreach ($personal_methods as $method => $state) { |
357
|
|
|
if ($state) { |
358
|
|
|
$methods[] = $method; |
359
|
|
|
} |
360
|
|
|
} |
361
|
|
|
|
362
|
|
|
if (empty($methods)) { |
363
|
|
|
return; |
364
|
|
|
} |
365
|
|
|
|
366
|
|
|
$subscriptions[$parent->getOwnerGUID()] = $methods; |
367
|
|
|
return $subscriptions; |
368
|
|
|
} |
369
|
|
|
|
370
|
|
|
/** |
371
|
|
|
* Get the latest wire guid - used for ajax update |
372
|
|
|
* |
373
|
|
|
* @return int |
374
|
|
|
*/ |
375
|
|
|
function thewire_latest_guid() { |
376
|
|
|
$post = elgg_get_entities([ |
377
|
|
|
'type' => 'object', |
378
|
|
|
'subtype' => 'thewire', |
379
|
|
|
'limit' => 1, |
380
|
|
|
]); |
381
|
|
|
if ($post) { |
382
|
|
|
return $post[0]->guid; |
383
|
|
|
} |
384
|
|
|
|
385
|
|
|
return 0; |
386
|
|
|
} |
387
|
|
|
|
388
|
|
|
/** |
389
|
|
|
* Get the parent of a wire post |
390
|
|
|
* |
391
|
|
|
* @param int $post_guid The guid of the reply |
392
|
|
|
* |
393
|
|
|
* @return void|ElggObject |
394
|
|
|
*/ |
395
|
|
|
function thewire_get_parent($post_guid) { |
396
|
|
|
$parents = elgg_get_entities([ |
397
|
|
|
'relationship' => 'parent', |
398
|
|
|
'relationship_guid' => $post_guid, |
399
|
|
|
'limit' => 1, |
400
|
|
|
]); |
401
|
|
|
if ($parents) { |
402
|
|
|
return $parents[0]; |
403
|
|
|
} |
404
|
|
|
} |
405
|
|
|
|
406
|
|
|
/** |
407
|
|
|
* Sets up the entity menu for thewire |
408
|
|
|
* |
409
|
|
|
* Adds reply, thread, and view previous links. Removes edit and access. |
410
|
|
|
* |
411
|
|
|
* @param string $hook 'register' |
412
|
|
|
* @param string $type 'menu:entity' |
413
|
|
|
* @param ElggMenuItem[] $value Array of menu items |
414
|
|
|
* @param array $params Array with the entity |
415
|
|
|
* |
416
|
|
|
* @return void|ElggMenuItem[] |
417
|
|
|
*/ |
418
|
|
|
function thewire_setup_entity_menu_items($hook, $type, $value, $params) { |
419
|
|
|
|
420
|
1 |
|
$entity = elgg_extract('entity', $params); |
421
|
1 |
|
if (!($entity instanceof \ElggWire)) { |
422
|
1 |
|
return; |
423
|
|
|
} |
424
|
|
|
|
425
|
|
|
foreach ($value as $index => $item) { |
426
|
|
|
if ($item->getName() == 'edit') { |
427
|
|
|
unset($value[$index]); |
428
|
|
|
} |
429
|
|
|
} |
430
|
|
|
|
431
|
|
|
if (elgg_is_logged_in()) { |
432
|
|
|
$value[] = ElggMenuItem::factory([ |
433
|
|
|
'name' => 'reply', |
434
|
|
|
'icon' => 'reply', |
435
|
|
|
'text' => elgg_echo('reply'), |
436
|
|
|
'href' => "thewire/reply/{$entity->guid}", |
437
|
|
|
]); |
438
|
|
|
} |
439
|
|
|
|
440
|
|
|
if ($entity->reply) { |
441
|
|
|
$value[] = ElggMenuItem::factory([ |
442
|
|
|
'name' => 'previous', |
443
|
|
|
'icon' => 'arrow-left', |
444
|
|
|
'text' => elgg_echo('previous'), |
445
|
|
|
'href' => "thewire/previous/{$entity->guid}", |
446
|
|
|
'link_class' => 'thewire-previous', |
447
|
|
|
'title' => elgg_echo('thewire:previous:help'), |
448
|
|
|
]); |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
$value[] = ElggMenuItem::factory([ |
452
|
|
|
'name' => 'thread', |
453
|
|
|
'icon' => 'comments-o', |
454
|
|
|
'text' => elgg_echo('thewire:thread'), |
455
|
|
|
'href' => "thewire/thread/{$entity->wire_thread}", |
456
|
|
|
]); |
457
|
|
|
|
458
|
|
|
return $value; |
459
|
|
|
} |
460
|
|
|
|
461
|
|
|
/** |
462
|
|
|
* Add a menu item to an ownerblock |
463
|
|
|
* |
464
|
|
|
* @param string $hook 'register' |
465
|
|
|
* @param string $type 'menu:owner_block' |
466
|
|
|
* @param ElggMenuItem[] $return current return value |
467
|
|
|
* @param array $params supplied params |
468
|
|
|
* |
469
|
|
|
* @return void|ElggMenuItem[] |
470
|
|
|
*/ |
471
|
|
|
function thewire_owner_block_menu($hook, $type, $return, $params) { |
472
|
|
|
|
473
|
|
|
$user = elgg_extract('entity', $params); |
474
|
|
|
if (!$user instanceof \ElggUser) { |
475
|
|
|
return; |
476
|
|
|
} |
477
|
|
|
|
478
|
|
|
$return[] = \ElggMenuItem::factory([ |
479
|
|
|
'name' => 'thewire', |
480
|
|
|
'text' => elgg_echo('item:object:thewire'), |
481
|
|
|
'href' => "thewire/owner/{$params['entity']->username}", |
482
|
|
|
]); |
483
|
|
|
|
484
|
|
|
return $return; |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Runs unit tests for the wire |
489
|
|
|
* |
490
|
|
|
* @param string $hook 'unit_test' |
491
|
|
|
* @param string $type 'system' |
492
|
|
|
* @param array $value current return value |
493
|
|
|
* @param array $params supplied params |
494
|
|
|
* |
495
|
|
|
* @return array |
496
|
|
|
*/ |
497
|
|
|
function thewire_test($hook, $type, $value, $params) { |
498
|
|
|
$value[] = elgg_get_plugins_path() . 'thewire/tests/regex.php'; |
499
|
|
|
return $value; |
500
|
|
|
} |
501
|
|
|
|
502
|
|
|
return function() { |
503
|
18 |
|
elgg_register_event_handler('init', 'system', 'thewire_init'); |
504
|
|
|
}; |
505
|
|
|
|
This function has been deprecated. The supplier of the function has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.