OSDN Git Service

BugTrack/2484 AutoTicketLink for JIRA
authorumorigu <umorigu@gmail.com>
Fri, 11 Jan 2019 15:49:49 +0000 (00:49 +0900)
committerumorigu <umorigu@gmail.com>
Fri, 11 Jan 2019 15:49:49 +0000 (00:49 +0900)
lib/func.php
lib/html.php
lib/make_link.php
plugin/edit.inc.php
pukiwiki.ini.php
skin/main.js

index 41bcd81..4650529 100644 (file)
@@ -2,7 +2,7 @@
 // PukiWiki - Yet another WikiWikiWeb clone.
 // func.php
 // Copyright
-//   2002-2018 PukiWiki Development Team
+//   2002-2019 PukiWiki Development Team
 //   2001-2002 Originally written by yu-ji
 // License: GPL v2 or (at your option) any later version
 //
@@ -1048,6 +1048,21 @@ function htmlsc($string = '', $flags = ENT_COMPAT, $charset = CONTENT_CHARSET)
 }
 
 /**
+ * Get JSON string with htmlspecialchars().
+ */
+function htmlsc_json($obj)
+{
+       // json_encode: PHP 5.2+
+       // JSON_UNESCAPED_UNICODE: PHP 5.4+
+       // JSON_UNESCAPED_SLASHES: PHP 5.4+
+       if (defined('JSON_UNESCAPED_UNICODE')) {
+               return htmlsc(json_encode($obj,
+                       JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
+       }
+       return '';
+}
+
+/**
  * Get redirect page name on Page Redirect Rules
  *
  * This function returns exactly false if it doesn't need redirection.
index 438aef2..c91a58e 100644 (file)
@@ -226,6 +226,7 @@ function get_html_scripting_data($page, $in_editing)
        global $ticket_link_sites, $plugin;
        global $external_link_cushion_page, $external_link_cushion;
        global $topicpath_title;
+       global $ticket_jira_default_site;
        if (!isset($ticket_link_sites) || !is_array($ticket_link_sites)) {
                return '';
        }
@@ -277,6 +278,22 @@ EOS;
        $ticketlink_data = <<<EOS
 <input type="hidden" class="ticketlink-def" value="$h_ticket_link_sites" />
 EOS;
+       // AutoTicketLink - JIRA
+       $ticket_jira_projects = get_ticketlink_jira_projects();
+       $ticketlink_jira_data = '';
+       if (count($ticket_jira_projects) > 0) {
+               $h_ticket_jira_projects = htmlsc_json($ticket_jira_projects);
+               $ticketlink_jira_data = <<<EOS
+<input type="hidden" class="ticketlink-jira-def" value="$h_ticket_jira_projects" />
+EOS;
+       }
+       $ticketlink_jira_default_data = '';
+       if (isset($ticket_jira_default_site) && is_array($ticket_jira_default_site)) {
+               $h_ticket_jira_default_site = htmlsc_json($ticket_jira_default_site);
+               $ticketlink_jira_default_data = <<<EOS
+<input type="hidden" class="ticketlink-jira-default-def" value="$h_ticket_jira_default_site" />
+EOS;
+       }
        // External link cushion page
        $external_link_cushion_data = '';
        if ($external_link_cushion_page) {
@@ -303,6 +320,8 @@ $plugin_prop
 $page_name_data
 $page_edit_data
 $ticketlink_data
+$ticketlink_jira_data
+$ticketlink_jira_default_data
 $external_link_cushion_data
 $topicpath_data
 </div>
index d338c52..4566ded 100644 (file)
@@ -2,7 +2,7 @@
 // PukiWiki - Yet another WikiWikiWeb clone.
 // make_link.php
 // Copyright
-//   2003-2018 PukiWiki Development Team
+//   2003-2019 PukiWiki Development Team
 //   2001-2002 Originally written by yu-ji
 // License: GPL v2 or (at your option) any later version
 //
@@ -927,3 +927,68 @@ function get_interwiki_url($name, $param)
 
        return $url;
 }
+
+function get_autoticketlink_def_page()
+{
+       return 'AutoTicketLinkName';
+}
+
+/**
+ * Get AutoTicketLink - JIRA projects from AutoTiketLinkName page
+ */
+function get_ticketlink_jira_projects()
+{
+       $autoticketlink_def_page = get_autoticketlink_def_page();
+       $active_jira_base_url = null;
+       $jira_projects = array();
+       foreach (get_source($autoticketlink_def_page) as $line) {
+               if (substr($line, 0, 1) !== '-') {
+                       $active_jira_base_url = null;
+                       continue;
+               }
+               $m = null;
+               if (preg_match('/^-\s*(jira)\s+(https?:\/\/[!~*\'();\/?:\@&=+\$,%#\w.-]+)\s*$/', $line, $m)) {
+                       $active_jira_base_url = $m[2];
+               } else if (preg_match('/^--\s*([A-Z][A-Z0-9]+)(\s+(.+?))?\s*$/', $line, $m)) {
+                       if ($active_jira_base_url) {
+                               $project_key = $m[1];
+                               $title = $m[2];
+                               array_push($jira_projects, array(
+                                       'key' => $m[1],
+                                       'title' => $title,
+                                       'base_url' => $active_jira_base_url,
+                               ));
+                       }
+               } else {
+                       $active_jira_base_url = null;
+               }
+       }
+       return $jira_projects;
+}
+
+function init_autoticketlink_def_page()
+{
+       $autoticketlink_def_page = get_autoticketlink_def_page();
+       if (is_page($autoticketlink_def_page)) {
+               return;
+       }
+       $body = <<<'EOS'
+#freeze
+* AutoTicketLink definition [#def]
+
+Reference: https://pukiwiki.osdn.jp/?AutoTicketLink
+
+ - jira https://site1.example.com/jira/browse/
+ -- AAA Project title $1
+ -- BBB Project title $1
+ - jira https://site2.example.com/jira/browse/
+ -- PROJECTA Site2 $1
+
+ (Default definition) pukiwiki.ini.php
+ $ticket_jira_default_site = array(
+   'title' => 'My JIRA - $1',
+   'base_url' => 'https://issues.example.com/jira/browse/',
+ );
+EOS;
+       page_write($autoticketlink_def_page, $body);
+}
index e1dcdb5..1ebfb79 100644 (file)
@@ -1,7 +1,7 @@
 <?php
 // PukiWiki - Yet another WikiWikiWeb clone.
 // edit.inc.php
-// Copyright 2001-2018 PukiWiki Development Team
+// Copyright 2001-2019 PukiWiki Development Team
 // License: GPL v2 or (at your option) any later version
 //
 // Edit plugin (cmd=edit)
@@ -279,4 +279,6 @@ function plugin_edit_setup_initial_pages()
        if (exist_plugin('rename') && function_exists('plugin_rename_setup_initial_pages')) {
                plugin_rename_setup_initial_pages();
        }
+       // AutoTicketLinkName page
+       init_autoticketlink_def_page();
 }
index 2526515..9dda985 100644 (file)
@@ -2,7 +2,7 @@
 // PukiWiki - Yet another WikiWikiWeb clone
 // pukiwiki.ini.php
 // Copyright
-//   2002-2016 PukiWiki Development Team
+//   2002-2019 PukiWiki Development Team
 //   2001-2002 Originally written by yu-ji
 // License: GPL v2 or (at your option) any later version
 //
@@ -314,6 +314,13 @@ $ticket_link_sites = array(
        ),
 */
 );
+// AutoTicketLink - JIRA Default site
+/*
+$ticket_jira_default_site = array(
+       'title' => 'My JIRA - $1',
+       'base_url' => 'https://issues.example.com/jira/browse/',
+);
+//*/
 
 /////////////////////////////////////////////////
 // Show External Link Cushion Page
index da31bf0..2da085e 100644 (file)
@@ -1,6 +1,6 @@
 // PukiWiki - Yet another WikiWikiWeb clone.
 // main.js
-// Copyright 2017 PukiWiki Development Team
+// Copyright 2017-2019 PukiWiki Development Team
 // License: GPL v2 or (at your option) any later version
 //
 // PukiWiki JavaScript client script
@@ -106,11 +106,13 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function(
   }
   // AutoTicketLink
   function autoTicketLink() {
-    var headReText = '([\\s\\b]|^)';
+    var headReText = '([\\s\\b:\\[]|^)';
     var tailReText = '\\b';
     var ignoreTags = ['A', 'INPUT', 'TEXTAREA', 'BUTTON',
       'SCRIPT', 'FRAME', 'IFRAME'];
     var ticketSiteList = [];
+    var jiraProjects = null;
+    var jiraDefaultInfo = null;
     function regexEscape(key) {
       return key.replace(/[-.]/g, function (m) {
         return '\\' + m;
@@ -137,6 +139,17 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function(
         site.re = new RegExp(headReText + reText + tailReText);
       }
     }
+    function getJiraSite() {
+      var reText = '()([A-Z][A-Z0-9]{1,20}-\\d{1,10})';
+      var site = {
+        title: 'Builtin JIRA',
+        type: '_jira_',
+        key: '_jira_',
+        reText: reText,
+        re: new RegExp(headReText + reText + tailReText)
+      };
+      return site;
+    }
     function getSiteListFromBody() {
       var defRoot = document.querySelector('#pukiwiki-site-properties .ticketlink-def');
       if (defRoot && defRoot.value) {
@@ -146,22 +159,86 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function(
       }
       return [];
     }
+    function getJiraProjectsFromBody() {
+      var defRoot = document.querySelector('#pukiwiki-site-properties .ticketlink-jira-def');
+      if (defRoot && defRoot.value) {
+        try {
+          return JSON.parse(defRoot.value); // List
+        } catch (e) {
+          return null;
+        }
+      }
+      return null;
+    }
+    function getJiraDefaultInfoFromBody() {
+      var defRoot = document.querySelector('#pukiwiki-site-properties .ticketlink-jira-default-def');
+      if (defRoot && defRoot.value) {
+        try {
+          return JSON.parse(defRoot.value); // object
+        } catch (e) {
+          return null;
+        }
+      }
+      return null;
+    }
     function getSiteList() {
       return ticketSiteList;
     }
+    function getJiraProjectList() {
+      return jiraProjects;
+    }
+    function getDefaultJira() {
+      return jiraDefaultInfo;
+    }
     function ticketToLink(keyText) {
       var siteList = getSiteList();
       for (var i = 0; i < siteList.length; i++) {
         var site = siteList[i];
         var m = keyText.match(site.re);
         if (m) {
-          var title = site.title;
           var ticketKey = m[3];
-          if (title) {
-            title = title.replace(/\$1/g, ticketKey);
+          var title = ticketKey;
+          var ticketUrl;
+          if (site.type === '_jira_') {
+            // JIRA issue
+            var projects = getJiraProjectList();
+            var hyphen = keyText.indexOf('-');
+            if (hyphen > 0) {
+              var projectKey = keyText.substr(0, hyphen);
+              if (projects) {
+                for (var j = 0; j < projects.length; j++) {
+                  var p = projects[j];
+                  if (p.key === projectKey) {
+                    if (p.title) {
+                      title = p.title.replace(/\$1/g, ticketKey);
+                    }
+                    ticketUrl = p.base_url + ticketKey;
+                    break;
+                  }
+                }
+              }
+              if (!ticketUrl) {
+                var defaultJira = getDefaultJira();
+                if (defaultJira) {
+                  if (defaultJira.title) {
+                    title = defaultJira.title.replace(/\$1/g, ticketKey);
+                  }
+                  ticketUrl = defaultJira.base_url + ticketKey;
+                }
+              }
+            }
+            if (!ticketUrl) {
+              return null;
+            }
+          } else {
+            // Explicit TicketLink
+            if (site.title) {
+              title = site.title.replace(/\$1/g, ticketKey);
+            }
+            ticketUrl = site.base_url + ticketKey;
           }
           return {
-            url: site.base_url + m[3],
+            url: ticketUrl,
             title: title
           };
         }
@@ -195,12 +272,17 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function(
         if (m.index > 0 || m[1].length > 0) {
           f.appendChild(document.createTextNode(text.substr(0, m.index) + m[1]));
         }
-        var a = document.createElement('a');
-        a.textContent = m[2];
-        var linkInfo = ticketToLink(a.textContent);
-        a.href = linkInfo.url;
-        a.title = linkInfo.title;
-        f.appendChild(a);
+        var linkKey = m[2];
+        var linkInfo = ticketToLink(linkKey);
+        if (linkInfo) {
+          var a = document.createElement('a');
+          a.textContent = linkKey;
+          a.href = linkInfo.url;
+          a.title = linkInfo.title;
+          f.appendChild(a);
+        } else {
+          f.appendChild(document.createTextNode(m[2]));
+        }
         text = text.substr(m.index + m[0].length);
       }
       if (f) {
@@ -230,6 +312,11 @@ window.addEventListener && window.addEventListener('DOMContentLoaded', function(
       return;
     }
     ticketSiteList = getSiteListFromBody();
+    jiraProjects = getJiraProjectsFromBody();
+    jiraDefaultInfo = getJiraDefaultInfoFromBody();
+    if (jiraDefaultInfo || (jiraProjects && jiraProjects.length > 0)) {
+      ticketSiteList.push(getJiraSite());
+    }
     var target = document.getElementById('body');
     walkElement(target);
   }