Subversion Repositories oidplus

Rev

Rev 969 | Rev 977 | 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
929 daniel-mar 5
 * Copyright 2019 - 2022 Daniel Marschall, ViaThinkSoft
2 daniel-mar 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
 
511 daniel-mar 20
if (!defined('INSIDE_OIDPLUS')) die();
21
 
730 daniel-mar 22
abstract class OIDplusObject extends OIDplusBaseClass {
261 daniel-mar 23
        const UUID_NAMEBASED_NS_OidPlusMisc = 'ad1654e6-7e15-11e4-9ef6-78e3b5fc7f22';
150 daniel-mar 24
 
2 daniel-mar 25
        public static function parse($node_id) { // please overwrite this function!
227 daniel-mar 26
                foreach (OIDplus::getEnabledObjectTypes() as $ot) {
954 daniel-mar 27
                        try {
956 daniel-mar 28
                                $good = false;
29
                                if (get_parent_class($ot) == 'OIDplusObject') {
30
                                        $reflector = new \ReflectionMethod($ot, 'parse');
31
                                        $isImplemented = ($reflector->getDeclaringClass()->getName() === $ot);
32
                                        if ($isImplemented) { // avoid endless loop if parse is not overriden
33
                                                $good = true;
34
                                        }
35
                                }
36
                                // We need to do the workaround with "$good", otherwise PHPstan shows
37
                                // "Call to an undefined static method object::parse()"
38
                                if ($good && $obj = $ot::parse($node_id)) return $obj;
954 daniel-mar 39
                        } catch (Exception $e) {}
2 daniel-mar 40
                }
41
                return null;
42
        }
43
 
228 daniel-mar 44
        public function /*OIDplusAltId[]*/ getAltIds() {
193 daniel-mar 45
                if ($this->isRoot()) return array();
46
 
47
                $ids = array();
48
                if ($this->ns() != 'oid') {
49
                        // Creates an OIDplus-Hash-OID
227 daniel-mar 50
                        $sid = OIDplus::getSystemId(true);
193 daniel-mar 51
                        if (!empty($sid)) {
817 daniel-mar 52
                                $ns_oid = $this->getPlugin()->getManifest()->getOid();
835 daniel-mar 53
                                if (str_starts_with($ns_oid, '1.3.6.1.4.1.37476.2.5.2.')) {
817 daniel-mar 54
                                        // Official ViaThinkSoft object type plugins
55
                                        // For backwards compatibility with existing IDs,
56
                                        // set the hash_payload as '<namespace>:<id>'
57
                                        $hash_payload = $this->nodeId(true);
58
                                } else {
59
                                        // Third-party object type plugins
60
                                        // Set the hash_payload as '<plugin oid>:<id>'
61
                                        $hash_payload = $ns_oid.':'.$this->nodeId(false);
62
                                }
63
                                $oid = $sid . '.' . smallhash($hash_payload);
360 daniel-mar 64
                                $ids[] = new OIDplusAltId('oid', $oid, _L('OIDplus Information Object ID'));
193 daniel-mar 65
                        }
929 daniel-mar 66
 
67
                        // Make a namebased UUID, but...
68
                        // ... exclude GUID, because a GUID is already a GUID
69
                        // ... exclude OID, because an OID already has a record UUID_NAMEBASED_NS_OID set  by class OIDplusOid
70
                        if ($this->ns() != 'guid') {
71
                                $ids[] = new OIDplusAltId('guid', gen_uuid_md5_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 3 / MD5 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
72
                                $ids[] = new OIDplusAltId('guid', gen_uuid_sha1_namebased(self::UUID_NAMEBASED_NS_OidPlusMisc, $this->nodeId()), _L('Name based version 5 / SHA1 UUID with namespace %1','UUID_NAMEBASED_NS_OidPlusMisc'));
73
                        }
193 daniel-mar 74
                }
75
                return $ids;
83 daniel-mar 76
        }
77
 
2 daniel-mar 78
        public abstract static function objectTypeTitle();
79
 
80
        public abstract static function objectTypeTitleShort();
81
 
817 daniel-mar 82
        public function getPlugin()/*: ?OIDplusObjectTypePlugin */ {
83
                $res = null;
84
                $plugins = OIDplus::getObjectTypePlugins();
85
                foreach ($plugins as $plugin) {
86
                        if (get_class($this) == $plugin::getObjectTypeClassName($this)) {
87
                                return $plugin;
88
                        }
89
                }
90
                return $res;
91
        }
92
 
2 daniel-mar 93
        public abstract static function ns();
94
 
95
        public abstract static function root();
96
 
97
        public abstract function isRoot();
98
 
247 daniel-mar 99
        public abstract function nodeId($with_ns=true);
2 daniel-mar 100
 
101
        public abstract function addString($str);
102
 
103
        public abstract function crudShowId(OIDplusObject $parent);
104
 
707 daniel-mar 105
        public function crudInsertPrefix() {
106
                return '';
107
        }
2 daniel-mar 108
 
707 daniel-mar 109
        public function crudInsertSuffix() {
110
                return '';
111
        }
112
 
2 daniel-mar 113
        public abstract function jsTreeNodeName(OIDplusObject $parent = null);
114
 
115
        public abstract function defaultTitle();
116
 
16 daniel-mar 117
        public abstract function isLeafNode();
118
 
34 daniel-mar 119
        public abstract function getContentPage(&$title, &$content, &$icon);
2 daniel-mar 120
 
27 daniel-mar 121
        public static function getRaRoots($ra_email=null) {
115 daniel-mar 122
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
123
 
27 daniel-mar 124
                $out = array();
150 daniel-mar 125
 
261 daniel-mar 126
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
150 daniel-mar 127
                        if (is_null($ra_email)) {
261 daniel-mar 128
                                $res = OIDplus::db()->query("select oChild.id as id, oChild.ra_email as child_mail, oParent.ra_email as parent_mail from ###objects as oChild ".
129
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
150 daniel-mar 130
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'));
236 daniel-mar 131
                                while ($row = $res->fetch_array()) {
549 daniel-mar 132
                                        if (!OIDplus::authUtils()->isRaLoggedIn($row['parent_mail']) && OIDplus::authUtils()->isRaLoggedIn($row['child_mail'])) {
150 daniel-mar 133
                                                $x = self::parse($row['id']); // can be FALSE if namespace was disabled
134
                                                if ($x) $out[] = $x;
135
                                        }
136
                                }
137
                        } else {
261 daniel-mar 138
                                $res = OIDplus::db()->query("select oChild.id as id from ###objects as oChild ".
139
                                                            "left join ###objects as oParent on oChild.parent = oParent.id ".
433 daniel-mar 140
                                                            "where (".OIDplus::db()->getSlang()->isNullFunction('oParent.ra_email',"''")." <> ? and ".
141
                                                            OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) or ".
142
                                                            "      (oParent.ra_email is null and ".OIDplus::db()->getSlang()->isNullFunction('oChild.ra_email',"''")." = ?) ".
150 daniel-mar 143
                                                            "order by ".OIDplus::db()->natOrder('oChild.id'), array($ra_email, $ra_email, $ra_email));
236 daniel-mar 144
                                while ($row = $res->fetch_array()) {
68 daniel-mar 145
                                        $x = self::parse($row['id']); // can be FALSE if namespace was disabled
150 daniel-mar 146
                                        if ($x) $out[] = self::parse($row['id']);
27 daniel-mar 147
                                }
2 daniel-mar 148
                        }
149
                } else {
150 daniel-mar 150
                        if (is_null($ra_email)) {
415 daniel-mar 151
                                $ra_mails_to_check = OIDplus::authUtils()->loggedInRaList();
150 daniel-mar 152
                                if (count($ra_mails_to_check) == 0) return $out;
153
                        } else {
154
                                $ra_mails_to_check = array($ra_email);
2 daniel-mar 155
                        }
150 daniel-mar 156
 
157
                        self::buildObjectInformationCache();
158
 
159
                        foreach ($ra_mails_to_check as $check_ra_mail) {
193 daniel-mar 160
                                $out_part = array();
150 daniel-mar 161
 
975 daniel-mar 162
                                foreach (self::$object_info_cache as $id => $cacheitem) {
193 daniel-mar 163
                                        // If the OID RA is the RA we are searching, then add the object to the choice list
975 daniel-mar 164
                                        $ra_email = $cacheitem[self::CACHE_RA_EMAIL];
193 daniel-mar 165
                                        if ($ra_email == $check_ra_mail) $out_part[] = $id;
150 daniel-mar 166
                                }
167
 
975 daniel-mar 168
                                foreach (self::$object_info_cache as $id => $cacheitem) {
169
                                        $parent = $cacheitem[self::CACHE_PARENT];
193 daniel-mar 170
                                        if (isset(self::$object_info_cache[$parent])) {
171
                                                if (self::$object_info_cache[$parent][self::CACHE_RA_EMAIL] == $ra_email) {
172
                                                        // if the parent has the same RA, then this OID cannot be a root => remove the element from the choice list
173
                                                        foreach (array_keys($out_part, $id) as $key) unset($out_part[$key]);
150 daniel-mar 174
                                                }
175
                                        }
176
                                }
177
 
178
                                natsort($out_part);
179
 
180
                                foreach ($out_part as $id) {
181
                                        $obj = self::parse($id);
182
                                        if ($obj) $out[] = $obj;
183
                                }
184
                        }
2 daniel-mar 185
                }
150 daniel-mar 186
 
2 daniel-mar 187
                return $out;
188
        }
189
 
150 daniel-mar 190
        public static function getAllNonConfidential() {
191
                $out = array();
192
 
261 daniel-mar 193
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
443 daniel-mar 194
                        $res = OIDplus::db()->query("select id from ###objects where confidential = ? order by ".OIDplus::db()->natOrder('id'), array(false));
150 daniel-mar 195
 
236 daniel-mar 196
                        while ($row = $res->fetch_array()) {
150 daniel-mar 197
                                $obj = self::parse($row['id']); // will be NULL if the object type is not registered
169 daniel-mar 198
                                if ($obj && (!$obj->isConfidential())) {
150 daniel-mar 199
                                        $out[] = $row['id'];
200
                                }
2 daniel-mar 201
                        }
202
                } else {
150 daniel-mar 203
                        self::buildObjectInformationCache();
2 daniel-mar 204
 
975 daniel-mar 205
                        foreach (self::$object_info_cache as $id => $cacheitem) {
206
                                $confidential = $cacheitem[self::CACHE_CONFIDENTIAL];
150 daniel-mar 207
                                if (!$confidential) {
208
                                        $obj = self::parse($id); // will be NULL if the object type is not registered
169 daniel-mar 209
                                        if ($obj && (!$obj->isConfidential())) {
150 daniel-mar 210
                                                $out[] = $id;
211
                                        }
212
                                }
2 daniel-mar 213
                        }
214
                }
215
 
216
                return $out;
217
        }
