Subversion Repositories oidplus

Rev

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