[1/4] Render comments when storing them in the database

Message ID 20170423165302.25025-2-lfleischer@archlinux.org
State Accepted, archived
Headers show
Series
  • Add Markdown syntax to comments
Related show

Commit Message

Lukas Fleischer April 23, 2017, 4:52 p.m. UTC
Instead of converting package comments from plain text to HTML code when
they are displayed, do the conversion when the comment is posted and
store the rendered result in the database. The conversion itself is done
by a Python script which uses Bleach for sanitizing the text.

Signed-off-by: Lukas Fleischer <lfleischer@archlinux.org>
---
 aurweb/scripts/rendercomment.py | 35 +++++++++++++++++++++++++++++++++++
 conf/config.proto               |  1 +
 schema/aur-schema.sql           |  1 +
 setup.py                        |  1 +
 test/setup.sh                   |  1 +
 test/t2600-rendercomment.sh     | 22 ++++++++++++++++++++++
 upgrading/4.6.0.txt             |  6 ++++++
 web/lib/pkgbasefuncs.inc.php    | 40 ++++++++++++++++++++++++++++++++++++----
 web/template/pkg_comments.php   |  4 ++++
 9 files changed, 107 insertions(+), 4 deletions(-)
 create mode 100755 aurweb/scripts/rendercomment.py
 create mode 100755 test/t2600-rendercomment.sh

Patch

diff --git a/aurweb/scripts/rendercomment.py b/aurweb/scripts/rendercomment.py
new file mode 100755
index 0000000..593cd36
--- /dev/null
+++ b/aurweb/scripts/rendercomment.py
@@ -0,0 +1,35 @@ 
+#!/usr/bin/python3
+
+import sys
+import bleach
+
+import aurweb.db
+
+
+def get_comment(conn, commentid):
+    cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?',
+                       [commentid])
+    return cur.fetchone()[0]
+
+
+def save_rendered_comment(conn, commentid, html):
+    conn.execute('UPDATE PackageComments SET RenderedComment = ? WHERE ID = ?',
+                 [html, commentid])
+
+
+def main():
+    commentid = int(sys.argv[1])
+
+    conn = aurweb.db.Connection()
+
+    html = get_comment(conn, commentid)
+    html = html.replace('\n', '<br>')
+    html = bleach.clean(html, tags=['br'])
+    save_rendered_comment(conn, commentid, html)
+
+    conn.commit()
+    conn.close()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/conf/config.proto b/conf/config.proto
index df10b99..094d821 100644
--- a/conf/config.proto
+++ b/conf/config.proto
@@ -33,6 +33,7 @@  log_uri = https://aur.archlinux.org/cgit/aur.git/log/?h=%s
 snapshot_uri = /cgit/aur.git/snapshot/%s.tar.gz
 enable-maintenance = 1
 maintenance-exceptions = 127.0.0.1
+render-comment-cmd = /usr/local/bin/aurweb-rendercomment
 
 [notifications]
 notify-cmd = /usr/local/bin/aurweb-notify
diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql
index be6f3e5..e584165 100644
--- a/schema/aur-schema.sql
+++ b/schema/aur-schema.sql
@@ -255,6 +255,7 @@  CREATE TABLE PackageComments (
 	PackageBaseID INTEGER UNSIGNED NOT NULL,
 	UsersID INTEGER UNSIGNED NULL DEFAULT NULL,
 	Comments TEXT NOT NULL,
+	RenderedComment TEXT NOT NULL,
 	CommentTS BIGINT UNSIGNED NOT NULL DEFAULT 0,
 	EditedTS BIGINT UNSIGNED NULL DEFAULT NULL,
 	EditedUsersID INTEGER UNSIGNED NULL DEFAULT NULL,
diff --git a/setup.py b/setup.py
index 99dbfed..9d10cc1 100644
--- a/setup.py
+++ b/setup.py
@@ -27,6 +27,7 @@  setup(
             'aurweb-notify = aurweb.scripts.notify:main',
             'aurweb-pkgmaint = aurweb.scripts.pkgmaint:main',
             'aurweb-popupdate = aurweb.scripts.popupdate:main',
+            'aurweb-rendercomment = aurweb.scripts.rendercomment:main',
             'aurweb-tuvotereminder = aurweb.scripts.tuvotereminder:main',
         ],
     },
diff --git a/test/setup.sh b/test/setup.sh
index b71e73e..f29695a 100644
--- a/test/setup.sh
+++ b/test/setup.sh
@@ -16,6 +16,7 @@  TUVOTEREMINDER="$TOPLEVEL/aurweb/scripts/tuvotereminder.py"
 PKGMAINT="$TOPLEVEL/aurweb/scripts/pkgmaint.py"
 AURBLUP="$TOPLEVEL/aurweb/scripts/aurblup.py"
 NOTIFY="$TOPLEVEL/aurweb/scripts/notify.py"