218
 
219
        public function isConfidential() {
261 daniel-mar 220
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
426 daniel-mar 221
                        //static $confidential_cache = array();
150 daniel-mar 222
                        $curid = $this->nodeId();
426 daniel-mar 223
                        //$orig_curid = $curid;
224
                        //if (isset($confidential_cache[$curid])) return $confidential_cache[$curid];
150 daniel-mar 225
                        // Recursively search for the confidential flag in the parents
790 daniel-mar 226
                        while (($res = OIDplus::db()->query("select parent, confidential from ###objects where id = ?", array($curid)))->any()) {
236 daniel-mar 227
                                $row = $res->fetch_array();
150 daniel-mar 228
                                if ($row['confidential']) {
426 daniel-mar 229
                                        //$confidential_cache[$curid] = true;
230
                                        //$confidential_cache[$orig_curid] = true;
150 daniel-mar 231
                                        return true;
232
                                } else {
426 daniel-mar 233
                                        //$confidential_cache[$curid] = false;
150 daniel-mar 234
                                }
235
                                $curid = $row['parent'];
426 daniel-mar 236
                                //if (isset($confidential_cache[$curid])) {
237
                                        //$confidential_cache[$orig_curid] = $confidential_cache[$curid];
238
                                        //return $confidential_cache[$curid];
239
                                //}
150 daniel-mar 240
                        }
241
 
426 daniel-mar 242
                        //$confidential_cache[$orig_curid] = false;
150 daniel-mar 243
                        return false;
244
                } else {
245
                        self::buildObjectInformationCache();
246
 
247
                        $curid = $this->nodeId();
248
                        // Recursively search for the confidential flag in the parents
169 daniel-mar 249
                        while (isset(self::$object_info_cache[$curid])) {
150 daniel-mar 250
                                if (self::$object_info_cache[$curid][self::CACHE_CONFIDENTIAL]) return true;
251
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
252
                        }
253
                        return false;
2 daniel-mar 254
                }
