Subversion Repositories oidplus

Rev

Rev 238 | Rev 251 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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.  
  20. if (!defined('IN_OIDPLUS')) die();
  21.  
  22. class OIDplusGui {
  23.  
  24.         private static $crudCounter = 0;
  25.  
  26.         protected static function objDescription($html) {
  27.                 // We allow HTML, but no hacking
  28.                 $html = anti_xss($html);
  29.  
  30.                 return trim_br($html);
  31.         }
  32.  
  33.         protected static function showCrud($parent='oid:') {
  34.                 $items_total = 0;
  35.                 $items_hidden = 0;
  36.  
  37.                 $objParent = OIDplusObject::parse($parent);
  38.                 $parentNS = $objParent::ns();
  39.  
  40.                 $result = OIDplus::db()->query("select o.*, r.ra_name " .
  41.                                                "from ".OIDPLUS_TABLENAME_PREFIX."objects o " .
  42.                                                "left join ".OIDPLUS_TABLENAME_PREFIX."ra r on r.email = o.ra_email " .
  43.                                                "where parent = ? " .
  44.                                                "order by ".OIDplus::db()->natOrder('id'), array($parent));
  45.                 $rows = array();
  46.                 if ($parentNS == 'oid') {
  47.                         $one_weid_available = $objParent->isWeid(true);
  48.                         while ($row = $result->fetch_object()) {
  49.                                 $obj = OIDplusObject::parse($row->id);
  50.                                 $rows[] = array($obj,$row);
  51.                                 if (!$one_weid_available) {
  52.                                         if ($obj->isWeid(true)) $one_weid_available = true;
  53.                                 }
  54.                         }
  55.                 } else {
  56.                         $one_weid_available = false;
  57.                         while ($row = $result->fetch_object()) {
  58.                                 $obj = OIDplusObject::parse($row->id);
  59.                                 $rows[] = array($obj,$row);
  60.                         }
  61.                 }
  62.  
  63.                 $output = '';
  64.                 $output .= '<div class="container box"><div id="suboid_table" class="table-responsive">';
  65.                 $output .= '<table class="table table-bordered table-striped">';
  66.                 $output .= '    <tr>';
  67.                 $output .= '         <th>ID'.(($parentNS == 'gs1') ? ' (without check digit)' : '').'</th>';
  68.                 if ($parentNS == 'oid') {
  69.                         if ($one_weid_available) $output .= '        <th>WEID</th>';
  70.                         $output .= '         <th>ASN.1 IDs (comma sep.)</th>';
  71.                         $output .= '         <th>IRI IDs (comma sep.)</th>';
  72.                 }
  73.                 $output .= '         <th>RA</th>';
  74.                 $output .= '         <th>Comment</th>';
  75.                 if ($objParent->userHasWriteRights()) {
  76.                         $output .= '         <th>Hide</th>';
  77.                         $output .= '         <th>Update</th>';
  78.                         $output .= '         <th>Delete</th>';
  79.                 }
  80.                 $output .= '         <th>Created</th>';
  81.                 $output .= '         <th>Updated</th>';
  82.                 $output .= '    </tr>';
  83.  
  84.                 foreach ($rows as list($obj,$row)) {
  85.                         $items_total++;
  86.                         if (!$obj->userHasReadRights()) {
  87.                                 $items_hidden++;
  88.                                 continue;
  89.                         }
  90.  
  91.                         $show_id = $obj->crudShowId($objParent);
  92.  
  93.                         $asn1ids = array();
  94.                         $res2 = OIDplus::db()->query("select name from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = ? order by lfd", array($row->id));
  95.                         while ($row2 = $res2->fetch_array()) {
  96.                                 $asn1ids[] = $row2['name'];
  97.                         }
  98.  
  99.                         $iris = array();
  100.                         $res2 = OIDplus::db()->query("select name from ".OIDPLUS_TABLENAME_PREFIX."iri where oid = ? order by lfd", array($row->id));
  101.                         while ($row2 = $res2->fetch_array()) {
  102.                                 $iris[] = $row2['name'];
  103.                         }
  104.                        
  105.                         $date_created = explode(' ', $row->created)[0] == '0000-00-00' ? '' : explode(' ', $row->created)[0];
  106.                         $date_updated = explode(' ', $row->updated)[0] == '0000-00-00' ? '' : explode(' ', $row->updated)[0];
  107.  
  108.                         $output .= '<tr>';
  109.                         $output .= '     <td><a href="?goto='.urlencode($row->id).'" onclick="openAndSelectNode('.js_escape($row->id).', '.js_escape($parent).'); return false;">'.htmlentities($show_id).'</a></td>';
  110.                         if ($objParent->userHasWriteRights()) {
  111.                                 if ($parentNS == 'oid') {
  112.                                         if ($one_weid_available) {
  113.                                                 if ($obj->isWeid(false)) {
  114.                                                         $output .= '    <td>'.$obj->weidArc().'</td>';
  115.                                                 } else {
  116.                                                         $output .= '    <td>n/a</td>';
  117.                                                 }
  118.                                         }
  119.                                         $output .= '     <td><input type="text" id="asn1ids_'.$row->id.'" value="'.implode(', ', $asn1ids).'"></td>';
  120.                                         $output .= '     <td><input type="text" id="iris_'.$row->id.'" value="'.implode(', ', $iris).'"></td>';
  121.                                 }
  122.                                 $output .= '     <td><input type="text" id="ra_email_'.$row->id.'" value="'.htmlentities($row->ra_email).'"></td>';
  123.                                 $output .= '     <td><input type="text" id="comment_'.$row->id.'" value="'.htmlentities($row->comment).'"></td>';
  124.                                 $output .= '     <td><input type="checkbox" id="hide_'.$row->id.'" '.($row->confidential ? 'checked' : '').'></td>';
  125.                                 $output .= '     <td><button type="button" name="update_'.$row->id.'" id="update_'.$row->id.'" class="btn btn-success btn-xs update" onclick="crudActionUpdate('.js_escape($row->id).', '.js_escape($parent).')">Update</button></td>';
  126.                                 $output .= '     <td><button type="button" name="delete_'.$row->id.'" id="delete_'.$row->id.'" class="btn btn-danger btn-xs delete" onclick="crudActionDelete('.js_escape($row->id).', '.js_escape($parent).')">Delete</button></td>';
  127.                                 $output .= '     <td>'.$date_created.'</td>';
  128.                                 $output .= '     <td>'.$date_updated.'</td>';
  129.                         } else {
  130.                                 if ($asn1ids == '') $asn1ids = '<i>(none)</i>';
  131.                                 if ($iris == '') $iris = '<i>(none)</i>';
  132.                                 if ($parentNS == 'oid') {
  133.                                         if ($one_weid_available) {
  134.                                                 if ($obj->isWeid(false)) {
  135.                                                         $output .= '    <td>'.$obj->weidArc().'</td>';
  136.                                                 } else {
  137.                                                         $output .= '    <td>n/a</td>';
  138.                                                 }
  139.                                         }
  140.                                         $asn1ids_ext = array();
  141.                                         foreach ($asn1ids as $asn1id) {
  142.                                                 $asn1ids_ext[] = '<a href="?goto='.urlencode($row->id).'" onclick="openAndSelectNode('.js_escape($row->id).', '.js_escape($parent).'); return false;">'.$asn1id.'</a>';
  143.                                         }
  144.                                         $output .= '     <td>'.implode(', ', $asn1ids_ext).'</td>';
  145.                                         $output .= '     <td>'.implode(', ', $iris).'</td>';
  146.                                 }
  147.                                 $output .= '     <td><a '.OIDplus::gui()->link('oidplus:rainfo$'.str_replace('@','&',$row->ra_email)).'>'.htmlentities(empty($row->ra_name) ? str_replace('@','&',$row->ra_email) : $row->ra_name).'</a></td>';
  148.                                 $output .= '     <td>'.htmlentities($row->comment).'</td>';
  149.                                 $output .= '     <td>'.$date_created.'</td>';
  150.                                 $output .= '     <td>'.$date_updated.'</td>';
  151.                         }
  152.                         $output .= '</tr>';
  153.                 }
  154.  
  155.                 $result = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($parent));
  156.                 $parent_ra_email = $result->num_rows() > 0 ? $result->fetch_object()->ra_email : '';
  157.  
  158.                 if ($objParent->userHasWriteRights()) {
  159.                         $output .= '<tr>';
  160.                         $prefix = is_null($objParent) ? '' : $objParent->crudInsertPrefix();
  161.                         if ($parentNS == 'oid') {
  162.                                 if ($objParent->isWeid(true)) {
  163.                                         $output .= '     <td>'.$prefix.' <input oninput="frdl_oidid_change()" type="text" id="id" value="" style="width:100%;min-width:100px"></td>'; // TODO: idee classname vergeben, z.B. "OID" und dann mit einem oid-spezifischen css die breite einstellbar machen, somit hat das plugin mehr kontrolle über das aussehen und die mindestbreiten
  164.                                         $output .= '     <td><input type="text" name="weid" id="weid" value="" oninput="frdl_weid_change()"></td>';
  165.                                 } else {
  166.                                         $output .= '     <td>'.$prefix.' <input type="text" id="id" value="" style="width:100%;min-width:50px"></td>'; // TODO: idee classname vergeben, z.B. "OID" und dann mit einem oid-spezifischen css die breite einstellbar machen, somit hat das plugin mehr kontrolle über das aussehen und die mindestbreiten
  167.                                         if ($one_weid_available) $output .= '     <td></td>'; // WEID-editor not available for root nodes. Do it manually, please
  168.                                 }
  169.                         } else {
  170.                                 $output .= '     <td>'.$prefix.' <input type="text" id="id" value=""></td>';
  171.                         }
  172.                         if ($parentNS == 'oid') $output .= '     <td><input type="text" id="asn1ids" value=""></td>';
  173.                         if ($parentNS == 'oid') $output .= '     <td><input type="text" id="iris" value=""></td>';
  174.                         $output .= '     <td><input type="text" id="ra_email" value="'.htmlentities($parent_ra_email).'"></td>';
  175.                         $output .= '     <td><input type="text" id="comment" value=""></td>';
  176.                         $output .= '     <td><input type="checkbox" id="hide"></td>';
  177.                         $output .= '     <td><button type="button" name="insert" id="insert" class="btn btn-success btn-xs update" onclick="crudActionInsert('.js_escape($parent).')">Insert</button></td>';
  178.                         $output .= '     <td></td>';
  179.                         $output .= '     <td></td>';
  180.                         $output .= '     <td></td>';
  181.                         $output .= '</tr>';
  182.                 } else {
  183.                         if ($items_total-$items_hidden == 0) {
  184.                                 $cols = ($parentNS == 'oid') ? 7 : 5;
  185.                                 if ($one_weid_available) $cols++;
  186.                                 $output .= '<tr><td colspan="'.$cols.'">No items available</td></tr>';
  187.                         }
  188.                 }
  189.  
  190.                 $output .= '</table>';
  191.                 $output .= '</div></div>';
  192.  
  193.                 if ($items_hidden == 1) {
  194.                         $output .= '<p>'.$items_hidden.' item is hidden. Please <a '.OIDplus::gui()->link('oidplus:login').'>log in</a> to see it.</p>';
  195.                 } else if ($items_hidden > 1) {
  196.                         $output .= '<p>'.$items_hidden.' items are hidden. Please <a '.OIDplus::gui()->link('oidplus:login').'>log in</a> to see them.</p>';
  197.                 }
  198.  
  199.                 return $output;
  200.         }
  201.  
  202.         // 'quickbars' added 11 July 2019: Disabled because of two problems:
  203.         //                                 1. When you load TinyMCE via AJAX using the left menu, the quickbar is immediately shown, even if TinyMCE does not have the focus
  204.         //                                 2. When you load a page without TinyMCE using the left menu, the quickbar is still visible, although there is no edit
  205.         // 'colorpicker', 'textcolor' and 'contextmenu' added in 07 April 2020, because it is built in in the core.
  206.         public static $exclude_tinymce_plugins = array('fullpage', 'bbcode', 'quickbars', 'colorpicker', 'textcolor', 'contextmenu');
  207.  
  208.         protected static function showMCE($name, $content) {
  209.                 $mce_plugins = array();
  210.                 foreach (glob(__DIR__ . '/../../3p/tinymce/plugins/*') as $m) { // */
  211.                         $mce_plugins[] = basename($m);
  212.                 }
  213.  
  214.                 foreach (self::$exclude_tinymce_plugins as $exclude) {
  215.                         $index = array_search($exclude, $mce_plugins);
  216.                         if ($index !== false) unset($mce_plugins[$index]);
  217.                 }
  218.  
  219.                 $out = '<script>
  220.                                 tinymce.remove("#'.$name.'");
  221.                                 tinymce.EditorManager.baseURL = "3p/tinymce";
  222.                                 tinymce.init({
  223.                                         document_base_url: "'.OIDplus::getSystemUrl().'",
  224.                                         selector: "#'.$name.'",
  225.                                         height: 200,
  226.                                         statusbar: false,
  227. //                                      menubar:false,
  228. //                                      toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table | fontsizeselect",
  229.                                         toolbar: "undo redo | styleselect | bold italic underline forecolor | bullist numlist | outdent indent | table | fontsizeselect",
  230.                                         plugins: "'.implode(' ', $mce_plugins).'",
  231.                                         mobile: {
  232.                                                 theme: "mobile",
  233.                                                 toolbar: "undo redo | styleselect | bold italic underline forecolor | bullist numlist | outdent indent | table | fontsizeselect",
  234.                                                 plugins: "'.implode(' ', $mce_plugins).'"
  235.                                         }
  236.  
  237.                                 });
  238.                         </script>';
  239.  
  240.                 $content = htmlentities($content); // For some reason, if we want to display the text "<xyz>" in TinyMCE, we need to double-encode things! &lt; will not be accepted, we need &amp;lt; ... why?
  241.  
  242.                 $out .= '<textarea name="'.htmlentities($name).'" id="'.htmlentities($name).'">'.trim($content).'</textarea><br>';
  243.  
  244.                 return $out;
  245.         }
  246.  
  247.         public static function generateContentPage($id) {
  248.                 $out = array();
  249.  
  250.                 $handled = false;
  251.                 $out['title'] = '';
  252.                 $out['icon'] = '';
  253.                 $out['text'] = '';
  254.  
  255.                 // === Plugins ===
  256.  
  257.                 foreach (OIDplus::getPagePlugins('*') as $plugin) {
  258.                         $plugin->gui($id, $out, $handled);
  259.                 }
  260.  
  261.                 // === Everything else (objects) ===
  262.  
  263.                 if (!$handled) {
  264.                         try {
  265.                                 $obj = OIDplusObject::parse($id);
  266.                         } catch (Exception $e) {
  267.                                 $out['title'] = 'Error';
  268.                                 $out['icon'] = 'img/error_big.png';
  269.                                 $out['text'] = htmlentities($e->getMessage());
  270.                                 return $out;
  271.                         }
  272.  
  273.                         if ((!is_null($obj)) && (!$obj->userHasReadRights())) {
  274.                                 $out['title'] = 'Access denied';
  275.                                 $out['icon'] = 'img/error_big.png';
  276.                                 $out['text'] = '<p>Please <a '.OIDplus::gui()->link('oidplus:login').'>log in</a> to receive information about this object.</p>';
  277.                                 return $out;
  278.                         }
  279.  
  280.                         // ---
  281.  
  282.                         $parent = null;
  283.                         $res = null;
  284.                         $row = null;
  285.                         $matches_any_registered_type = false;
  286.                         foreach (OIDplus::getEnabledObjectTypes() as $ot) {
  287.                                 if ($obj = $ot::parse($id)) {
  288.                                         $matches_any_registered_type = true;
  289.                                         if ($obj->isRoot()) {
  290.                                                 $obj->getContentPage($out['title'], $out['text'], $out['icon']);
  291.                                                 $parent = null; // $obj->getParent();
  292.                                                 break;
  293.                                         } else {
  294.                                                 $res = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($obj->nodeId()));
  295.                                                 $row = $res->fetch_array();
  296.                                                 if ($res->num_rows() == 0) {
  297.                                                         http_response_code(404);
  298.                                                         $out['title'] = 'Object not found';
  299.                                                         $out['icon'] = 'img/error_big.png';
  300.                                                         $out['text'] = 'The object <code>'.htmlentities($id).'</code> was not found in this database.';
  301.                                                         return $out;
  302.                                                 } else {
  303.                                                         $obj->getContentPage($out['title'], $out['text'], $out['icon']);
  304.                                                         if (empty($out['title'])) $out['title'] = explode(':',$id,2)[1];
  305.                                                         $parent = $obj->getParent();
  306.                                                         break;
  307.                                                 }
  308.                                         }
  309.                                 }
  310.                         }
  311.                         if (!$matches_any_registered_type) {
  312.                                 http_response_code(404);
  313.                                 $out['title'] = 'Object not found';
  314.                                 $out['icon'] = 'img/error_big.png';
  315.                                 $out['text'] = 'The object <code>'.htmlentities($id).'</code> was not found in this database.';
  316.                                 return $out;
  317.                         }
  318.  
  319.                         // ---
  320.  
  321.                         if ($parent) {
  322.                                 if ($parent->isRoot()) {
  323.  
  324.                                         $parent_link_text = $parent->objectTypeTitle();
  325.                                         $out['text'] = '<p><a '.OIDplus::gui()->link($parent->root()).'><img src="img/arrow_back.png" width="16"> Parent node: '.htmlentities($parent_link_text).'</a></p>' . $out['text'];
  326.  
  327.                                 } else {
  328.                                         $res_ = OIDplus::db()->query("select * from ".OIDPLUS_TABLENAME_PREFIX."objects where id = ?", array($parent->nodeId()));
  329.                                         $row_ = $res_->fetch_array();
  330.  
  331.                                         $parent_title = $row_['title'];
  332.                                         if (empty($parent_title) && ($parent->ns() == 'oid')) {
  333.                                                 $res_ = OIDplus::db()->query("select name from ".OIDPLUS_TABLENAME_PREFIX."asn1id where oid = ?", array($parent->nodeId()));
  334.                                                 $row_ = $res_->fetch_array();
  335.                                                 $parent_title = $row_['name']; // TODO: multiple ASN1 ids?
  336.                                         }
  337.  
  338.                                         $parent_link_text = empty($parent_title) ? explode(':',$parent->nodeId())[1] : $parent_title.' ('.explode(':',$parent->nodeId())[1].')';
  339.  
  340.                                         $out['text'] = '<p><a '.OIDplus::gui()->link($parent->nodeId()).'><img src="img/arrow_back.png" width="16"> Parent node: '.htmlentities($parent_link_text).'</a></p>' . $out['text'];
  341.                                 }
  342.                         } else {
  343.                                 $parent_link_text = 'Go back to front page';
  344.                                 $out['text'] = '<p><a '.OIDplus::gui()->link('oidplus:system').'><img src="img/arrow_back.png" width="16"> '.htmlentities($parent_link_text).'</a></p>' . $out['text'];
  345.                         }
  346.  
  347.                         // ---
  348.  
  349.                         if (!is_null($row) && isset($row['description'])) {
  350.                                 if (empty($row['description'])) {
  351.                                         if (empty($row['title'])) {
  352.                                                 $desc = '<p><i>No description for this object available</i></p>';
  353.                                         } else {
  354.                                                 $desc = $row['title'];
  355.                                         }
  356.                                 } else {
  357.                                         $desc = OIDplusGui::objDescription($row['description']);
  358.                                 }
  359.  
  360.                                 if ($obj->userHasWriteRights()) {
  361.                                         $rand = ++self::$crudCounter;
  362.                                         $desc = '<noscript><p><b>You need to enable JavaScript to edit title or description of this object.</b></p>'.$desc.'</noscript>';
  363.                                         $desc .= '<div class="container box" style="display:none" id="descbox_'.$rand.'">';
  364.                                         $desc .= 'Title: <input type="text" name="title" id="titleedit" value="'.htmlentities($row['title']).'"><br><br>Description:<br>';
  365.                                         $desc .= self::showMCE('description', $row['description']);
  366.                                         $desc .= '<button type="button" name="update_desc" id="update_desc" class="btn btn-success btn-xs update" onclick="updateDesc()">Update description</button>';
  367.                                         $desc .= '</div>';
  368.                                         $desc .= '<script>document.getElementById("descbox_'.$rand.'").style.display = "block";</script>';
  369.                                 }
  370.                         } else {
  371.                                 $desc = '';
  372.                         }
  373.  
  374.                         // ---
  375.  
  376.                         if (strpos($out['text'], '%%DESC%%') !== false)
  377.                                 $out['text'] = str_replace('%%DESC%%',    $desc,                              $out['text']);
  378.                         if (strpos($out['text'], '%%CRUD%%') !== false)
  379.                                 $out['text'] = str_replace('%%CRUD%%',    self::showCrud($id),                $out['text']);
  380.                         if (strpos($out['text'], '%%RA_INFO%%') !== false)
  381.                                 $out['text'] = str_replace('%%RA_INFO%%', OIDplusPagePublicRaInfo::showRaInfo($row['ra_email']), $out['text']);
  382.  
  383.                         $alt_ids = $obj->getAltIds();
  384.                         if (count($alt_ids) > 0) {
  385.                                 $out['text'] .= "<h2>Alternative Identifiers</h2>";
  386.                                 foreach ($alt_ids as $alt_id) {
  387.                                         $ns = $alt_id->getNamespace();
  388.                                         $aid = $alt_id->getId();
  389.                                         $aiddesc = $alt_id->getDescription();
  390.                                         $out['text'] .= "$aiddesc <code>$ns:$aid</code><br>";
  391.                                 }
  392.                         }
  393.  
  394.                         foreach (OIDplus::getPagePlugins('public') as $plugin) $plugin->modifyContent($id, $out['title'], $out['icon'], $out['text']);
  395.                         foreach (OIDplus::getPagePlugins('ra')     as $plugin) $plugin->modifyContent($id, $out['title'], $out['icon'], $out['text']);
  396.                         foreach (OIDplus::getPagePlugins('admin')  as $plugin) $plugin->modifyContent($id, $out['title'], $out['icon'], $out['text']);
  397.                 } else {
  398.                         // Other pages (search, whois, etc.)
  399.                         /*
  400.                         if ($id != 'oidplus:system') {
  401.                                 $parent_link_text = 'Go back to front page';
  402.                                 $out['text'] = '<p><a '.OIDplus::gui()->link('oidplus:system').'><img src="img/arrow_back.png" width="16"> '.htmlentities($parent_link_text).'</a></p>' . $out['text'];
  403.                         }
  404.                         */
  405.                 }
  406.  
  407.                 return $out;
  408.         }
  409.  
  410.         public static function link($goto) {
  411.                 if (strpos($goto, '#') !== false) {
  412.                         list($goto, $anchor) = explode('#', $goto, 2);
  413.                         return 'href="?goto='.urlencode($goto).'#'.htmlentities($anchor).'" onclick="openOidInPanel('.js_escape($goto).', true, '.js_escape($anchor).'); return false;"';
  414.                 } else {
  415.                         return 'href="?goto='.urlencode($goto).'" onclick="openOidInPanel('.js_escape($goto).', true); return false;"';
  416.                 }
  417.         }
  418. }
  419.