Subversion Repositories oidplus

Rev

Rev 228 | Rev 239 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
5
 * Copyright 2019 Daniel Marschall, ViaThinkSoft
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
112 daniel-mar 20
if (!defined('IN_OIDPLUS')) die();
21
 
150 daniel-mar 22
define('OIDPLUS_OBJECT_CACHING', true);
23
 
193 daniel-mar 24
define('UUID_NAMEBASED_NS_OidPlusMisc', 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22');
25
 
227 daniel-mar 26
abstract class OIDplusObject {
2 daniel-mar 27
        public static function parse($node_id) { // please overwrite this function!
28
                // TODO: in case we are not calling this class directly, check if function is overwritten and throw exception otherwise
227 daniel-mar 29
                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
2 daniel-mar 30
                        if ($obj = $ot::parse($node_id)) return $obj;
31
                }
32
                return null;
33
        }
34
 
228 daniel-mar 35
        public function /*OIDplusAltId[]*/ getAltIds() {
193 daniel-mar 36
                if ($this->isRoot()) return array();
37
 
38
                $ids = array();
39
                if ($this->ns() != 'oid') {
40
                        // Creates an OIDplus-Hash-OID
41
                        // If the object type has a better way of defining an OID, please override this method!
227 daniel-mar 42
                        $sid = OIDplus::getSystemId(true);
193 daniel-mar 43
                        if (!empty($sid)) {
44
                                $oid = $sid . '.' . smallhash($this->nodeId());
228 daniel-mar 45
                                $ids[] = new OIDplusAltId('oid', $oid, 'OIDplus Information Object ID');
193 daniel-mar 46
                        }
47
                }
48
                if ($this->ns() != 'guid') {
228 daniel-mar 49
                        $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), 'Namebased version 3 / MD5 UUID with namespace UUID_NAMEBASED_NS_OidPlusMisc');
50
                        $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), 'Namebased version 5 / SHA1 UUID with namespace UUID_NAMEBASED_NS_OidPlusMisc');
193 daniel-mar 51
                }
52
                return $ids;
83 daniel-mar 53
        }
54
 
2 daniel-mar 55
        public abstract static function objectTypeTitle();
56
 
57
        public abstract static function objectTypeTitleShort();
58
 
59
        public abstract static function ns();
60
 
61
        public abstract static function root();
62
 
63
        public abstract function isRoot();
64
 
65
        public abstract function nodeId();
66
 
67
        public abstract function addString($str);
68
 
69
        public abstract function crudShowId(OIDplusObject $parent);
70
 
71
        public abstract function crudInsertPrefix();
72
 
73
        public abstract function jsTreeNodeName(OIDplusObject $parent = null);
74
 
75
        public abstract function defaultTitle();
76
 
16 daniel-mar 77
        public abstract function isLeafNode();
78
 
34 daniel-mar 79
        public abstract function getContentPage(&$title, &$content, &$icon);
2 daniel-mar 80
 