255
        }
256
 
257
        public function isChildOf(OIDplusObject $obj) {
261 daniel-mar 258
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
150 daniel-mar 259
                        $curid = $this->nodeId();
790 daniel-mar 260
                        while (($res = OIDplus::db()->query("select parent from ###objects where id = ?", array($curid)))->any()) {
236 daniel-mar 261
                                $row = $res->fetch_array();
150 daniel-mar 262
                                if ($curid == $obj->nodeId()) return true;
263
                                $curid = $row['parent'];
264
                        }
265
                        return false;
266
                } else {
267
                        self::buildObjectInformationCache();
268
 
269
                        $curid = $this->nodeId();
169 daniel-mar 270
                        while (isset(self::$object_info_cache[$curid])) {
150 daniel-mar 271
                                if ($curid == $obj->nodeId()) return true;
272
                                $curid = self::$object_info_cache[$curid][self::CACHE_PARENT];
273
                        }
274
                        return false;
2 daniel-mar 275
                }
150 daniel-mar 276
        }
2 daniel-mar 277
 
150 daniel-mar 278
        public function getChildren() {
279
                $out = array();
261 daniel-mar 280
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
281
                        $res = OIDplus::db()->query("select id from ###objects where parent = ?", array($this->nodeId()));
236 daniel-mar 282
                        while ($row = $res->fetch_array()) {
150 daniel-mar 283
                                $obj = self::parse($row['id']);
284
                                if (!$obj) continue;
285
                                $out[] = $obj;
286
                        }
287
                } else {
288
                        self::buildObjectInformationCache();
289
 
975 daniel-mar 290
                        foreach (self::$object_info_cache as $id => $cacheitem) {
291
                                $parent = $cacheitem[self::CACHE_PARENT];
150 daniel-mar 292
                                if ($parent == $this->nodeId()) {
293
                                        $obj = self::parse($id);
294
                                        if (!$obj) continue;
295
                                        $out[] = $obj;
296
                                }
297
                        }
298
                }
