changeset 20:3bb3d9a9f1b7

Filter by keywords and states. Configuration via configuration file. "No prio" grapf is displayed. (./display_issues_demo.py is not yet dynamic, it needs all states)
author Magnus Schieder <mschieder@intevation.de>
date Mon, 22 Oct 2018 16:49:58 +0200
parents 8ffd584065a4
children 7a523e13fcb3
files README.creole collect_issues.py display_issues.py display_issues_demo.py examples/collect_demo3.py examples/config3.ini graph.html roundup_content_data/__init__.py
diffstat 8 files changed, 163 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/README.creole	Mon Jul 09 14:49:44 2018 +0200
+++ b/README.creole	Mon Oct 22 16:49:58 2018 +0200
@@ -8,16 +8,18 @@
 Run ./demo.py from a roundup-tracker to have a running tracker.
 
 {{{
-cp  examples/collect_demo1.py c1.py
-./c1.py
+cp examples/collect_demo3.py c3.py
+cp examples/config3.ini .
+# change config3.ini
+./c3.py
 # create or change some issues
-./c1.py
+./c3.py
 
 # to inspect the database contents
-sqlite3 demo1.db 'select * from issues;'
+sqlite3 demo3.db 'select * from issues;'
 
-./display_issues_demo.py >demo1.html
-chromium demo1.html
+./display_issues_demo.py >demo3.html
+chromium demo3.html
 }}}
 
 
--- a/collect_issues.py	Mon Jul 09 14:49:44 2018 +0200
+++ b/collect_issues.py	Mon Oct 22 16:49:58 2018 +0200
@@ -24,8 +24,9 @@
 
 
 CHECK_ROUNDUP_ORDER = "priority?@action=export_csv&@columns=id,order"
-CHECK_ROUNDUP_SEARCH_VALUES = "status?@action=export_csv&@columns=id&@filter=open&open=1"
-SEARCH_ROUNDUP = "issue?@action=export_csv&@columns=priority&@filter=status&@pagesize=500&@startwith=0&status=-1,{search_values}"
+CHECK_KEYWORD_ORDER = "keyword?@action=export_csv&@columns=id,name"
+CHECK_ROUNDUP_SEARCH_VALUES = "status?@action=export_csv&@columns=id,name&@filter=open&open=1"
+SEARCH_ROUNDUP = "issue?@action=export_csv&@columns=priority&@filter=status,keyword&@pagesize=500&@startwith=0&status={search_values}&keyword={keyword_values}"
 
 
 def connect_to_server(params, baseurl):
@@ -44,18 +45,6 @@
     return csv_reader
 
 
-def set_search_paramters_on_URL(url, search_param_csv):
-
-    id_list = []
-
-    for row in search_param_csv:
-        id_list.append(row["id"])
-
-    new_url = url.format(search_values = ",".join(id_list))
-
-    return new_url
-
-
 def check_create_database(database_file, sql_create_db):
     if not os.path.isfile(database_file):
         con = None
@@ -76,6 +65,38 @@
             if con:
                 con.close()
 