+RENDERCOMMENT="$TOPLEVEL/aurweb/scripts/rendercomment.py"
 
 # Create the configuration file and a dummy notification script.
 cat >config <<-EOF
diff --git a/test/t2600-rendercomment.sh b/test/t2600-rendercomment.sh
new file mode 100755
index 0000000..8d79336
--- /dev/null
+++ b/test/t2600-rendercomment.sh
@@ -0,0 +1,22 @@ 
+#!/bin/sh
+
+test_description='rendercomment tests'
+
+. ./setup.sh
+
+test_expect_success 'Test comment rendering.' '
+	cat <<-EOD | sqlite3 aur.db &&
+	INSERT INTO PackageComments (ID, PackageBaseID, Comments, RenderedComment) VALUES (1, 1, "Hello world!
+	This is a comment.", "");
+	EOD
+	"$RENDERCOMMENT" 1 &&
+	cat <<-EOD >expected &&
+	Hello world!<br>This is a comment.
+	EOD
+	cat <<-EOD | sqlite3 aur.db >actual &&
+	SELECT RenderedComment FROM PackageComments WHERE ID = 1;
+	EOD
+	test_cmp actual expected
+'
+
+test_done
diff --git a/upgrading/4.6.0.txt b/upgrading/4.6.0.txt
index 45740f4..b051bac 100644
--- a/upgrading/4.6.0.txt
+++ b/upgrading/4.6.0.txt
@@ -9,3 +9,9 @@  UPDATE PackageDepends
 	SET DepName = SUBSTRING(DepName FROM 1 FOR POSITION(': ' IN DepName) - 1)
 	WHERE POSITION(': ' IN DepName) > 0;
 ---
+
+2. Add RenderedComment column to PackageComments:
+
+---
+ALTER TABLE PackageComments ADD COLUMN RenderedComment TEXT NOT NULL;
+---
diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php
index 57933e8..3e78309 100644
--- a/web/lib/pkgbasefuncs.inc.php
+++ b/web/lib/pkgbasefuncs.inc.php
@@ -54,7 +54,7 @@  function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false
 	$dbh = DB::connect();
 	$q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, ";
 	$q.= "PackageBaseID, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, ";
-	$q.= "DelUsersID, C.UserName AS DelUserName, ";
+	$q.= "DelUsersID, C.UserName AS DelUserName, RenderedComment, ";
 	$q.= "PinnedTS FROM PackageComments ";
 	$q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID ";
 	$q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID ";
@@ -79,6 +79,36 @@  function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false
 	return $result->fetchAll();
 }
 
+/*
+ * Invoke the comment rendering script.
+ *
+ * @param int $id ID of the comment to render
+ *
+ * @return void
+ */
+function render_comment($id) {
+	$cmd = config_get('options', 'render-comment-cmd');
+	$cmd .= ' ' . intval($id);
+
+	$descspec = array(
+		0 => array('pipe', 'r'),
+		1 => array('pipe', 'w'),
+		2 => array('pipe', 'w')
+	);
+
+	$p = proc_open($cmd, $descspec, $pipes);
+
+	if (!is_resource($p)) {
+		return false;
+	}
+
+	fclose($pipes[0]);
+	fclose($pipes[1]);
+	fclose($pipes[2]);
+
+	return proc_close($p);
+}
+
 /**
  * Add a comment to a package page and send out appropriate notifications
  *
@@ -96,12 +126,14 @@  function pkgbase_add_comment($base_id, $uid, $comment) {
 	}
 
 	$q = "INSERT INTO PackageComments ";
-	$q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES (";
-	$q.= intval($base_id) . ", " . $uid . ", ";
-	$q.= $dbh->quote($comment) . ", " . strval(time()) . ")";
+	$q.= "(PackageBaseID, UsersID, Comments, RenderedComment, CommentTS) ";
+	$q.= "VALUES (" . intval($base_id) . ", " . $uid . ", ";
+	$q.= $dbh->quote($comment) . ", '', " . strval(time()) . ")";
 	$dbh->exec($q);
 	$comment_id = $dbh->lastInsertId();
 
+	render_comment($comment_id);
+
 	notify(array('comment', $uid, $base_id, $comment_id));
 
 	return array(true, __('Comment has been added.'));
diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php
index c23ec42..f973b74 100644
--- a/web/template/pkg_comments.php
+++ b/web/template/pkg_comments.php
@@ -103,9 +103,13 @@  if (!isset($count)) {
 			<?php endif; ?>
 		</h4>
 		<div id="<?= isset($pinned) ? "pinned-" : "comment-" ?><?= $row['ID'] ?>-content" class="article-content<?php if ($is_deleted): ?> comment-deleted<?php endif; ?>">
+			<?php if (!empty($row['RenderedComment'])): ?>
+			<?= $row['RenderedComment'] ?>
+			<?php else: ?>
 			<p>
 				<?= parse_comment($row['Comments']) ?>
 			</p>
+			<?php endif; ?>
 		</div>
 	<?php endwhile; ?>