299
                return $out;
2 daniel-mar 300
        }
301
 
115 daniel-mar 302
        public function getRa() {
150 daniel-mar 303
                return new OIDplusRA($this->getRaMail());
115 daniel-mar 304
        }
305
 
2 daniel-mar 306
        public function userHasReadRights($ra_email=null) {
115 daniel-mar 307
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
308
 
2 daniel-mar 309
                // If it is not confidential, everybody can read/see it.
416 daniel-mar 310
                // Note: This also checks if superior OIDs are confidential.
2 daniel-mar 311
                if (!$this->isConfidential()) return true;
312
 
313
                if (is_null($ra_email)) {
416 daniel-mar 314
                        // Admin may do everything
549 daniel-mar 315
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
416 daniel-mar 316
 
317
                        // If the RA is logged in, then they can see the OID.
549 daniel-mar 318
                        if (OIDplus::authUtils()->isRaLoggedIn($this->getRaMail())) return true;
2 daniel-mar 319
                } else {
416 daniel-mar 320
                        // If this OID belongs to the requested RA, then they may see it.
150 daniel-mar 321
                        if ($this->getRaMail() == $ra_email) return true;
2 daniel-mar 322
                }
323
 
324
                // If someone has rights to an object below our confidential node,
325
                // we let him see the confidential node,
326
                // Otherwise he could not browse through to his own node.
327
                $roots = $this->getRaRoots($ra_email);
328
                foreach ($roots as $root) {
329
                        if ($root->isChildOf($this)) return true;
330
                }
331
 
332
                return false;
333
        }
334
 