+def get_keyword_ids(opener, baseurl, keywords):
+    if keywords == [""]:
+        return ""
+
+    keywords_csv = get_csv_from_server(opener, baseurl, CHECK_KEYWORD_ORDER)
+    keywords_dict = {}
+    for x in keywords_csv:
+       keywords_dict[x["name"]] = x["id"]
+
+    keywords_ids = []
+    for x in keywords:
+        keywords_ids.append(keywords_dict[x])
+
+    return ",".join(keywords_ids)
+
+def get_status_ids(opener, baseurl, status):
+
+    status_csv = get_csv_from_server(opener, baseurl, CHECK_ROUNDUP_SEARCH_VALUES)
+
+    if status == [""]:
+        return ""
+
+    status_dict = {}
+    for x in status_csv:
+        status_dict[x["name"]] = x["id"]
+
+    staus_ids = ["-1"]
+    for x in status:
+        staus_ids.append(status_dict[x])
+
+    return ",".join(staus_ids)
+
 
 def issues_to_quantities(issue_csv, columns, orders_csv):
     """Count issues per priority.
@@ -126,18 +147,17 @@
             con.close()
 
 
-def save_stats_in_db(login_parmeters, baseurl, db_file, columns, sql_create_db, sql_insert_in_db, searchurl=False, include_no_prio=False):
+def save_stats_in_db(login_parmeters, baseurl, db_file, columns, sql_create_db, sql_insert_in_db, keywords, status, include_no_prio=False):
     try:
 
         opener = connect_to_server(login_parmeters, baseurl)
 
-        search_operators_csv = get_csv_from_server(opener, baseurl, CHECK_ROUNDUP_SEARCH_VALUES)
         order_csv = get_csv_from_server(opener, baseurl, CHECK_ROUNDUP_ORDER)
 
-        if searchurl == False:
-            formated_search_url = set_search_paramters_on_URL(SEARCH_ROUNDUP, search_operators_csv)
-        else:
-            formated_search_url = searchurl
+        keywords_ids_url = get_keyword_ids(opener, baseurl, keywords)
+
+        status_ids_url =  get_status_ids(opener, baseurl, status)
+        formated_search_url = SEARCH_ROUNDUP.format(search_values=status_ids_url, keyword_values=keywords_ids_url)
 
         current_issues_csv = get_csv_from_server(opener, baseurl, formated_search_url)
 
--- a/display_issues.py	Mon Jul 09 14:49:44 2018 +0200
+++ b/display_issues.py	Mon Oct 22 16:49:58 2018 +0200
@@ -40,7 +40,7 @@
 
     return ", ".join(formated)
 
-def get_webpage(graph=None):
+def get_webpage(status, keywords, graph=None):
 
     if graph is None:
         graph = os.path.dirname(os.path.realpath(__file__)) + '/graph.html'
@@ -48,17 +48,21 @@
     with open(graph, "r") as html_chart_file:
         base_html_data = html_chart_file.read()
 
+
     base_html_data = (base_html_data
+        .replace("status", status)
+        .replace("keywords", keywords)
         .replace("var critical=[];", "var critical=[" + make_js_object_string(rcd.data_dict["critical"]) + "]")
         .replace("var urgent=[];", "var urgent=[" + make_js_object_string(rcd.data_dict["urgent"]) + "]")
         .replace("var bug=[];", "var bug=[" + make_js_object_string(rcd.data_dict["bug"]) + "]")
         .replace("var feature=[];", "var feature=[" + make_js_object_string(rcd.data_dict["feature"]) + "]")
         .replace("var wish=[];", "var wish=[" + make_js_object_string(rcd.data_dict["wish"]) + "]")
+        .replace("var noPrio=[];", "var noPrio=[" + make_js_object_string(rcd.data_dict["noPrio"]) + "]")
         .replace("var timestamp=[];", "var timestamp=[" + make_js_object_date(rcd.data_dict["date"]) + "]"))
 
     return base_html_data
 
-def compile_db_stats_html(db_file, sql_select, graph=None):
+def compile_db_stats_html(db_file, sql_select, status="", keywords="", graph=None):
 
     con = None
     cur = None
@@ -75,20 +79,21 @@
             rcd.data_dict["bug"].append(row[3])
             rcd.data_dict["feature"].append(row[4])
             rcd.data_dict["wish"].append(row[5])
+            rcd.data_dict["noPrio"].append(row[6])
     finally:
         if cur:
             cur.close()
         if con:
             con.close()
 
-    return get_webpage(graph)
+    return get_webpage(status, keywords, graph)
 
 def render_webpage(content):
     for line in content.split("\n"):
         print(line)
 
-def render_db_stats_as_html(db_file, sql_select):
-    render_webpage(compile_db_stats_html(db_file, sql_select))
+def render_db_stats_as_html(db_file, sql_select, status="", keywords=""):
+    render_webpage(compile_db_stats_html(db_file, sql_select, status, keywords))
 
 if __name__ == '__main__':
     cgitb.enable()
@@ -96,4 +101,4 @@
     #print("Content-Type: text/html")
     #print()
 
-    render_db_stats_as_html("./demo1.db", rcd.SELECT_ALL)
+    render_db_stats_as_html("./demo3.db", rcd.SELECT_ALL)
--- a/display_issues_demo.py	Mon Jul 09 14:49:44 2018 +0200
+++ b/display_issues_demo.py	Mon Oct 22 16:49:58 2018 +0200
@@ -12,10 +12,21 @@
 GNU GENERAL PUBLIC LICENSE Version 3 or later.
 See http://www.gnu.org/licenses/gpl-3.0.txt for details
 """