27 daniel-mar 81
        public static function getRaRoots($ra_email=null) {
115 daniel-mar 82
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
83
 
27 daniel-mar 84
                $out = array();
150 daniel-mar 85
 
86
                if (!OIDPLUS_OBJECT_CACHING) {
87
                        if (is_null($ra_email)) {
88
                                $res = OIDplus::db()->query("select oChild.id as id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ".OIDPLUS_TABLENAME_PREFIX."objects as oChild ".
89
                                                            "left join ".OIDPLUS_TABLENAME_PREFIX."objects as oParent on oChild.parent = oParent.id ".
90
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'));
236 daniel-mar 91
                                while ($row = $res->fetch_array()) {
150 daniel-mar 92
                                        if (!OIDplus::authUtils()::isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()::isRaLoggedIn($row['child_mail'])) {
93
                                                $x = self::parse($row['id']); // can be FALSE if namespace was disabled
94
                                                if ($x) $out[] = $x;
95
                                        }
96
                                }
97
                        } else {
98
                                $res = OIDplus::db()->query("select oChild.id as id from ".OIDPLUS_TABLENAME_PREFIX."objects as oChild ".
99
                                                            "left join ".OIDPLUS_TABLENAME_PREFIX."objects as oParent on oChild.parent = oParent.id ".
100
                                                            "where (ifnull(oParent.ra_email,'') <> ? and ifnull(oChild.ra_email,'') = ?) or ".
101
                                                            "      (oParent.ra_email is null and ifnull(oChild.ra_email,'') = ?) ".
102
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'), array($ra_email, $ra_email, $ra_email));
236 daniel-mar 103
                                while ($row = $res->fetch_array()) {
68 daniel-mar 104
                                        $x = self::parse($row['id']); // can be FALSE if namespace was disabled
150 daniel-mar 105
                                        if ($x) $out[] = self::parse($row['id']);
27 daniel-mar 106
                                }
2 daniel-mar 107
                        }
108
                } else {
150 daniel-mar 109
                        if (is_null($ra_email)) {
110
                                $ra_mails_to_check = OIDplusAuthUtils::loggedInRaList();
111
                                if (count($ra_mails_to_check) == 0) return $out;
112
                        } else {
113
                                $ra_mails_to_check = array($ra_email);
2 daniel-mar 114
                        }
150 daniel-mar 115
 
116
                        self::buildObjectInformationCache();
117
 
118
                        foreach ($ra_mails_to_check as $check_ra_mail) {
193 daniel-mar 119
                                $out_part = array();
150 daniel-mar 120
 
193 daniel-mar 121
                                foreach (self::$object_info_cache as $id => list($confidential, $parent, $ra_email, $title)) {
122
                                        // If the OID RA is the RA we are searching, then add the object to the choice list
123
                                        if ($ra_email == $check_ra_mail) $out_part[] = $id;
150 daniel-mar 124
                                }
125
 
193 daniel-mar 126
                                foreach (self::$object_info_cache as $id => list($confidential, $parent, $ra_email, $title)) {
127
                                        if (isset(self::$object_info_cache[$parent])) {
128
                                                if (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] == $ra_email) {
129
                                                        // if the parent has the same RA, then this OID cannot be a root => remove the element from the choice list
130
                                                        foreach (array_keys($out_part, $id) as $key) unset($out_part[$key]);
150 daniel-mar 131
                                                }
132
                                        }
133
                                }
134
 
135
                                natsort($out_part);
136
 
137
                                foreach ($out_part as $id) {
138
                                        $obj = self::parse($id);
139
                                        if ($obj) $out[] = $obj;
140
                                }
141
                        }
2 daniel-mar 142
                }
150 daniel-mar 143
 
2 daniel-mar 144
                return $out;
145
        }
146
 
150 daniel-mar 147
        public static function getAllNonConfidential() {
148
                $out = array();
149
 
150
                if (!OIDPLUS_OBJECT_CACHING) {
169 daniel-mar 151
                        $res = OIDplus::db()->query("select id from ".OIDPLUS_TABLENAME_PREFIX."objects where confidential = 0 order by ".OIDplus::db()->natOrder('id'));
150 daniel-mar 152
 
236 daniel-mar 153
                        while ($row = $res->fetch_array()) {
150 daniel-mar 154
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
169 daniel-mar 155
                                if ($obj && (!$obj->isConfidential())) {
150 daniel-mar 156
                                        $out[] = $row['id'];
157
                                }
2 daniel-mar 158
                        }
159
                } else {
150 daniel-mar 160
                        self::buildObjectInformationCache();
2 daniel-mar 161
 
193 daniel-mar 162
                        foreach (self::$object_info_cache as $id => list($confidential, $parent, $ra_email, $title)) {
150 daniel-mar 163
                                if (!$confidential) {
164
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
169 daniel-mar 165
                                        if ($obj && (!$obj->isConfidential())) {
150 daniel-mar 166
                                                $out[] = $id;
167
                                        }
168
                                }
2 daniel-mar 169
                        }
170
                }
171
 
172
                return $out;
173
        }
174
 
175
        public function isConfidential() {
150 daniel-mar 176
                if (!OIDPLUS_OBJECT_CACHING) {
177
                        $curid = $this->nodeId();
178
                        $orig_curid = $curid;
179
                        if (isset(self::$object_info_cache[$curid])) return self::$object_info_cache[$curid];
180
                        // Recursively search for the confidential flag in the parents
236 daniel-mar 181
                        while (($res = OIDplus::db()->query("select parent, confidential from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($curid)))->num_rows() > 0) {
182
                                $row = $res->fetch_array();
150 daniel-mar 183
                                if ($row['confidential']) {
184
                                        self::$object_info_cache[$curid] = true;
185
                                        self::$object_info_cache[$orig_curid] = true;
186
                                        return true;
187
                                } else {
188
                                        self::$object_info_cache[$curid] = false;
189
                                }
190
                                $curid = $row['parent'];
191
                                if (isset(self::$object_info_cache[$curid])) {
192
                                        self::$object_info_cache[$orig_curid] = self::$object_info_cache[$curid];
193
                                        return self::$object_info_cache[$curid];
194
                                }
195
                        }
196
 
197
                        self::$object_info_cache[$orig_curid] = false;
198
                        return false;
199
                } else {
200
                        self::buildObjectInformationCache();
201
 
202
                        $curid = $this->nodeId();
203
                        // Recursively search for the confidential flag in the parents
169 daniel-mar 204
                        while (isset(self::$object_info_cache[$curid])) {
150 daniel-mar 205
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
206
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
207
                        }
208
                        return false;
2 daniel-mar 209
                }
210
        }
211
 
212
        public function isChildOf(OIDplusObject $obj) {
150 daniel-mar 213
                if (!OIDPLUS_OBJECT_CACHING) {
214
                        $curid = $this->nodeId();
236 daniel-mar 215
                        while (($res = OIDplus::db()->query("select parent from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($curid)))->num_rows() > 0) {
216
                                $row = $res->fetch_array();
150 daniel-mar 217
                                if ($curid == $obj->nodeId()) return true;
218
                                $curid = $row['parent'];
219
                        }
220
                        return false;
221
                } else {
222
                        self::buildObjectInformationCache();
223
 
224
                        $curid = $this->nodeId();
169 daniel-mar 225
                        while (isset(self::$object_info_cache[$curid])) {
150 daniel-mar 226
                                if ($curid == $obj->nodeId()) return true;
227
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
228
                        }
229
                        return false;
2 daniel-mar 230
                }
150 daniel-mar 231
        }
2 daniel-mar 232
 
150 daniel-mar 233
        public function getChildren() {
234
                $out = array();
235
                if (!OIDPLUS_OBJECT_CACHING) {
236
                        $res = OIDplus::db()->query("select id from ".OIDPLUS_TABLENAME_PREFIX."objects where parent = ?", array($this->nodeId()));
236 daniel-mar 237
                        while ($row = $res->fetch_array()) {
150 daniel-mar 238
                                $obj = self::parse($row['id']);
239
                                if (!$obj) continue;
240
                                $out[] = $obj;
241
                        }
242
                } else {
243
                        self::buildObjectInformationCache();
244
 
193 daniel-mar 245
                        foreach (self::$object_info_cache as $id => list($confidential, $parent, $ra_email, $title)) {
150 daniel-mar 246
                                if ($parent == $this->nodeId()) {
247
                                        $obj = self::parse($id);
248
                                        if (!$obj) continue;
249
                                        $out[] = $obj;
250
                                }
251
                        }
252
                }
253
                return $out;
2 daniel-mar 254
        }
255
 
115 daniel-mar 256
        public function getRa() {
150 daniel-mar 257
                return new OIDplusRA($this->getRaMail());
115 daniel-mar 258
        }
259
 
2 daniel-mar 260
        public function userHasReadRights($ra_email=null) {
115 daniel-mar 261
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
262
 
2 daniel-mar 263
                // Admin may do everything
264
                if (OIDplus::authUtils()::isAdminLoggedIn()) return true;
265
 
266
                // If it is not confidential, everybody can read/see it.
267
                if (!$this->isConfidential()) return true;
268
 
269
                // If we own the object, we may see it
270
                if (is_null($ra_email)) {
271
                        if ($this->userHasWriteRights()) return true;
272
                } else {
150 daniel-mar 273
                        if ($this->getRaMail() == $ra_email) return true;
2 daniel-mar 274
                }
275
 
276
                // If someone has rights to an object below our confidential node,
277
                // we let him see the confidential node,
278
                // Otherwise he could not browse through to his own node.
279
                $roots = $this->getRaRoots($ra_email);
280
                foreach ($roots as $root) {
281
                        if ($root->isChildOf($this)) return true;
282
                }
283
 
284
                return false;
285
        }
286
 
287
        public function getIcon($row=null) {
20 daniel-mar 288
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
2 daniel-mar 289
 
290
                if (is_null($row)) {
150 daniel-mar 291
                        $ra_email = $this->getRaMail();
292
                } else {
293
                        $ra_email = $row['ra_email'];
2 daniel-mar 294
                }
295
                // TODO: have different icons for Leaf-Nodes
150 daniel-mar 296
                if (OIDplus::authUtils()::isRaLoggedIn($ra_email)) {
2 daniel-mar 297
                        $icon = 'plugins/objectTypes/'.$namespace.'/img/treeicon_own.png';
298
                } else {
299
                        $icon = 'plugins/objectTypes/'.$namespace.'/img/treeicon_general.png';
300
                }
301
                if (!file_exists($icon)) $icon = null; // default icon (folder)
302
                return $icon;
303
        }
304
 
12 daniel-mar 305
        public static function exists($id) {
150 daniel-mar 306
                if (!OIDPLUS_OBJECT_CACHING) {
307
                        $res = OIDplus::db()->query("select id from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($id));
236 daniel-mar 308
                        return $res->num_rows() > 0;
150 daniel-mar 309
                } else {
310
                        self::buildObjectInformationCache();
311
                        return isset(self::$object_info_cache[$id]);
312
                }
12 daniel-mar 313
        }
314
 
2 daniel-mar 315
        public function getParent() {
150 daniel-mar 316
                if (!OIDPLUS_OBJECT_CACHING) {
317
                        $res = OIDplus::db()->query("select parent from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($this->nodeId()));
236 daniel-mar 318
                        $row = $res->fetch_array();
150 daniel-mar 319
                        $parent = $row['parent'];
320
                        $obj = OIDplusObject::parse($parent);
321
                        if ($obj) return $obj;
322
                } else {
323
                        self::buildObjectInformationCache();
324
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
325
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
326
                                $obj = OIDplusObject::parse($parent);
327
                                if ($obj) return $obj;
328
                        }
20 daniel-mar 329
 
150 daniel-mar 330
                        // If this OID does not exist, the SQL query "select parent from ..." does not work. So we try to find the next possible parent using one_up()
331
                        $cur = $this->one_up();
20 daniel-mar 332
                        if (!$cur) return false;
150 daniel-mar 333
                        do {
334
                                if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
20 daniel-mar 335
 
150 daniel-mar 336
                                $prev = $cur;
337
                                $cur = $cur->one_up();
338
                                if (!$cur) return false;
339
                        } while ($prev != $cur);
340
 
341
                        return false;
342
                }
2 daniel-mar 343
        }
344
 
345
        public function getRaMail() {
150 daniel-mar 346
                if (!OIDPLUS_OBJECT_CACHING) {
347
                        $res = OIDplus::db()->query("select ra_email from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($this->nodeId()));
236 daniel-mar 348
                        $row = $res->fetch_array();
150 daniel-mar 349
                        return $row['ra_email'];
350
                } else {
351
                        self::buildObjectInformationCache();
352
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
353
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
354
                        }
355
                        return false;
356
                }
2 daniel-mar 357
        }
358
 
192 daniel-mar 359
        public function getTitle() {
360
                if (!OIDPLUS_OBJECT_CACHING) {
361
                        $res = OIDplus::db()->query("select title from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($this->nodeId()));
236 daniel-mar 362
                        $row = $res->fetch_array();
192 daniel-mar 363
                        return $row['title'];
364
                } else {
365
                        self::buildObjectInformationCache();
366
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
367
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
368
                        }
369
                        return false;
370
                }
371
        }
372
 
2 daniel-mar 373
        public function userHasParentalWriteRights($ra_email=null) {
115 daniel-mar 374
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
375
 
2 daniel-mar 376
                if (is_null($ra_email)) {
377
                        if (OIDplus::authUtils()::isAdminLoggedIn()) return true;
378
                }
379
 
380
                $objParent = $this->getParent();
381
                if (is_null($objParent)) return false;
382
                return $objParent->userHasWriteRights($ra_email);
383
        }
384
 
385
        public function userHasWriteRights($ra_email=null) {
115 daniel-mar 386
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
387
 
2 daniel-mar 388
                if (is_null($ra_email)) {
389
                        if (OIDplus::authUtils()::isAdminLoggedIn()) return true;
390
                        return OIDplus::authUtils()::isRaLoggedIn($this->getRaMail());
391
                } else {
392
                        return $this->getRaMail() == $ra_email;
393
                }
394
        }
12 daniel-mar 395
 
396
        public function distance($to) {
397
                return null; // not implemented
398
        }
20 daniel-mar 399
 
400
        public function equals($obj) {
401
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
28 daniel-mar 402
                if (!($obj instanceof $this)) return false;
403
 
20 daniel-mar 404
                $distance = $this->distance($obj);
405
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
406
 
407
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
408
        }
409
 
410
        public static function findFitting($id) {
411
                $obj = OIDplusObject::parse($id);
412
                if (!$obj) throw new Exception("findFitting: Parse failed\n");
413
 
150 daniel-mar 414
                if (!OIDPLUS_OBJECT_CACHING) {
415
                        $res = OIDplus::db()->query("select id from ".OIDPLUS_TABLENAME_PREFIX."objects where id like ?", array($obj->ns().':%'));
236 daniel-mar 416
                        while ($row = $res->fetch_object()) {
150 daniel-mar 417
                                $test = OIDplusObject::parse($row->id);
418
                                if ($obj->equals($test)) return $test;
419
                        }
420
                        return false;
421
                } else {
422
                        self::buildObjectInformationCache();
193 daniel-mar 423
                        foreach (self::$object_info_cache as $id => list($confidential, $parent, $ra_email, $title)) {
150 daniel-mar 424
                                if (strpos($id, $obj->ns().':') === 0) {
425
                                        $test = OIDplusObject::parse($id);
426
                                        if ($obj->equals($test)) return $test;
427
                                }
428
                        }
429
                        return false;
20 daniel-mar 430
                }
431
        }
432
 
433
        public function one_up() {
434
                return null; // not implemented
435
        }
150 daniel-mar 436
 
437
        // Caching stuff
438
 
439
        protected static $object_info_cache = null;
440
 
441
        public static function resetObjectInformationCache() {
442
                self::$object_info_cache = null;
443
        }
444
 
193 daniel-mar 445
        const CACHE_CONFIDENTIAL = 0; // TODO: An object would be better so you can use $cacheitem->isConfidential() etc.
150 daniel-mar 446
        const CACHE_PARENT = 1;
447
        const CACHE_RA_EMAIL = 2;
192 daniel-mar 448
        const CACHE_TITLE = 3;
150 daniel-mar 449
 
450
        private static function buildObjectInformationCache() {
451
                if (is_null(self::$object_info_cache)) {
452
                        self::$object_info_cache = array();
192 daniel-mar 453
                        $res = OIDplus::db()->query("select id, parent, confidential, ra_email, title from ".OIDPLUS_TABLENAME_PREFIX."objects");
236 daniel-mar 454
                        while ($row = $res->fetch_array()) {
150 daniel-mar 455
                                if ($row['confidential'] == chr(0)) $row['confidential'] = false; // ODBC...
456
                                if ($row['confidential'] == chr(1)) $row['confidential'] = true; // ODBC...
192 daniel-mar 457
                                self::$object_info_cache[$row['id']] = array($row['confidential'], $row['parent'], $row['ra_email'], $row['title']);
150 daniel-mar 458
                        }
459
                }
460
        }
2 daniel-mar 461
}