335
        public function getIcon($row=null) {
20 daniel-mar 336
                $namespace = $this->ns(); // must use $this, not self::, otherwise the virtual method will not be called
2 daniel-mar 337
 
338
                if (is_null($row)) {
150 daniel-mar 339
                        $ra_email = $this->getRaMail();
340
                } else {
341
                        $ra_email = $row['ra_email'];
2 daniel-mar 342
                }
343
                // TODO: have different icons for Leaf-Nodes
632 daniel-mar 344
 
635 daniel-mar 345
                $dirs = glob(OIDplus::localpath().'plugins/'.'*'.'/objectTypes/'.$namespace.'/');
632 daniel-mar 346
 
347
                if (count($dirs) == 0) return null; // default icon (folder)
348
 
349
                $dir = substr($dirs[0], strlen(OIDplus::localpath()));
350
 
805 daniel-mar 351
                // We use $this:: instead of self:: , because we want to call the overridden methods
549 daniel-mar 352
                if (OIDplus::authUtils()->isRaLoggedIn($ra_email)) {
805 daniel-mar 353
                        $icon = $dir.'/'.$this::treeIconFilename('own');
2 daniel-mar 354
                } else {
805 daniel-mar 355
                        $icon = $dir.'/'.$this::treeIconFilename('general');
2 daniel-mar 356
                }
632 daniel-mar 357
 
358
                if (!file_exists($icon)) return null; // default icon (folder)
359
 
2 daniel-mar 360
                return $icon;
361
        }
362
 
12 daniel-mar 363
        public static function exists($id) {
261 daniel-mar 364
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
365
                        $res = OIDplus::db()->query("select id from ###objects where id = ?", array($id));
790 daniel-mar 366
                        return $res->any();
150 daniel-mar 367
                } else {
368
                        self::buildObjectInformationCache();
369
                        return isset(self::$object_info_cache[$id]);
370
                }
12 daniel-mar 371
        }
372
 
415 daniel-mar 373
        // Get parent gives the next possible parent which is EXISTING in OIDplus
374
        // It does not give the immediate parent
2 daniel-mar 375
        public function getParent() {
261 daniel-mar 376
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
377
                        $res = OIDplus::db()->query("select parent from ###objects where id = ?", array($this->nodeId()));
790 daniel-mar 378
                        if (!$res->any()) return null;
236 daniel-mar 379
                        $row = $res->fetch_array();
150 daniel-mar 380
                        $parent = $row['parent'];
381
                        $obj = OIDplusObject::parse($parent);
382
                        if ($obj) return $obj;
415 daniel-mar 383
                        // TODO: Also implement one_up() like below
150 daniel-mar 384
                } else {
385
                        self::buildObjectInformationCache();
386
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
387
                                $parent = self::$object_info_cache[$this->nodeId()][self::CACHE_PARENT];
388
                                $obj = OIDplusObject::parse($parent);
389
                                if ($obj) return $obj;
390
                        }
20 daniel-mar 391
 
150 daniel-mar 392
                        // 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()
393
                        $cur = $this->one_up();
418 daniel-mar 394
                        if (!$cur) return null;
150 daniel-mar 395
                        do {
415 daniel-mar 396
                                // findFitting() checks if that OID exists
150 daniel-mar 397
                                if ($fitting = self::findFitting($cur->nodeId())) return $fitting;
20 daniel-mar 398
 
150 daniel-mar 399
                                $prev = $cur;
400
                                $cur = $cur->one_up();
418 daniel-mar 401
                                if (!$cur) return null;
150 daniel-mar 402
                        } while ($prev != $cur);
403
 
418 daniel-mar 404
                        return null;
150 daniel-mar 405
                }
2 daniel-mar 406
        }
407
 
408
        public function getRaMail() {
261 daniel-mar 409
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
410
                        $res = OIDplus::db()->query("select ra_email from ###objects where id = ?", array($this->nodeId()));
790 daniel-mar 411
                        if (!$res->any()) return null;
236 daniel-mar 412
                        $row = $res->fetch_array();
150 daniel-mar 413
                        return $row['ra_email'];
414
                } else {
415
                        self::buildObjectInformationCache();
416
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
417
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_RA_EMAIL];
418
                        }
419
                        return false;
420
                }
2 daniel-mar 421
        }
422
 
