Passed
Push — master ( 1d6e3e...f1fbfb )
by Andreas
11:14
created

net_nemein_wiki_wikipage   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 173
Duplicated Lines 0 %

Test Coverage

Coverage 54.55%

Importance

Changes 0
Metric Value
eloc 84
c 0
b 0
f 0
dl 0
loc 173
ccs 48
cts 88
cp 0.5455
rs 10
wmc 24

8 Methods

Rating   Name   Duplication   Size   Complexity  
A _on_updating() 0 11 3
A _on_creating() 0 22 5
A _on_loaded() 0 6 2
A _on_updated() 0 5 1
A list_watchers() 0 13 1
A update_link_cache() 0 26 4
A get_diff() 0 21 3
A update_watchers() 0 40 5
1
<?php
2
/**
3
 * @package net.nemein.wiki
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
 * Wiki note helper class to be used by other components
11
 *
12
 * @package net.nemein.wiki
13
 */
14
class net_nemein_wiki_wikipage extends midcom_db_article
15
{
16
    public array $autodelete_dependents = [
17
        net_nemein_wiki_link_dba::class => 'frompage'
18
    ];
19
20 10
    public function _on_loaded()
21
    {
22
        // Backwards compatibility
23 10
        if ($this->name == '') {
24
            $this->name = midcom_helper_misc::urlize($this->title);
25
            $this->update();
26
        }
27
    }
28
29 3
    public function _on_creating() : bool
30
    {
31 3
        if (   $this->title == ''
32 3
            || !$this->topic) {
33
            // We must have wikiword and topic at this stage
34
            return false;
35
        }
36
37
        // Check for duplicates
38 3
        $qb = self::new_query_builder();
39 3
        $qb->add_constraint('topic', '=', $this->topic);
40 3
        $qb->add_constraint('title', '=', $this->title);
41 3
        if ($qb->count() > 0) {
42
            midcom_connection::set_error(MGD_ERR_OBJECT_NAME_EXISTS);
43
            return false;
44
        }
45
46
        // Generate URL-clean name
47 3
        if ($this->name != 'index') {
48 1
            $this->name = midcom_helper_misc::urlize($this->title);
49
        }
50 3
        return true;
51
    }
52
53 4
    public function _on_updating() : bool
54
    {
55 4
        if ($guid = midcom::get()->auth->user?->guid) {
56
            // Place current user in the page authors list
57
            $authors = explode('|', substr($this->metadata->authors, 1, -1));
58
            if (!in_array($guid, $authors)) {
59
                $authors[] = $guid;
60
                $this->metadata->authors = '|' . implode('|', $authors) . '|';
61
            }
62
        }
63 4
        return parent::_on_updating();
64
    }
65
66 4
    public function _on_updated()
67
    {
68 4
        parent::_on_updated();
69 4
        $this->update_watchers();
70 4
        $this->update_link_cache();
71
    }
72
73
    /**
74
     * Caches links in the wiki page into database for faster "what links here" queries
75
     */
76 4
    private function update_link_cache()
77
    {
78 4
        $parser = new net_nemein_wiki_parser($this);
79 4
        $links_in_content = $parser->find_links_in_content();
80
81 4
        $qb = net_nemein_wiki_link_dba::new_query_builder();
82 4
        $qb->add_constraint('frompage', '=', $this->id);
83
84
        // Check links in DB versus links in content to see what needs to be removed
85 4
        foreach ($qb->execute() as $link) {
86 2
            if (!array_key_exists($link->topage, $links_in_content)) {
87
                // This link is not any more in content, remove
88 1
                $link->delete();
89 1
                continue;
90
            }
91
            //no change for this link
92 1
            unset($links_in_content[$link->topage]);
93
        }
94
95
        // What is still left needs to be added
96 4
        foreach (array_keys($links_in_content) as $wikilink) {
97 1
            $link = new net_nemein_wiki_link_dba();
98 1
            $link->frompage = $this->id;
99 1
            $link->topage = $wikilink;
100 1
            debug_add("Creating net_nemein_wiki_link_dba: from page #{$link->frompage}, to page: '$link->topage'");
101 1
            $link->create();
102
        }
103
    }
104
105
    /**
106
     * Get list of people watching this page
107
     */
108 4
    private function list_watchers() : array
109
    {
110 4
        $topic = new midcom_db_topic($this->topic);
111 4
        $qb = new midgard_query_builder('midgard_parameter');
112 4
        $qb->add_constraint('domain', '=', 'net.nemein.wiki:watch');
113 4
        $qb->begin_group('OR');
114
            // List people watching the whole wiki
115 4
            $qb->add_constraint('parentguid', '=', $topic->guid);
116
            // List people watching this particular page
117 4
            $qb->add_constraint('parentguid', '=', $this->guid);
118 4
        $qb->end_group();
119
120 4
        return array_unique(array_column($qb->execute(), 'name'));
121
    }
122
123 4
    private function update_watchers()
124
    {
125 4
        $watchers = $this->list_watchers();
126 4
        if (empty($watchers)) {
127 4
            return;
128
        }
129
130
        $diff = $this->get_diff();
131
        if (empty($diff)) {
132
            // No sense to email empty diffs
133
            return;
134
        }
135
136
        // Construct the message
137
        $message = [];
138
        $user_string = midcom::get()->i18n->get_string('anonymous', 'net.nemein.wiki');
139
        if ($user = midcom::get()->auth->user?->get_storage()) {
140
            $user_string = $user->name;
141
        }
142
        // Title for long notifications
143
        $message['title'] = sprintf(midcom::get()->i18n->get_string('page %s has been updated by %s', 'net.nemein.wiki'), $this->title, $user_string);
144
        // Content for long notifications
145
        $message['content']  = "{$message['title']}\n\n";
146
147
        $message['content'] .= midcom::get()->i18n->get_string('page modifications', 'net.nemein.wiki') . ":\n";
148
        $message['content'] .= "\n{$diff}\n\n";
149
150
        $message['content'] .= midcom::get()->i18n->get_string('link to page', 'net.nemein.wiki') . ":\n";
151
        $message['content'] .= midcom::get()->permalinks->create_permalink($this->guid);
152
153
        // Content for short notifications
154
        $topic = new midcom_db_topic($this->topic);
155
        $message['abstract'] = sprintf(midcom::get()->i18n->get_string('page %s has been updated by %s in wiki %s', 'net.nemein.wiki'), $this->title, $user_string, $topic->extra);
156
157
        debug_add("Processing list of Wiki subscribers");
158
159
        // Send the message out
160
        foreach ($watchers as $recipient) {
161
            debug_add("Notifying {$recipient}...");
162
            org_openpsa_notifications::notify('net.nemein.wiki:page_updated', $recipient, $message);
163
        }
164
    }
165
166
    private function get_diff() : string
167
    {
168
        // Load the RCS handler
169
        $rcs_handler = midcom::get()->rcs->load_backend($this);
170
171
        // Find out what versions to diff
172
        $history = $rcs_handler->get_history();
173
        if (count($history->all()) < 2) {
174
            return '';
175
        }
176
        $this_version = $history->get_last()['revision'];
177
        $prev_version = $history->get_previous($this_version)['revision'];
178
179
        try {
180
            $diff_fields = $rcs_handler->get_diff($prev_version, $this_version);
181
        } catch (midcom_error $e) {
182
            $e->log();
183
            return '';
184
        }
185
186
        return $diff_fields['content']['diff'] ?? '';
187
    }
188
}
189