+import configparser
+from display_issues import *
 
-from display_issues import *
+config = configparser.ConfigParser()
+config.read('config3.ini')
+
+keywords = config.get("SEARCH", "Keywords", fallback="")
+status = config.get("SEARCH", "Status", fallback="")
+columns = config.get("SEARCH", "Columns", fallback="critical, urgent, bug, feature, wish")
+noPrio = config.get("SEARCH", "IncludeNoPrio", fallback=False)
+if noPrio:
+    columns += ", None"
 
 cgitb.enable() # (optional) HTML traceback to browser
 #render_db_stats_as_html("./demo1.db", rcd.SELECT_ALL)
-render_db_stats_as_html("./demo1.db",
-        rcd.SELECT_WHERE.format("timestamp > date('now', '-2 month')"))
+render_db_stats_as_html("./demo3.db",
+        rcd.build_sql_select(columns).format("timestamp > date('now', '-2 month')"),
+        status, keywords)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/collect_demo3.py	Mon Oct 22 16:49:58 2018 +0200
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+"""Connect to roundup-tracker and save status to db for example demo1.
+
+Run periodically as often as you want data points to be saved.
+demo1 only tracks issues with a priority.
+"""
+
+import json
+import configparser
+from collect_issues import save_stats_in_db
+import roundup_content_data as rcd
+
+COLUMNS = "critical, urgent, bug, feature, wish"
+
+config = configparser.ConfigParser()
+config.read('config3.ini')
+
+base_url = config.get("URL", "BaseURL")
+
+user = config.get("LOGIN","Username")
+password = config.get("LOGIN", "Password")
+
+LOGIN_PARAMETERS_DEMO = (
+    ("__login_name", user),
+    ("__login_password", password),
+    ("@action", "Login"),
+    )
+
+database_file = config.get("DB", "DatabaseFile")
+
+keywords = config.get("SEARCH", "Keywords", fallback="").split(", ")
+
+list_of_columns = config.get("SEARCH", "Columns", fallback=COLUMNS).split(", ")
+
+status = config.get("SEARCH", "Status", fallback="").split(", ")
+
+include_no_prio = config.getboolean("SEARCH", "IncludeNoPrio", fallback= False)
+
+if include_no_prio:
+    list_of_columns += ["None"]
+
+select_all, select_where, create_db, insert_new = \
+    rcd.build_sql_commands(list_of_columns)
+
+save_stats_in_db(LOGIN_PARAMETERS_DEMO, base_url, database_file,
+                list_of_columns, create_db, insert_new, keywords, status)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/config3.ini	Mon Oct 22 16:49:58 2018 +0200
@@ -0,0 +1,15 @@
+[URL]
+BaseURL = http://localhost:8917/demo/
+
+[LOGIN]
+Username = demo
+Password = demo
+
+[DB]
+DatabaseFile = ./demo3.db
+
+[SEARCH]
+Keywords = keywords1, keyword2, keyword3
+Columns = critical, urgent, bug, feature, wish
+Status = unread, deferred, chatting, need-eg, in-progress, testing, done-cbb, resolved
+IncludeNoPrio = True
--- a/graph.html	Mon Jul 09 14:49:44 2018 +0200
+++ b/graph.html	Mon Oct 22 16:49:58 2018 +0200
@@ -74,6 +74,14 @@
 					fill: blue;
 			}
 