192 daniel-mar 423
        public function getTitle() {
261 daniel-mar 424
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
425
                        $res = OIDplus::db()->query("select title from ###objects where id = ?", array($this->nodeId()));
790 daniel-mar 426
                        if (!$res->any()) return null;
236 daniel-mar 427
                        $row = $res->fetch_array();
192 daniel-mar 428
                        return $row['title'];
429
                } else {
430
                        self::buildObjectInformationCache();
431
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
432
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_TITLE];
433
                        }
434
                        return false;
435
                }
436
        }
437
 
975 daniel-mar 438
        public function getDescription() {
439
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
440
                        $res = OIDplus::db()->query("select description from ###objects where id = ?", array($this->nodeId()));
441
                        if (!$res->any()) return null;
442
                        $row = $res->fetch_array();
443
                        return $row['description'];
444
                } else {
445
                        self::buildObjectInformationCache();
446
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
447
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_DESCRIPTION];
448
                        }
449
                        return false;
450
                }
451
        }
452
 
453
        public function getComment() {
454
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
455
                        $res = OIDplus::db()->query("select comment from ###objects where id = ?", array($this->nodeId()));
456
                        if (!$res->any()) return null;
457
                        $row = $res->fetch_array();
458
                        return $row['comment'];
459
                } else {
460
                        self::buildObjectInformationCache();
461
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
462
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_COMMENT];
463
                        }
464
                        return false;
465
                }
466
        }
467
 
468
        public function getCreatedTime() {
469
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
470
                        $res = OIDplus::db()->query("select created from ###objects where id = ?", array($this->nodeId()));
471
                        if (!$res->any()) return null;
472
                        $row = $res->fetch_array();
473
                        return $row['created'];
474
                } else {
475
                        self::buildObjectInformationCache();
476
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
477
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_CREATED];
478
                        }
479
                        return false;
480
                }
481
        }
482
 
483
        public function getUpdatedTime() {
484
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
485
                        $res = OIDplus::db()->query("select updated from ###objects where id = ?", array($this->nodeId()));
486
                        if (!$res->any()) return null;
487
                        $row = $res->fetch_array();
488
                        return $row['updated'];
489
                } else {
490
                        self::buildObjectInformationCache();
491
                        if (isset(self::$object_info_cache[$this->nodeId()])) {
492
                                return self::$object_info_cache[$this->nodeId()][self::CACHE_UPDATED];
493
                        }
494
                        return false;
495
                }
496
        }
497
 
2 daniel-mar 498
        public function userHasParentalWriteRights($ra_email=null) {
115 daniel-mar 499
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
500
 
2 daniel-mar 501
                if (is_null($ra_email)) {
549 daniel-mar 502
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
2 daniel-mar 503
                }
504
 
505
                $objParent = $this->getParent();
419 daniel-mar 506
                if (!$objParent) return false;
2 daniel-mar 507
                return $objParent->userHasWriteRights($ra_email);
508
        }
509
 
510
        public function userHasWriteRights($ra_email=null) {
115 daniel-mar 511
                if ($ra_email instanceof OIDplusRA) $ra_email = $ra_email->raEmail();
512
 
2 daniel-mar 513
                if (is_null($ra_email)) {
549 daniel-mar 514
                        if (OIDplus::authUtils()->isAdminLoggedIn()) return true;
515
                        return OIDplus::authUtils()->isRaLoggedIn($this->getRaMail());
2 daniel-mar 516
                } else {
517
                        return $this->getRaMail() == $ra_email;
518
                }
519
        }
12 daniel-mar 520
 
521
        public function distance($to) {
522
                return null; // not implemented
523
        }
20 daniel-mar 524
 
525
        public function equals($obj) {
526
                if (!is_object($obj)) $obj = OIDplusObject::parse($obj);
28 daniel-mar 527
                if (!($obj instanceof $this)) return false;
528
 
20 daniel-mar 529
                $distance = $this->distance($obj);
530
                if (is_numeric($distance)) return $distance === 0; // if the distance function is implemented, use it
531
 
532
                return $this->nodeId() == $obj->nodeId(); // otherwise compare the node id case-sensitive
533
        }
534
 
