From 08313c191c0cb1d87c76f190bdac1886fc63ca02 Mon Sep 17 00:00:00 2001 From: Thomas Sileo Date: Thu, 26 Dec 2013 19:19:15 +0100 Subject: [PATCH 1/3] Added reply notification for commenter --- isso/css/isso.scss | 6 ++++ isso/db/comments.py | 11 ++++--- isso/ext/notifications.py | 61 +++++++++++++++++++++-------------- isso/js/app/i18n/en.js | 1 + isso/js/app/i18n/fr.js | 1 + isso/js/app/isso.js | 4 ++- isso/js/app/text/postbox.html | 4 +++ isso/views/comments.py | 6 ++-- 8 files changed, 61 insertions(+), 33 deletions(-) diff --git a/isso/css/isso.scss b/isso/css/isso.scss index 94dd227..11f6350 100644 --- a/isso/css/isso.scss +++ b/isso/css/isso.scss @@ -214,5 +214,11 @@ a { } } } + + > .notification-section { + display: none; + padding-bottom: 10px; + } + } } diff --git a/isso/db/comments.py b/isso/db/comments.py index 6897c97..47ed6a7 100644 --- a/isso/db/comments.py +++ b/isso/db/comments.py @@ -20,7 +20,7 @@ class Comments: """ fields = ['tid', 'id', 'parent', 'created', 'modified', 'mode', 'remote_addr', - 'text', 'author', 'email', 'website', 'likes', 'dislikes', 'voters'] + 'text', 'author', 'email', 'website', 'likes', 'dislikes', 'voters', 'notification'] def __init__(self, db): @@ -30,7 +30,8 @@ class Comments: ' tid REFERENCES threads(id), id INTEGER PRIMARY KEY, parent INTEGER,', ' created FLOAT NOT NULL, modified FLOAT, mode INTEGER, remote_addr VARCHAR,', ' text VARCHAR, author VARCHAR, email VARCHAR, website VARCHAR,', - ' likes INTEGER DEFAULT 0, dislikes INTEGER DEFAULT 0, voters BLOB NOT NULL);']) + ' likes INTEGER DEFAULT 0, dislikes INTEGER DEFAULT 0, voters BLOB NOT NULL,', + ' notification INTEGER);']) def add(self, uri, c): """ @@ -41,16 +42,16 @@ class Comments: 'INSERT INTO comments (', ' tid, parent,' ' created, modified, mode, remote_addr,', - ' text, author, email, website, voters )', + ' text, author, email, website, voters, notification)', 'SELECT', ' threads.id, ?,', ' ?, ?, ?, ?,', - ' ?, ?, ?, ?, ?', + ' ?, ?, ?, ?, ?, ?', 'FROM threads WHERE threads.uri = ?;'], ( c.get('parent'), c.get('created') or time.time(), None, c["mode"], c['remote_addr'], c['text'], c.get('author'), c.get('email'), c.get('website'), buffer( - Bloomfilter(iterable=[c['remote_addr']]).array), + Bloomfilter(iterable=[c['remote_addr']]).array), c.get('notification', 0), uri) ) diff --git a/isso/ext/notifications.py b/isso/ext/notifications.py index 3283bd6..7e9ad27 100644 --- a/isso/ext/notifications.py +++ b/isso/ext/notifications.py @@ -58,10 +58,10 @@ class SMTP(object): def __enter__(self): klass = (smtplib.SMTP_SSL if self.conf.get('security') == 'ssl' else smtplib.SMTP) + klass = smtplib.SMTP self.client = klass(host=self.conf.get('host'), port=self.conf.getint('port')) - - if self.conf.get('security') == 'starttls': - self.client.starttls(); + #if self.conf.get('security') == 'starttls': + # self.client.starttls(); if self.conf.get('username') and self.conf.get('password'): self.client.login(self.conf.get('username'), @@ -75,7 +75,7 @@ class SMTP(object): def __iter__(self): yield "comments.new:after-save", self.notify - def format(self, thread, comment): + def format(self, thread, comment, admin=False): rv = io.StringIO() @@ -88,39 +88,50 @@ class SMTP(object): rv.write(comment["text"] + "\n") rv.write("\n") - if comment["website"]: - rv.write("User's URL: %s\n" % comment["website"]) + if admin: + if comment["website"]: + rv.write("User's URL: %s\n" % comment["website"]) - rv.write("IP address: %s\n" % comment["remote_addr"]) - rv.write("Link to comment: %s\n" % (local("origin") + thread["uri"] + "#isso-%i" % comment["id"])) - rv.write("\n") + rv.write("IP address: %s\n" % comment["remote_addr"]) + rv.write("Link to comment: %s\n" % (local("origin") + thread["uri"] + "#isso-%i" % comment["id"])) + rv.write("\n") - uri = local("host") + "/id/%i" % comment["id"] - key = self.isso.sign(comment["id"]) + uri = local("host") + "/id/%i" % comment["id"] + key = self.isso.sign(comment["id"]) - rv.write("---\n") - rv.write("Delete comment: %s\n" % (uri + "/delete/" + key)) + rv.write("---\n") + rv.write("Delete comment: %s\n" % (uri + "/delete/" + key)) - if comment["mode"] == 2: - rv.write("Activate comment: %s\n" % (uri + "/activate/" + key)) + if comment["mode"] == 2: + rv.write("Activate comment: %s\n" % (uri + "/activate/" + key)) rv.seek(0) return rv.read() def notify(self, thread, comment): - - body = self.format(thread, comment) - + if "parent" in comment: + comment_parent = self.isso.db.comments.get(comment["parent"]) + # Notify the author that a new comment is posted if requested + if "email" in comment_parent and comment_parent["notification"]: + body = self.format(thread, comment, admin=False) + subject = "Re: New comment posted on %s" % thread["title"] + self.sendmail(subject, body, thread, comment, to=comment_parent["email"]) + + body = self.format(thread, comment, admin=True) + self.sendmail(thread["title"], body, thread, comment) + + def sendmail(self, subject, body, thread, comment, to=None): if uwsgi: - uwsgi.spool({b"subject": thread["title"].encode("utf-8"), - b"body": body.encode("utf-8")}) + uwsgi.spool({b"subject": subject.encode("utf-8"), + b"body": body.encode("utf-8"), + b"to": to}) else: - start_new_thread(self._retry, (thread["title"], body)) + start_new_thread(self._retry, (subject, body, to)) - def _sendmail(self, subject, body): + def _sendmail(self, subject, body, to=None): from_addr = self.conf.get("from") - to_addr = self.conf.get("to") + to_addr = to or self.conf.get("to") msg = MIMEText(body, 'plain', 'utf-8') msg['From'] = "Ich schrei sonst! <%s>" % from_addr @@ -131,10 +142,10 @@ class SMTP(object): with self as con: con.sendmail(from_addr, to_addr, msg.as_string()) - def _retry(self, subject, body): + def _retry(self, subject, body, to): for x in range(5): try: - self._sendmail(subject, body) + self._sendmail(subject, body, to) except smtplib.SMTPConnectError: time.sleep(60) else: diff --git a/isso/js/app/i18n/en.js b/isso/js/app/i18n/en.js index 0381a63..db73336 100644 --- a/isso/js/app/i18n/en.js +++ b/isso/js/app/i18n/en.js @@ -3,6 +3,7 @@ define({ "postbox-author": "Name (optional)", "postbox-email": "E-mail (optional)", "postbox-submit": "Submit", + "postbox-notification": "Subscribe to email notification of replies", "num-comments": "One Comment\n{{ n }} Comments", "no-comments": "No Comments Yet", diff --git a/isso/js/app/i18n/fr.js b/isso/js/app/i18n/fr.js index fbc8762..7434ef9 100644 --- a/isso/js/app/i18n/fr.js +++ b/isso/js/app/i18n/fr.js @@ -3,6 +3,7 @@ define({ "postbox-author": "Nom (optionel)", "postbox-email": "Courriel (optionel)", "postbox-submit": "Soumettre", + "postbox-notification": "S'abonner aux notifications de réponses", "num-comments": "Un commentaire\n{{ n }} commentaires", "no-comments": "Aucun commentaire pour l'instant", diff --git a/isso/js/app/isso.js b/isso/js/app/isso.js index b374614..a472e59 100644 --- a/isso/js/app/isso.js +++ b/isso/js/app/isso.js @@ -34,6 +34,7 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m .then(function(rv) { $(".avatar svg", el).replace(lib.identicons.generate(rv, 4, 48)); }); + $(".notification-section").style.display = "block"; }, 200); }, false); @@ -63,7 +64,8 @@ define(["app/text/html", "app/dom", "app/utils", "app/config", "app/api", "app/m author: $("[name=author]", el).value || null, email: $("[name=email]", el).value || null, text: $("textarea", el).value, - parent: parent || null + parent: parent || null, + notification: $("[name=notification]", el).checked ? 1 : 0, }).then(function(comment) { $("[name=author]", el).value = ""; $("[name=email]", el).value = ""; diff --git a/isso/js/app/text/postbox.html b/isso/js/app/text/postbox.html index a72f71f..18a418e 100644 --- a/isso/js/app/text/postbox.html +++ b/isso/js/app/text/postbox.html @@ -6,6 +6,7 @@
+

