Passed
Push — master ( 409c3f...e5371a )
by Andreas
09:22
created

net_nehmer_comments_comment::moderate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 2.003

Importance

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