Subversion Repositories oidplus

Rev

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