Passed
Push — master ( be6fbd...8a140a )
by Andreas
24:16
created

net_nehmer_comments_comment   A

Complexity

Total Complexity 39

Size/Duplication

Total Lines 300
Duplicated Lines 0 %

Test Coverage

Coverage 31.47%

Importance

Changes 0
Metric Value
eloc 151
dl 0
loc 300
ccs 45
cts 143
cp 0.3147
rs 9.28
c 0
b 0
f 0
wmc 39

12 Methods

Rating   Name   Duplication   Size   Complexity  
A get_class_magic_default_privileges() 0 7 1
A list_by_objectguid_filter_anonymous() 0 12 2
A list_by_objectguid() 0 10 2
A count_by_objectguid() 0 4 1
A get_logs() 0 32 5
B _cache_ratings() 0 49 9
A get_default_status() 0 14 2
A moderate() 0 18 3
A _construct_message() 0 28 2
A _prepare_query() 0 16 3
A _on_updated() 0 7 2
B _send_notifications() 0 35 7
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 $__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
     * 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 197
    public static function list_by_objectguid(string $guid, $limit = false, string $order = 'ASC', $paging = false)
61
    {
62 197
        $qb = self::_prepare_query($guid, $paging, $limit);
63 197
        $qb->add_order('metadata.published', $order);
64
65 197
        if ($paging !== false) {
66
            return $qb;
67
        }
68
69 197
        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 198
    private static function _prepare_query(string $guid, $paging = false, $limit = false) : midcom_core_querybuilder
104
    {
105 198
        if ($paging !== false) {
106
            $qb = new org_openpsa_qbpager(self::class, 'net_nehmer_comments_comment');
107
            $qb->results_per_page = $paging;
108
        } else {
109 198
            $qb = self::new_query_builder();
110 198
            if ($limit) {
111 2
                $qb->set_limit($limit);
112
            }
113
        }
114
115 198
        $qb->add_constraint('status', 'IN', self::get_default_status());
116 198
        $qb->add_constraint('objectguid', '=', $guid);
117
118 198
        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
        if ($reporter === null) {
163 1
            $reporter = midcom::get()->auth->user->guid ?? 'anonymous';
164
        }
165 1
        $browser = str_replace(':', '_', $_SERVER['HTTP_USER_AGENT']);
166 1
        $address = str_replace(':', '_', $_SERVER['REMOTE_ADDR']);
167
168 1
        $log_action = [$action, gmdate('Ymd\This')];
169 1
        $log_details = [$reporter, $address, $browser];
170
171 1
        $this->set_parameter('net.nehmer.comments:moderation_log', implode(':', $log_action), implode(':', $log_details));
172 1
        return true;
173
    }
174
175 198
    public static function get_default_status() : array
176
    {
177
        $view_status = [
178 198
            self::NEW_ANONYMOUS,
179
            self::NEW_USER,
180
            self::MODERATED,
181
        ];
182
183 198
        $config = midcom_baseclasses_components_configuration::get('net.nehmer.comments', 'config');
184 198
        if ($config->get('show_reported_abuse_as_normal')) {
185 198
            $view_status[] = self::REPORTED_ABUSE;
186
        }
187
188 198
        return $view_status;
189
    }
190
191
    /**
192
     * Update possible ratings cache as requested in configuration
193
     */
194 2
    private function _cache_ratings()
195
    {
196 2
        $config = midcom_baseclasses_components_configuration::get('net.nehmer.comments', 'config');
197
198 2
        if (   $config->get('ratings_enable')
199
            && (    $config->get('ratings_cache_to_object')
200 2
                 || $config->get('comment_count_cache_to_object'))) {
201
            // Handle ratings
202
            $comments = self::list_by_objectguid($this->objectguid);
203
            $ratings_total = 0;
204
            $rating_comments = 0;
205
            $value = 0;
206
            foreach ($comments as $comment) {
207
                if (!empty($comment->rating)) {
208
                    $rating_comments++;
209
                    $ratings_total += $comment->rating;
210
                }
211
            }
212
213
            // Get parent object
214
            $parent_property = $config->get('ratings_cache_to_object_property');
215
            midcom::get()->auth->request_sudo('net.nehmer.comments');
216
            $parent_object = midcom::get()->dbfactory->get_object_by_guid($this->objectguid);
217
218
            if ($config->get('ratings_cache_total')) {
219
                $value = $ratings_total;
220
            } elseif ($rating_comments != 0) {
221
                $value = $ratings_total / $rating_comments;
222
            }
223
224
            if ($config->get('ratings_cache_to_object_property_metadata')) {
225
                $parent_object->metadata->set($parent_property, round($value));
226
            } else {
227
                $orig_rcs = $parent_object->_use_rcs;
228
                $parent_object->_use_rcs = (boolean) $config->get('ratings_cache_to_object_use_rcs');
229
                // TODO: Figure out whether to round
230
                $parent_object->$parent_property = $value;
231
                $parent_object->update();
232
                $parent_object->_use_rcs = $orig_rcs;
233
            }
234
235
            $parent_property = $config->get('comment_count_cache_to_object_property');
236
            $orig_rcs = $parent_object->_use_rcs;
237
            $parent_object->_use_rcs = (boolean) $config->get('comment_count_cache_to_object_use_rcs');
238
            $parent_object->$parent_property = count($comments);
239
            $parent_object->update();
240
            $parent_object->_use_rcs = $orig_rcs;
241
242
            midcom::get()->auth->drop_sudo();
243
        }
244 2
    }
245
246
    private function _send_notifications()
247
    {
248
        if (   empty($this->title)
249
            && empty($this->content)) {
250
            // No need to send notifications about empty rating entries
251
            return;
252
        }
253
        //Get the parent object
254
        try {
255
            $parent = midcom::get()->dbfactory->get_object_by_guid($this->objectguid);
256
        } catch (midcom_error $e) {
257
            $e->log();
258
            return;
259
        }
260
261
        // Construct the message
262
        $message = $this->_construct_message();
263
264
        $authors = explode('|', substr($parent->metadata->authors, 1, -1));
265
        if (empty($authors)) {
266
            // Fall back to original creator if authors are not set for some reason
267
            $authors = [$parent->metadata->creator];
268
        }
269
270
        //Go through all the authors
271
        foreach ($authors as $author) {
272
            // Send the notification to each author of the original document
273
            org_openpsa_notifications::notify('net.nehmer.comments:comment_posted', $author, $message);
274
        }
275
276
        $subscriptions = $parent->list_parameters('net.nehmer.comments:subscription');
277
        //Go through each subscription
278
        foreach (array_keys($subscriptions) as $user_guid) {
279
            // Send notice
280
            org_openpsa_notifications::notify('net.nehmer.comments:subscription', $user_guid, $message);
281
        }
282
    }
283
284
    /**
285
     * Construct the message
286
     */
287
    private function _construct_message() : array
288
    {
289
        // Construct the message
290
        $message = [];
291
292
        // Resolve parent title
293
        $parent_object = midcom::get()->dbfactory->get_object_by_guid($this->objectguid);
294
        $ref = midcom_helper_reflector::get($parent_object);
295
        $parent_title = $ref->get_object_label($parent_object);
296
297
        // Resolve commenting user
298
        $auth = midcom::get()->auth;
299
        if ($auth->user) {
300
            $user_string = "{$auth->user->name} ({$auth->user->username})";
301
        } else {
302
            $user_string = "{$this->author} (" . midcom::get()->i18n->get_string('anonymous', 'midcom') . ")";
303
        }
304
305
        $message['title'] = sprintf(midcom::get()->i18n->get_string('page %s has been commented by %s', 'net.nehmer.comments'), $parent_title, $user_string);
306
307
        $message['content']  = "{$this->title}\n";
308
        $message['content'] .= "{$this->content}\n\n";
309
        $message['content'] .= midcom::get()->i18n->get_string('link to page', 'net.nemein.wiki') . ":\n";
310
        $message['content'] .= midcom::get()->permalinks->create_permalink($this->objectguid);
311
312
        $message['abstract'] = $message['title'];
313
314
        return $message;
315
    }
316
317 2
    public function _on_updated()
318
    {
319 2
        $this->_cache_ratings();
320
321 2
        if ($this->_send_notification) {
322
            //Notify authors and subscribers about the new comment
323
            $this->_send_notifications();
324
        }
325 2
    }
326
}
327