@@ -17,5 +18,8 @@

+
+ +
\ No newline at end of file diff --git a/isso/views/comments.py b/isso/views/comments.py index 492e99c..f0ecb00 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -52,10 +52,10 @@ def xhr(func): class API(object): FIELDS = set(['id', 'parent', 'text', 'author', 'website', 'email', - 'mode', 'created', 'modified', 'likes', 'dislikes', 'hash']) + 'mode', 'created', 'modified', 'likes', 'dislikes', 'hash', 'notification']) # comment fields, that can be submitted - ACCEPT = set(['text', 'author', 'website', 'email', 'parent']) + ACCEPT = set(['text', 'author', 'website', 'email', 'parent', 'notification']) VIEWS = [ ('fetch', ('GET', '/')), @@ -123,6 +123,7 @@ class API(object): valid, reason = API.verify(data) if not valid: + print valid, "VALID" return BadRequest(reason) for field in ("author", "email"): @@ -134,6 +135,7 @@ class API(object): with self.isso.lock: if uri not in self.threads: + print "URI", uri, local('origin') with http.curl('GET', local("origin"), uri) as resp: if resp and resp.status == 200: uri, title = parse.thread(resp.read(), id=uri) From e50ecc78111dd4603d3a2adb614666a66b148388 Mon Sep 17 00:00:00 2001 From: Thomas Sileo Date: Thu, 26 Dec 2013 19:22:55 +0100 Subject: [PATCH 2/3] Removed debug info --- isso/ext/notifications.py | 5 ++--- isso/views/comments.py | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/isso/ext/notifications.py b/isso/ext/notifications.py index 7e9ad27..fce0a04 100644 --- a/isso/ext/notifications.py +++ b/isso/ext/notifications.py @@ -58,10 +58,9 @@ class SMTP(object): def __enter__(self): klass = (smtplib.SMTP_SSL if self.conf.get('security') == 'ssl' else smtplib.SMTP) - klass = smtplib.SMTP self.client = klass(host=self.conf.get('host'), port=self.conf.getint('port')) - #if self.conf.get('security') == 'starttls': - # self.client.starttls(); + if self.conf.get('security') == 'starttls': + self.client.starttls() if self.conf.get('username') and self.conf.get('password'): self.client.login(self.conf.get('username'), diff --git a/isso/views/comments.py b/isso/views/comments.py index f0ecb00..963e520 100644 --- a/isso/views/comments.py +++ b/isso/views/comments.py @@ -123,7 +123,6 @@ class API(object): valid, reason = API.verify(data) if not valid: - print valid, "VALID" return BadRequest(reason) for field in ("author", "email"): @@ -135,7 +134,6 @@ class API(object): with self.isso.lock: if uri not in self.threads: - print "URI", uri, local('origin') with http.curl('GET', local("origin"), uri) as resp: if resp and resp.status == 200: uri, title = parse.thread(resp.read(), id=uri) From a322cf673af0aad21cd05f5c0459cb4446b5cb90 Mon Sep 17 00:00:00 2001 From: Thomas Sileo Date: Thu, 26 Dec 2013 22:22:48 +0100 Subject: [PATCH 3/3] Bugfix --- isso/ext/notifications.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isso/ext/notifications.py b/isso/ext/notifications.py index fce0a04..decd13c 100644 --- a/isso/ext/notifications.py +++ b/isso/ext/notifications.py @@ -111,7 +111,7 @@ class SMTP(object): if "parent" in comment: comment_parent = self.isso.db.comments.get(comment["parent"]) # Notify the author that a new comment is posted if requested - if "email" in comment_parent and comment_parent["notification"]: + if comment_parent and "email" in comment_parent and comment_parent["notification"]: body = self.format(thread, comment, admin=False) subject = "Re: New comment posted on %s" % thread["title"] self.sendmail(subject, body, thread, comment, to=comment_parent["email"])