Subversion Repositories oidplus

Rev

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