1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Handles all the mentions actions so members are notified of mentionable actions |
5
|
|
|
* |
6
|
|
|
* @name ElkArte Forum |
7
|
|
|
* @copyright ElkArte Forum contributors |
8
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
9
|
|
|
* |
10
|
|
|
* @version 1.0 |
11
|
|
|
* |
12
|
|
|
*/ |
13
|
|
|
|
14
|
|
|
if (!defined('ELK')) |
15
|
|
|
die('No access...'); |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Takes care of validating and inserting mention notifications in the database |
19
|
|
|
* |
20
|
|
|
* @package Mentions |
21
|
|
|
*/ |
22
|
|
|
class Mentioning extends AbstractModel |
23
|
|
|
{ |
24
|
|
|
/** |
25
|
|
|
* Value assumed by a new mention |
26
|
|
|
* |
27
|
|
|
* @const int |
28
|
|
|
*/ |
29
|
|
|
const MNEW = 0; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Value assumed by a mention that has been read |
33
|
|
|
* |
34
|
|
|
* @const int |
35
|
|
|
*/ |
36
|
|
|
const READ = 1; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Value assumed by a mention that has been deleted |
40
|
|
|
* |
41
|
|
|
* @const int |
42
|
|
|
*/ |
43
|
|
|
const DELETED = 2; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Value assumed by an unapproved mention |
47
|
|
|
* |
48
|
|
|
* @const int |
49
|
|
|
*/ |
50
|
|
|
const UNAPPROVED = 3; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Will hold all available mention types |
54
|
|
|
* |
55
|
|
|
* @var array |
56
|
|
|
*/ |
57
|
|
|
protected $_known_mentions = array(); |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Will hold all available mention status |
61
|
|
|
* 'new' => 0, 'read' => 1, 'deleted' => 2, 'unapproved' => 3, |
62
|
|
|
* |
63
|
|
|
* @var array |
64
|
|
|
*/ |
65
|
|
|
protected $_known_status = array(); |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Holds the instance of the data validation class |
69
|
|
|
* |
70
|
|
|
* @var object |
71
|
|
|
*/ |
72
|
|
|
protected $_validator = null; |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Holds the passed data for this instance, is passed through the validator |
76
|
|
|
* |
77
|
|
|
* @var array |
78
|
|
|
*/ |
79
|
|
|
protected $_data = null; |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Start things up, what else does a constructor do |
83
|
|
|
*/ |
84
|
|
|
public function __construct($db, $validator, $enabled_mentions = '') |
85
|
|
|
{ |
86
|
|
|
$this->_known_status = array( |
87
|
|
|
'new' => Mentioning::MNEW, |
88
|
|
|
'read' => Mentioning::READ, |
89
|
|
|
'deleted' => Mentioning::DELETED, |
90
|
|
|
'unapproved' => Mentioning::UNAPPROVED, |
91
|
|
|
); |
92
|
|
|
|
93
|
|
|
$this->_validator = $validator; |
94
|
|
|
|
95
|
|
|
$this->_known_mentions = array_filter(array_unique(explode(',', $enabled_mentions))); |
96
|
|
|
|
97
|
|
|
parent::__construct($db); |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Inserts a new mention. |
102
|
|
|
* |
103
|
|
|
* @param Mention_Type_Interface $mention_obj The object that knows how to store |
104
|
|
|
* the mention in the database |
105
|
|
|
* @param mixed[] $data must contain uid, type and msg at a minimum |
106
|
|
|
*/ |
107
|
|
|
public function create($mention_obj, $data) |
108
|
|
|
{ |
109
|
|
|
global $user_info; |
110
|
|
|
|
111
|
|
|
$this->_data = $this->_prepareData($data); |
112
|
|
|
|
113
|
|
|
// Common checks to determine if we can go on |
114
|
|
|
if (!$this->_isValid()) |
115
|
|
|
return false; |
116
|
|
|
|
117
|
|
|
// Cleanup, validate and remove the invalid values (0 and $user_info['id']) |
|
|
|
|
118
|
|
|
$id_targets = array_diff(array_map('intval', array_unique($this->_validator->uid)), array(0, $user_info['id'])); |
119
|
|
|
|
120
|
|
|
if (empty($id_targets)) |
121
|
|
|
return false; |
122
|
|
|
|
123
|
|
|
$mention_obj->setDb($this->_db); |
124
|
|
|
$mention_obj->insert($user_info['id'], $id_targets, $this->_validator->msg, $this->_validator->log_time, $this->_data['status']); |
125
|
|
|
|
126
|
|
|
// Update the member mention count |
127
|
|
|
foreach ($id_targets as $id_target) |
128
|
|
|
$this->_updateMenuCount($this->_data['status'], $id_target); |
129
|
|
|
|
130
|
|
|
return true; |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Prepares the data send through Mentioning::create to be ready for the |
135
|
|
|
* actual insert. |
136
|
|
|
* |
137
|
|
|
* @param mixed[] $data must contain uid, type and msg at a minimum |
138
|
|
|
*/ |
139
|
|
|
protected function _prepareData($data) |
140
|
|
|
{ |
141
|
|
|
if (isset($data['id_member'])) |
142
|
|
|
{ |
143
|
|
|
$_data = array( |
144
|
|
|
'uid' => is_array($data['id_member']) ? $data['id_member'] : array($data['id_member']), |
145
|
|
|
'type' => $data['type'], |
146
|
|
|
'msg' => $data['id_msg'], |
147
|
|
|
'status' => isset($data['status']) && isset($this->_known_status[$data['status']]) ? $this->_known_status[$data['status']] : 0, |
148
|
|
|
); |
149
|
|
|
|
150
|
|
|
if (isset($data['id_member_from'])) |
151
|
|
|
$_data['id_member_from'] = $data['id_member_from']; |
152
|
|
|
|
153
|
|
|
if (isset($data['log_time'])) |
154
|
|
|
$_data['log_time'] = $data['log_time']; |
155
|
|
|
} |
156
|
|
|
else |
157
|
|
|
$_data = $data; |
158
|
|
|
|
159
|
|
|
return $_data; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
/** |
163
|
|
|
* Did you read the mention? Then let's move it to the graveyard. |
164
|
|
|
* Used in Display.controller.php, it may be merged to action_updatestatus |
165
|
|
|
* though that would require to add an optional parameter to avoid the redirect |
166
|
|
|
*/ |
167
|
|
|
public function markread($mention_id) |
168
|
|
|
{ |
169
|
|
|
$this->updateStatus($mention_id, 'readall'); |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
/** |
173
|
|
|
* Updating the status from the listing? |
174
|
|
|
*/ |
175
|
|
|
public function updateStatus($items, $mark) |
176
|
|
|
{ |
177
|
|
|
// Make sure its all good |
178
|
|
|
$own_id = $this->_getAccessible((array) $items, $mark); |
179
|
|
|
|
180
|
|
|
if (!empty($own_id)) |
181
|
|
|
{ |
182
|
|
|
switch ($mark) |
183
|
|
|
{ |
184
|
|
|
case 'read': |
185
|
|
|
case 'readall': |
186
|
|
|
$this->_changeStatus($own_id, 'read'); |
187
|
|
|
break; |
188
|
|
|
case 'unread': |
189
|
|
|
$this->_changeStatus($own_id, 'new'); |
190
|
|
|
break; |
191
|
|
|
case 'delete': |
192
|
|
|
$this->_changeStatus($own_id, 'deleted'); |
193
|
|
|
break; |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
/** |
199
|
|
|
* Of the passed IDs returns those accessible to the user. |
200
|
|
|
* |
201
|
|
|
* @param int[] $mention_ids |
202
|
|
|
* @param string $action |
203
|
|
|
* @return int[] |
204
|
|
|
*/ |
205
|
|
|
protected function _getAccessible($mention_ids, $action) |
206
|
|
|
{ |
207
|
|
|
require_once(SUBSDIR . '/Mentions.subs.php'); |
208
|
|
|
$sanitization = array( |
209
|
|
|
'id_mention' => 'intval', |
210
|
|
|
'mark' => 'trim', |
211
|
|
|
); |
212
|
|
|
$validation = array( |
213
|
|
|
'id_mention' => 'validate_ownmention', |
214
|
|
|
'mark' => 'contains[read,unread,delete,readall]', |
215
|
|
|
); |
216
|
|
|
|
217
|
|
|
$this->_validator->sanitation_rules($sanitization); |
218
|
|
|
$this->_validator->validation_rules($validation); |
219
|
|
|
|
220
|
|
|
$own = array(); |
221
|
|
|
foreach ($mention_ids as $id) |
222
|
|
|
{ |
223
|
|
|
if ($this->_validator->validate(array('id_mention' => $id, 'mark' => $action))) |
224
|
|
|
$own[] = $id; |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
return $own; |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
/** |
231
|
|
|
* Check if the user can do what he is supposed to do, and validates the input. |
232
|
|
|
*/ |
233
|
|
|
protected function _isValid() |
234
|
|
|
{ |
235
|
|
|
$sanitization = array( |
236
|
|
|
'type' => 'trim', |
237
|
|
|
'msg' => 'intval', |
238
|
|
|
); |
239
|
|
|
$validation = array( |
240
|
|
|
'type' => 'required|contains[' . implode(',', $this->_known_mentions) . ']', |
241
|
|
|
'uid' => 'isarray', |
242
|
|
|
); |
243
|
|
|
|
244
|
|
|
// Any optional fields we need to check? |
245
|
|
|
if (isset($this->_data['id_member_from'])) |
246
|
|
|
{ |
247
|
|
|
$sanitization['id_member_from'] = 'intval'; |
248
|
|
|
$validation['id_member_from'] = 'required|notequal[0]'; |
249
|
|
|
} |
250
|
|
|
if (isset($this->_data['log_time'])) |
251
|
|
|
{ |
252
|
|
|
$sanitization['log_time'] = 'intval'; |
253
|
|
|
$validation['log_time'] = 'required|notequal[0]'; |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
$this->_validator->sanitation_rules($sanitization); |
257
|
|
|
$this->_validator->validation_rules($validation); |
258
|
|
|
|
259
|
|
|
if (!$this->_validator->validate($this->_data)) |
260
|
|
|
return false; |
261
|
|
|
|
262
|
|
|
// If everything is fine, let's prepare for the fun! |
263
|
|
|
loadLanguage('Mentions'); |
264
|
|
|
|
265
|
|
|
return true; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* Changes a specific mention status for a member. |
270
|
|
|
* |
271
|
|
|
* - Can be used to mark as read, new, deleted, etc |
272
|
|
|
* - note that delete is a "soft-delete" because otherwise anyway we have to remember |
273
|
|
|
* - when a user was already mentioned for a certain message (e.g. in case of editing) |
274
|
|
|
* |
275
|
|
|
* @package Mentions |
276
|
|
|
* @param int|int[] $id_mentions the mention id in the db |
277
|
|
|
* @param string $status status to update, 'new', 'read', 'deleted', 'unapproved' |
278
|
|
|
*/ |
279
|
|
|
protected function _changeStatus($id_mentions, $status = 'read') |
280
|
|
|
{ |
281
|
|
|
global $user_info; |
282
|
|
|
|
283
|
|
|
$this->_db->query('', ' |
284
|
|
|
UPDATE {db_prefix}log_mentions |
285
|
|
|
SET status = {int:status} |
286
|
|
|
WHERE id_mention IN ({array_int:id_mentions})', |
287
|
|
|
array( |
288
|
|
|
'id_mentions' => (array) $id_mentions, |
289
|
|
|
'status' => $this->_known_status[$status], |
290
|
|
|
) |
291
|
|
|
); |
292
|
|
|
$success = $this->_db->affected_rows() != 0; |
293
|
|
|
|
294
|
|
|
// Update the top level mentions count |
295
|
|
|
if ($success) |
296
|
|
|
$this->_updateMenuCount($this->_known_status[$status], $user_info['id']); |
297
|
|
|
|
298
|
|
|
return $success; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* Updates the mention count as a result of an action, read, new, delete, etc |
303
|
|
|
* |
304
|
|
|
* @package Mentions |
305
|
|
|
* @param int $status |
306
|
|
|
* @param int $member_id |
307
|
|
|
*/ |
308
|
|
|
protected function _updateMenuCount($status, $member_id) |
309
|
|
|
{ |
310
|
|
|
require_once(SUBSDIR . '/Members.subs.php'); |
311
|
|
|
|
312
|
|
|
// If its new add to our menu count |
313
|
|
|
if ($status === 0) |
314
|
|
|
updateMemberdata($member_id, array('mentions' => '+')); |
315
|
|
|
// Mark as read we decrease the count |
316
|
|
|
elseif ($status === 1) |
317
|
|
|
updateMemberdata($member_id, array('mentions' => '-')); |
318
|
|
|
// Deleting or unapproving may have been read or not, so a count is required |
319
|
|
|
else |
320
|
|
|
countUserMentions(false, '', $member_id); |
321
|
|
|
} |
322
|
|
|
} |
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.
The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.
This check looks for comments that seem to be mostly valid code and reports them.