+			.line.noprio {
+					stroke: grey;
+			}
+
+			.line.noprio.legend {
+					fill: grey;
+			}
+
 			.grid .tick {
 					stroke: lightgrey;
 					opacity: 0.7;
@@ -86,6 +94,9 @@
 		</style>
 	</head>
 	<body>
+	 	<h1>Filter</h1>
+		<p>States:  status</p>
+		<p>Keywords: keywords</p>
 		<div id="content" style="display: inline-block"></div>
 		<script type="text/javascript" src="d3.v3.min.js"></script>
 		<script type="text/javascript">
@@ -100,6 +111,7 @@
 			var bug=[];
 			var feature=[];
 			var wish=[];
+			var noPrio=[];
 			var timestamp=[];
 
 
@@ -139,6 +151,7 @@
 				maxIssuesOfAllArrays.push(maxInObject(bug));
 				maxIssuesOfAllArrays.push(maxInObject(feature));
 				maxIssuesOfAllArrays.push(maxInObject(wish));
+				maxIssuesOfAllArrays.push(maxInObject(noPrio));
 
 				return Math.max.apply(Math, maxIssuesOfAllArrays)+1;
 			}
@@ -214,6 +227,7 @@
 				draw_legend_line(svg, legend_distance, set_propper_distance(distance_steps), "Bug", bug[bug.length-1].points);
 				draw_legend_line(svg, legend_distance, set_propper_distance(distance_steps), "Feature", feature[feature.length-1].points);
 				draw_legend_line(svg, legend_distance, set_propper_distance(distance_steps), "Wish", wish[wish.length-1].points);
+				draw_legend_line(svg, legend_distance, set_propper_distance(distance_steps), "NoPrio", noPrio[noPrio.length-1].points);
 			}
 
 
@@ -243,6 +257,7 @@
 				var bugLine = base_line;
 				var featureLine = base_line;
 				var wishLine = base_line;
+				var noPrioLine = base_line;
 				var timestampLine = base_line;
 
 
@@ -350,6 +365,7 @@
 				draw_line(svg, bug, "line bug", bugLine, "7, 7");
 				draw_line(svg, urgent, "line urgent", urgentLine, "13, 13");
 				draw_line(svg, critical, "line critical", criticalLine, "17, 17");
+				draw_line(svg, noPrio, "line noprio", noPrioLine, "17, 17");
 
 
 				makeLegend(svg, width);
--- a/roundup_content_data/__init__.py	Mon Jul 09 14:49:44 2018 +0200
+++ b/roundup_content_data/__init__.py	Mon Oct 22 16:49:58 2018 +0200
@@ -27,7 +27,8 @@
     "urgent": [],
     "bug": [],
     "feature": [],
-    "wish": []
+    "wish": [],
+    "noPrio": []
 }
 
 #SQL
@@ -50,7 +51,8 @@
     urgent,
     bug,
     feature,
-    wish
+    wish,
+    None
 FROM issues
 WHERE {}
 ORDER BY timestamp
@@ -72,6 +74,15 @@
     INSERT INTO issues (critical, urgent, bug, feature, wish)
     VALUES (?, ?, ?, ?, ?)
 """
+def build_sql_select(columns):
+    return """
+    SELECT strftime("%Y-%m-%dT%H:%M:%S", timestamp),
+    """+ columns + """
+    FROM issues
+    WHERE {}
+    ORDER BY timestamp
+    """
+
 
 
 def build_sql_commands(list_of_columns: list):
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)