535
        public static function findFitting($id) {
536
                $obj = OIDplusObject::parse($id);
969 daniel-mar 537
                if (!$obj) return false; // e.g. if ObjectType plugin is disabled
20 daniel-mar 538
 
261 daniel-mar 539
                if (!OIDplus::baseConfig()->getValue('OBJECT_CACHING', true)) {
540
                        $res = OIDplus::db()->query("select id from ###objects where id like ?", array($obj->ns().':%'));
236 daniel-mar 541
                        while ($row = $res->fetch_object()) {
150 daniel-mar 542
                                $test = OIDplusObject::parse($row->id);
543
                                if ($obj->equals($test)) return $test;
544
                        }
545
                        return false;
546
                } else {
547
                        self::buildObjectInformationCache();
975 daniel-mar 548
                        foreach (self::$object_info_cache as $id => $cacheitem) {
150 daniel-mar 549
                                if (strpos($id, $obj->ns().':') === 0) {
550
                                        $test = OIDplusObject::parse($id);
551
                                        if ($obj->equals($test)) return $test;
552
                                }
553
                        }
554
                        return false;
20 daniel-mar 555
                }
556
        }
557
 
558
        public function one_up() {
559
                return null; // not implemented
560
        }
150 daniel-mar 561
 
562
        // Caching stuff
563
 
564
        protected static $object_info_cache = null;
565
 
566
        public static function resetObjectInformationCache() {
567
                self::$object_info_cache = null;
568
        }
569
 
975 daniel-mar 570
        const CACHE_ID = 'id';
571
        const CACHE_PARENT = 'parent';
572
        const CACHE_TITLE = 'title';
573
        const CACHE_DESCRIPTION = 'description';
574
        const CACHE_RA_EMAIL = 'ra_email';
575
        const CACHE_CONFIDENTIAL = 'confidential';
576
        const CACHE_CREATED = 'created';
577
        const CACHE_UPDATED = 'updated';
578
        const CACHE_COMMENT = 'comment';
150 daniel-mar 579
 
580
        private static function buildObjectInformationCache() {
581
                if (is_null(self::$object_info_cache)) {
582
                        self::$object_info_cache = array();
975 daniel-mar 583
                        $res = OIDplus::db()->query("select * from ###objects");
236 daniel-mar 584
                        while ($row = $res->fetch_array()) {
975 daniel-mar 585
                                self::$object_info_cache[$row['id']] = $row;
150 daniel-mar 586
                        }
587
                }
588
        }
513 daniel-mar 589
 
590
        // override this function if you want your object type to save
591
        // attachments in directories with easy names.
592
        // Take care that your custom directory name will not allow jailbreaks (../) !
593
        public function getDirectoryName() {
514 daniel-mar 594
                if ($this->isRoot()) return $this->ns();
595
                return $this->getLegacyDirectoryName();
513 daniel-mar 596
        }
597
 
514 daniel-mar 598
        public final function getLegacyDirectoryName() {
804 daniel-mar 599
                if ($this::ns() == 'oid') {
513 daniel-mar 600
                        $oid = $this->nodeId(false);
601
                } else {
602
                        $oid = null;
603
                        $alt_ids = $this->getAltIds();
604
                        foreach ($alt_ids as $alt_id) {
605
                                if ($alt_id->getNamespace() == 'oid') {
606
                                        $oid = $alt_id->getId();
607
                                        break; // we prefer the first OID (for GUIDs, the first OID is the OIDplus-OID, and the second OID is the UUID OID)
608
                                }
609
                        }
610
                }
611
 
612
                if (!is_null($oid) && ($oid != '')) {
613
                        // For OIDs, it is the OID, for other identifiers
614
                        // it it the OID alt ID (generated using the SystemID)
615
                        return str_replace('.', '_', $oid);
616
                } else {
617
                        // Can happen if you don't have a system ID (due to missing OpenSSL plugin)
618
                        return md5($this->nodeId(true)); // we don't use $id, because $this->nodeId(true) is possibly more canonical than $id
619
                }
620
        }
800 daniel-mar 621
 
805 daniel-mar 622
        public static function treeIconFilename($mode) {
800 daniel-mar 623
                // for backwards-compatibility with older plugins
624
                return 'img/treeicon_'.$mode.'.png';
625
        }
626
 
415 daniel-mar 627
}