Completed
Push — master ( fe9df2...561103 )
by Andreas
17:49
created

org_openpsa_contacts_interface::find_root_group()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 4.0119

Importance

Changes 0
Metric Value
cc 4
eloc 22
nc 4
nop 1
dl 0
loc 35
ccs 20
cts 22
cp 0.9091
crap 4.0119
rs 9.568
c 0
b 0
f 0
1
<?php
2
/**
3
 * @package org.openpsa.contacts
4
 * @author Nemein Oy http://www.nemein.com/
5
 * @copyright Nemein Oy http://www.nemein.com/
6
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
7
 */
8
9
use midcom\datamanager\datamanager;
10
11
/**
12
 * OpenPSA Contact registers/user manager
13
 *
14
 * @package org.openpsa.contacts
15
 */
16
class org_openpsa_contacts_interface extends midcom_baseclasses_components_interface
17
implements midcom_services_permalinks_resolver
18
{
19
    /**
20
     * Prepares the component's indexer client
21
     */
22
    public function _on_reindex($topic, $config, &$indexer)
23
    {
24
        $qb_organisations = org_openpsa_contacts_group_dba::new_query_builder();
25
        $qb_organisations->add_constraint('orgOpenpsaObtype', '<>', org_openpsa_contacts_group_dba::MYCONTACTS);
26
        $organisation_dm = datamanager::from_schemadb($config->get('schemadb_group'));
27
28
        $qb_persons = org_openpsa_contacts_person_dba::new_query_builder();
29
        $person_dm = datamanager::from_schemadb($config->get('schemadb_person'));
30
31
        $indexer = new org_openpsa_contacts_midcom_indexer($topic, $indexer);
32
        $indexer->add_query('organisations', $qb_organisations, $organisation_dm);
33
        $indexer->add_query('persons', $qb_persons, $person_dm);
34
35
        return $indexer;
36
    }
37
38
    /**
39
     * Locates the root group
40
     */
41 18
    public static function find_root_group($name = '__org_openpsa_contacts') : midcom_db_group
42
    {
43 18
        static $root_groups = [];
44
45
        //Check if we have already initialized
46 18
        if (!empty($root_groups[$name])) {
47 16
            return $root_groups[$name];
48
        }
49
50 2
        $qb = midcom_db_group::new_query_builder();
51 2
        $qb->add_constraint('owner', '=', 0);
52 2
        $qb->add_constraint('name', '=', $name);
53
54 2
        $results = $qb->execute();
55
56 2
        if (!empty($results)) {
57
            $root_groups[$name] = end($results);
58
        } else {
59 2
            debug_add("OpenPSA Contacts root group could not be found", MIDCOM_LOG_WARN);
60
61
            //Attempt to  auto-initialize the group.
62 2
            midcom::get()->auth->request_sudo('org.openpsa.contacts');
63 2
            $grp = new midcom_db_group();
64 2
            $grp->owner = 0;
65 2
            $grp->name = $name;
66 2
            $grp->official = midcom::get()->i18n->get_l10n('org.openpsa.contacts')->get($name);
67 2
            $ret = $grp->create();
68 2
            midcom::get()->auth->drop_sudo();
69 2
            if (!$ret) {
70
                throw new midcom_error("Could not auto-initialize the module, group creation failed: " . midcom_connection::get_error_string());
71
            }
72 2
            $root_groups[$name] = $grp;
73
        }
74
75 2
        return $root_groups[$name];
76
    }
77
78
    public function resolve_object_link(midcom_db_topic $topic, midcom_core_dbaobject $object)
79
    {
80
        if (   $object instanceof org_openpsa_contacts_group_dba
81
            || $object instanceof midcom_db_group) {
82
            return "group/{$object->guid}/";
83
        }
84
        if (   $object instanceof org_openpsa_contacts_person_dba
85
            || $object instanceof midcom_db_person) {
86
            return "person/{$object->guid}/";
87
        }
88
        return null;
89
    }
90
91
    private function _get_data_from_url(string $url) : array
92
    {
93
        $data = [];
94
95
        // TODO: Error handling
96
        $client = new org_openpsa_httplib();
97
        $html = $client->get($url);
98
99
        // Check for ICBM coordinate information
100
        if ($icbm = org_openpsa_httplib_helpers::get_meta_value($html, 'icbm')) {
101
            $data['icbm'] = $icbm;
102
        }
103
104
        // Check for RSS feed
105
        $rss_url = org_openpsa_httplib_helpers::get_link_values($html, 'alternate');
106
107
        if (!empty($rss_url)) {
108
            $data['rss_url'] = $rss_url[0]['href'];
109
110
            // We have a feed URL, but we should check if it is GeoRSS as well
111
            $items = net_nemein_rss_fetch::raw_fetch($data['rss_url'])->get_items();
112
113
            if (   !empty($items)
114
                && (   $items[0]->get_latitude()
115
                    || $items[0]->get_longitude())) {
116
                // This is a GeoRSS feed
117
                $data['georss_url'] = $data['rss_url'];
118
            }
119
        }
120
121
        $microformats = Mf2\parse($html);
122
        $hcards = [];
123
        foreach ($microformats['items'] as $item) {
124
            if (in_array('h-card', $item['type'])) {
125
                $hcards[] = $item['properties'];
126
            }
127
        }
128
129
        if (!empty($hcards)) {
130
            // We have found hCard data here
131
            $data['hcards'] = $hcards;
132
        }
133
134
        return $data;
135
    }
136
137
    /**
138
     * AT handler for fetching Semantic Web data for person or group
139
     *
140
     * @param array $args handler arguments
141
     * @param midcom_baseclasses_components_cron_handler $handler The cron_handler object calling this method.
142
     * @return boolean indicating success/failure
143
     */
144
    public function check_url(array $args, midcom_baseclasses_components_cron_handler $handler) : bool
145
    {
146
        if (array_key_exists('person', $args)) {
147
            $type = 'person';
148
        } elseif (array_key_exists('group', $args)) {
149
            $type = 'group';
150
        } else {
151
            $handler->print_error('Person or Group GUID not set, aborting');
152
            return false;
153
        }
154
155
        $classname = 'org_openpsa_contacts_' . $type . '_dba';
156
        $method = '_check_' . $type . '_url';
157
        $guid = $args[$type];
158
159
        try {
160
            $object = new $classname($guid);
161
        } catch (midcom_error $e) {
162
            $handler->print_error($type . " {$guid} not found, error " . $e->getMessage());
163
            return false;
164
        }
165
        if (!$object->homepage) {
166
            $handler->print_error($type . " {$object->guid} has no homepage, skipping");
167
            return false;
168
        }
169
        return $this->$method($object);
170
    }
171
172
    private function _check_group_url(org_openpsa_contacts_group_dba $group) : bool
173
    {
174
        $data = $this->_get_data_from_url($group->homepage);
175
176
        // TODO: We can use a lot of other data too
177
        if (array_key_exists('hcards', $data)) {
178
            // Process those hCard values that are interesting for us
179
            foreach ($data['hcards'] as $hcard) {
180
                $this->_update_from_hcard($group, $hcard);
181
            }
182
183
            $group->update();
184
        }
185
        return true;
186
    }
187
188
    private function _check_person_url(org_openpsa_contacts_person_dba $person) : bool
189
    {
190
        $data = $this->_get_data_from_url($person->homepage);
191
192
        if (array_key_exists('rss_url', $data)) {
193
            // Instead of using the ICBM position data directly we can subscribe to it so we get modifications too
194
            $person->set_parameter('net.nemein.rss', 'url', $data['rss_url']);
195
        }
196
197
        if (array_key_exists('hcards', $data)) {
198
            // Process those hCard values that are interesting for us
199
            foreach ($data['hcards'] as $hcard) {
200
                $this->_update_from_hcard($person, $hcard);
201
            }
202
203
            $person->update();
204
        }
205
        return true;
206
    }
207
208
    private function _update_from_hcard($object, $hcard)
209
    {
210
        foreach ($hcard as $key => $val) {
211
            switch ($key) {
212
                case 'email':
213
                    $object->email = reset($val);
214
                    break;
215
216
                case 'tel':
217
                    $object->workphone = reset($val);
218
                    break;
219
220
                case 'note':
221
                    $object->extra = reset($val);
222
                    break;
223
224
                case 'photo':
225
                    // TODO: Importing the photo would be cool
226
                    break;
227
228
                case 'adr':
229
                    $adr = reset($val);
230
                    if (array_key_exists('street-address', $adr['properties'])) {
231
                        $object->street = reset($adr['properties']['street-address']);
232
                    }
233
                    if (array_key_exists('postal-code', $adr['properties'])) {
234
                        $object->postcode = reset($adr['properties']['postal-code']);
235
                    }
236
                    if (array_key_exists('locality', $adr['properties'])) {
237
                        $object->city = reset($adr['properties']['locality']);
238
                    }
239
                    if (array_key_exists('country-name', $adr['properties'])) {
240
                        $object->country = reset($adr['properties']['country-name']);
241
                    }
242
                    break;
243
            }
244
        }
245
    }
246
}
247