Passed
Push — master ( 00519f...366a1b )
by Andreas
17:30
created

net_nehmer_comments_comment::confirm_abuse()   A

Complexity

Conditions 5
Paths 4

Size

Total Lines 18
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 10
nc 4
nop 0
dl 0
loc 18
ccs 0
cts 11
cp 0
crap 30
rs 9.6111
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package net.nehmer.comments
4
 * @author The Midgard Project, http://www.midgard-project.org
5
 * @copyright The Midgard Project, http://www.midgard-project.org
6
 * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
7
 */
8
9
/**
10
 * Comments main comment class
11
 *
12
 * Comments link up to the object they refer to.
13
 *
14
 * @property string $author
15
 * @property string $objectguid
16
 * @property string $title
17
 * @property longstring $content
18
 * @property integer $rating
19
 * @property string $remoteid Remote ID for comments fetched from external source (rss …)
20
 * @property string $ip
21
 * @property integer $status
22
 * @package net.nehmer.comments
23
 */
24
class net_nehmer_comments_comment extends midcom_core_dbaobject
25
{
26
    public $__midcom_class_name__ = __CLASS__;
27
    public $__mgdschema_class_name__ = 'net_nehmer_comments_comment_db';
28
29
    // New messages enter at 4, and can be lowered or raised
30
    const JUNK = 1;
31
    const ABUSE = 2;
32
    const REPORTED_ABUSE = 3;
33
    const NEW_ANONYMOUS = 4;
34
    const NEW_USER = 5;
35
    const MODERATED = 6;
36
37
    var $_send_notification = false;
38
39
    /**
40
     * DBA magic defaults which assign write privileges for all USERS, so that they can
41
     * add new comments at will.
42
     */
43
    public function get_class_magic_default_privileges()
44
    {
45
        return [
46
            'EVERYONE' => [],
47
            'ANONYMOUS' => [],
48
            'USERS' => [
49
                'midgard:create' => MIDCOM_PRIVILEGE_ALLOW
50
            ],
51
        ];
52
    }
53
54
    /**
55
     * Link to the parent object specified in the objectguid field.
56
     */
57 2
    public function get_parent_guid_uncached() : string
58
    {
59 2
        return $this->objectguid;
60
    }
61
62
    /**
63
     * Returns a list of comments applicable to a given object, ordered by creation
64
     * date.
65
     *
66
     * @param string $guid The GUID of the object to bind to.
67
     * @return net_nehmer_comments_comment[] List of applicable comments.
68
     */
69 185
    public static function list_by_objectguid($guid, $limit = false, $order = 'ASC', $paging = false)
70
    {
71 185
        $qb = self::_prepare_query($guid, $paging, $limit);
72 185
        $qb->add_order('metadata.published', $order);
73
74 185
        if ($paging !== false) {
75
            return $qb;
76
        }
77
78 185
        return $qb->execute();
79
    }
80
81
    /**
82
     * Returns a list of comments applicable to a given object
83
     * not displaying empty comments or anonymous posts,
84
     * ordered by creation date.
85
     *
86
     * @param string $guid The GUID of the object to bind to.
87
     * @return net_nehmer_comments_comment[] List of applicable comments.
88
     */
89 1
    public static function list_by_objectguid_filter_anonymous($guid, $limit = false, $order = 'ASC', $paging = false)
90
    {
91 1
        $qb = self::_prepare_query($guid, $paging, $limit);
92 1
        $qb->add_order('metadata.published', $order);
93 1
        $qb->add_constraint('author', '<>', '');
94 1
        $qb->add_constraint('content', '<>', '');
95
96 1
        if ($paging !== false) {
97
            return $qb;
98
        }
99
100 1
        return $qb->execute();
101
    }
102
103
    /**
104
     * Returns the number of comments associated with a given object. This is intended for
105
     * outside usage to render stuff like "15 comments". The count is executed unchecked.
106
     */
107 5
    public static function count_by_objectguid($guid) : int
108
    {
109 5
        $qb = self::_prepare_query($guid);
110 5
        return $qb->count_unchecked();
111
    }
112
113
    /**
114
     * Returns the number of comments associated with a given object by actual registered users.
115
     * This is intended for outside usage to render stuff like "15 comments". The count is
116
     * executed unchecked.
117
     */
118
    public static function count_by_objectguid_filter_anonymous($guid) : int
119
    {
120
        $qb = self::_prepare_query($guid);
121
        $qb->add_constraint('author', '<>', '');
122
        $qb->add_constraint('content', '<>', '');
123
        return $qb->count_unchecked();
124
    }
125
126 191
    private static function _prepare_query(string $guid, bool $paging = false, $limit = false)
127
    {
128 191
        if ($paging !== false) {
129
            $qb = new org_openpsa_qbpager(self::class, 'net_nehmer_comments_comment');
130
            $qb->results_per_page = $paging;
131
        } else {
132 191
            $qb = self::new_query_builder();
133 191
            if ($limit) {
134 2
                $qb->set_limit($limit);
135
            }
136
        }
137
138 191
        $qb->add_constraint('status', 'IN', self::get_default_status());
139 191
        $qb->add_constraint('objectguid', '=', $guid);
140
141 191
        return $qb;
142
    }
143
144
    public function get_logs() : array
145
    {
146
        $log_entries = [];
147
        $logs = $this->list_parameters('net.nehmer.comments:moderation_log');
148
        foreach ($logs as $action => $details) {
149
            // TODO: Show everything only to moderators
150
            $log_action  = explode(':', $action);
151
            $log_details = explode(':', $details);
152
153
            if (count($log_action) == 2) {
154
                switch ($log_details[0]) {
155
                    case 'anonymous':
156
                        $reporter = 'anonymous';
157
                        break;
158
                    case 'linksleeve':
159
                        $reporter = 'linksleeve';
160
                        break;
161
                    default:
162
                        $user = midcom::get()->auth->get_user($log_details[0]);
163
                        $reporter = $user->name;
164
                        break;
165
                }
166
167
                $log_entries[$log_action[1]] = [
168
                    'action'   => $log_action[0],
169
                    'reporter' => $reporter,
170
                    'ip'       => $log_details[1],
171
                    'browser'  => $log_details[2],
172
                ];
173
            }
174
        }
175
        return $log_entries;
176
    }
177
178 1
    public function moderate(int $status, string $action, $reporter = null) : bool
179
    {
180 1
        $this->status = $status;
181 1
        if (!$this->update()) {
182
            return false;
183
        }
184
        // Log who reported it
185 1
        if ($reporter === null) {
186 1
            $reporter = midcom::get()->auth->user->guid ?? 'anonymous';
187
        }
188 1
        $browser = str_replace(':', '_', $_SERVER['HTTP_USER_AGENT']);
189 1
        $address = str_replace(':', '_', $_SERVER['REMOTE_ADDR']);
190
191 1
        $log_action = [$action, gmdate('Ymd\This')];
192 1
        $log_details = [$reporter, $address, $browser];
193
194 1
        $this->set_parameter('net.nehmer.comments:moderation_log', implode(':', $log_action), implode(':', $log_details));
195 1
        return true;
196
    }
197
198 191
    public static function get_default_status() : array
199
    {
200
        $view_status = [
201 191
            self::NEW_ANONYMOUS,
202
            self::NEW_USER,
203
            self::MODERATED,
204
        ];
205
206 191
        $config = midcom_baseclasses_components_configuration::get('net.nehmer.comments', 'config');
207 191
        if ($config->get('show_reported_abuse_as_normal')) {
208 191
            $view_status[] = self::REPORTED_ABUSE;
209
        }
210
211 191
        return $view_status;
212
    }
213
214
    /**
215
     * Update possible ratings cache as requested in configuration
216
     */
217 2
    private function _cache_ratings()
218
    {
219 2
        $config = midcom_baseclasses_components_configuration::get('net.nehmer.comments', 'config');
220
221 2
        if (   $config->get('ratings_enable')
222
            && (    $config->get('ratings_cache_to_object')
223 2
                 || $config->get('comment_count_cache_to_object'))) {
224
            // Handle ratings
225
            $comments = self::list_by_objectguid($this->objectguid);
226
            $ratings_total = 0;
227
            $rating_comments = 0;
228
            $value = 0;
229
            foreach ($comments as $comment) {
230
                if (!empty($comment->rating)) {
231
                    $rating_comments++;
232
                    $ratings_total += $comment->rating;
233
                }
234
            }
235
236
            // Get parent object
237
            $parent_property = $config->get('ratings_cache_to_object_property');
238
            midcom::get()->auth->request_sudo('net.nehmer.comments');
239
            $parent_object = midcom::get()->dbfactory->get_object_by_guid($this->objectguid);
240
241
            if ($config->get('ratings_cache_total')) {
242
                $value = $ratings_total;
243
            } elseif ($rating_comments != 0) {
244
                $value = $ratings_total / $rating_comments;
245
            }
246
247
            if ($config->get('ratings_cache_to_object_property_metadata')) {
248
                $parent_object->metadata->set($parent_property, round($value));
249
            } else {
250
                $orig_rcs = $parent_object->_use_rcs;
251
                $parent_object->_use_rcs = (boolean) $config->get('ratings_cache_to_object_use_rcs');
252
                // TODO: Figure out whether to round
253
                $parent_object->$parent_property = $value;
254
                $parent_object->update();
255
                $parent_object->_use_rcs = $orig_rcs;
256
            }
257
258
            $parent_property = $config->get('comment_count_cache_to_object_property');
259
            $orig_rcs = $parent_object->_use_rcs;
260
            $parent_object->_use_rcs = (boolean) $config->get('comment_count_cache_to_object_use_rcs');
261
            $parent_object->$parent_property = count($comments);
262
            $parent_object->update();
263
            $parent_object->_use_rcs = $orig_rcs;
264
265
            midcom::get()->auth->drop_sudo();
266
        }
267 2
    }
268
269
    private function _send_notifications()
270
    {
271
        if (   empty($this->title)
272
            && empty($this->content)) {
273
            // No need to send notifications about empty rating entries
274
            return;
275
        }
276
        //Get the parent object
277
        try {
278
            $parent = midcom::get()->dbfactory->get_object_by_guid($this->objectguid);
279
        } catch (midcom_error $e) {
280
            $e->log();
281
            return;
282
        }
283
284
        // Construct the message
285
        $message = $this->_construct_message();
286
287
        $authors = explode('|', substr($parent->metadata->authors, 1, -1));
288
        if (empty($authors)) {
289
            // Fall back to original creator if authors are not set for some reason
290
            $authors = [$parent->metadata->creator];
291
        }
292
293
        //Go through all the authors
294
        foreach ($authors as $author) {
295
            // Send the notification to each author of the original document
296
            org_openpsa_notifications::notify('net.nehmer.comments:comment_posted', $author, $message);
297
        }
298
299
        $subscriptions = $parent->list_parameters('net.nehmer.comments:subscription');
300
        //Go through each subscription
301
        foreach (array_keys($subscriptions) as $user_guid) {
302
            // Send notice
303
            org_openpsa_notifications::notify('net.nehmer.comments:subscription', $user_guid, $message);
304
        }
305
    }
306
307
    /**
308
     * Construct the message
309
     */
310
    private function _construct_message() : array
311
    {
312
        // Construct the message
313
        $message = [];
314
315
        // Resolve parent title
316
        $parent_object = midcom::get()->dbfactory->get_object_by_guid($this->objectguid);
317
        $ref = midcom_helper_reflector::get($parent_object);
318
        $parent_title = $ref->get_object_label($parent_object);
319
320
        // Resolve commenting user
321
        $auth = midcom::get()->auth;
322
        if ($auth->user) {
323
            $user_string = "{$auth->user->name} ({$auth->user->username})";
324
        } else {
325
            $user_string = "{$this->author} (" . midcom::get()->i18n->get_string('anonymous', 'midcom') . ")";
326
        }
327
328
        $message['title'] = sprintf(midcom::get()->i18n->get_string('page %s has been commented by %s', 'net.nehmer.comments'), $parent_title, $user_string);
329
330
        $message['content']  = "{$this->title}\n";
331
        $message['content'] .= "{$this->content}\n\n";
332
        $message['content'] .= midcom::get()->i18n->get_string('link to page', 'net.nemein.wiki') . ":\n";
333
        $message['content'] .= midcom::get()->permalinks->create_permalink($this->objectguid);
334
335
        $message['abstract'] = $message['title'];
336
337
        return $message;
338
    }
339
340 2
    public function _on_updated()
341
    {
342 2
        $this->_cache_ratings();
343
344 2
        if ($this->_send_notification) {
345
            //Notify authors and subscribers about the new comment
346
            $this->_send_notifications();
347
        }
348 2
    }
349
}
350