Make unsubscribe work with notifications for replies
This commit is contained in:
parent
f6f61c547a
commit
0063fd6e88
@ -81,14 +81,14 @@ class Comments:
|
|||||||
' mode=1',
|
' mode=1',
|
||||||
'WHERE id=? AND mode=2'], (id, ))
|
'WHERE id=? AND mode=2'], (id, ))
|
||||||
|
|
||||||
def unsubscribe(self, id):
|
def unsubscribe(self, email, id):
|
||||||
"""
|
"""
|
||||||
Turn off email notifications for replies to this comment.
|
Turn off email notifications for replies to this comment.
|
||||||
"""
|
"""
|
||||||
self.db.execute([
|
self.db.execute([
|
||||||
'UPDATE comments SET',
|
'UPDATE comments SET',
|
||||||
' notification=0',
|
' notification=0',
|
||||||
'WHERE id=?'], (id, ))
|
'WHERE email=? AND (id=? OR parent=?);'], (email, id, id))
|
||||||
|
|
||||||
def update(self, id, data):
|
def update(self, id, data):
|
||||||
"""
|
"""
|
||||||
|
@ -14,6 +14,11 @@ from email.utils import formatdate
|
|||||||
from email.header import Header
|
from email.header import Header
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
|
|
||||||
|
try:
|
||||||
|
from urllib.parse import quote
|
||||||
|
except ImportError:
|
||||||
|
from urllib import quote
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
logger = logging.getLogger("isso")
|
logger = logging.getLogger("isso")
|
||||||
|
|
||||||
@ -99,7 +104,7 @@ class SMTP(object):
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
yield "comments.new:after-save", self.notify
|
yield "comments.new:after-save", self.notify
|
||||||
|
|
||||||
def format(self, thread, comment, comment_parent, admin=False):
|
def format(self, thread, comment, parent_comment, recipient=None, admin=False):
|
||||||
|
|
||||||
rv = io.StringIO()
|
rv = io.StringIO()
|
||||||
|
|
||||||
@ -133,10 +138,10 @@ class SMTP(object):
|
|||||||
rv.write("Activate comment: %s\n" % (uri + "/activate/" + key))
|
rv.write("Activate comment: %s\n" % (uri + "/activate/" + key))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
uri = self.general_host + "/id/%i" % comment_parent["id"]
|
uri = self.general_host + "/id/%i" % parent_comment["id"]
|
||||||
key = self.isso.sign(('unsubscribe', comment_parent["id"]))
|
key = self.isso.sign(('unsubscribe', recipient))
|
||||||
|
|
||||||
rv.write("Unsubscribe from this conversation: %s\n" % (uri + "/unsubscribe/" + key))
|
rv.write("Unsubscribe from this conversation: %s\n" % (uri + "/unsubscribe/" + quote(recipient) + "/" + key))
|
||||||
|
|
||||||
rv.seek(0)
|
rv.seek(0)
|
||||||
return rv.read()
|
return rv.read()
|
||||||
@ -152,10 +157,10 @@ class SMTP(object):
|
|||||||
email = comment_to_notify["email"]
|
email = comment_to_notify["email"]
|
||||||
if "email" in comment_to_notify and comment_to_notify["notification"] and email not in notified \
|
if "email" in comment_to_notify and comment_to_notify["notification"] and email not in notified \
|
||||||
and comment_to_notify["id"] != comment["id"] and email != comment["email"]:
|
and comment_to_notify["id"] != comment["id"] and email != comment["email"]:
|
||||||
body = self.format(thread, comment, comment_to_notify, admin=False)
|
body = self.format(thread, comment, parent_comment, email, admin=False)
|
||||||
subject = "Re: New comment posted on %s" % thread["title"]
|
subject = "Re: New comment posted on %s" % thread["title"]
|
||||||
self.sendmail(subject, body, thread, comment, to=email)
|
self.sendmail(subject, body, thread, comment, to=email)
|
||||||
notified += email
|
notified.append(email)
|
||||||
|
|
||||||
body = self.format(thread, comment, None, admin=True)
|
body = self.format(thread, comment, None, admin=True)
|
||||||
self.sendmail(thread["title"], body, thread, comment)
|
self.sendmail(thread["title"], body, thread, comment)
|
||||||
|
@ -32,6 +32,10 @@ try:
|
|||||||
from urlparse import urlparse
|
from urlparse import urlparse
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
try:
|
||||||
|
from urllib import unquote
|
||||||
|
except ImportError:
|
||||||
|
from urllib.parse import unquote
|
||||||
try:
|
try:
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -107,7 +111,7 @@ class API(object):
|
|||||||
('view', ('GET', '/id/<int:id>')),
|
('view', ('GET', '/id/<int:id>')),
|
||||||
('edit', ('PUT', '/id/<int:id>')),
|
('edit', ('PUT', '/id/<int:id>')),
|
||||||
('delete', ('DELETE', '/id/<int:id>')),
|
('delete', ('DELETE', '/id/<int:id>')),
|
||||||
('unsubscribe', ('GET', '/id/<int:id>/unsubscribe/<string:key>')),
|
('unsubscribe', ('GET', '/id/<int:id>/unsubscribe/<string:email>/<string:key>')),
|
||||||
('moderate', ('GET', '/id/<int:id>/<any(edit,activate,delete):action>/<string:key>')),
|
('moderate', ('GET', '/id/<int:id>/<any(edit,activate,delete):action>/<string:key>')),
|
||||||
('moderate', ('POST', '/id/<int:id>/<any(edit,activate,delete):action>/<string:key>')),
|
('moderate', ('POST', '/id/<int:id>/<any(edit,activate,delete):action>/<string:key>')),
|
||||||
('like', ('POST', '/id/<int:id>/like')),
|
('like', ('POST', '/id/<int:id>/like')),
|
||||||
@ -494,18 +498,20 @@ class API(object):
|
|||||||
return resp
|
return resp
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@api {get} /id/:id/key unsubscribe
|
@api {get} /id/:id/:email/key unsubscribe
|
||||||
@apiGroup Comment
|
@apiGroup Comment
|
||||||
@apiDescription
|
@apiDescription
|
||||||
Opt out from getting any further email notifications about replies to a particular comment. In order to use this endpoint, the requestor needs a `key` that is usually obtained from an email sent out by isso.
|
Opt out from getting any further email notifications about replies to a particular comment. In order to use this endpoint, the requestor needs a `key` that is usually obtained from an email sent out by isso.
|
||||||
|
|
||||||
@apiParam {number} id
|
@apiParam {number} id
|
||||||
The id of the comment to unsubscribe from replies to.
|
The id of the comment to unsubscribe from replies to.
|
||||||
|
@apiParam {string} email
|
||||||
|
The email address of the subscriber.
|
||||||
@apiParam {string} key
|
@apiParam {string} key
|
||||||
The key to authenticate the subscriber.
|
The key to authenticate the subscriber.
|
||||||
|
|
||||||
@apiExample {curl} Unsubscribe from replies to comment with id 13:
|
@apiExample {curl} Unsubscribe Alice from replies to comment with id 13:
|
||||||
curl -X GET 'https://comments.example.com/id/13/unsubscribe/TODO-COMPUTE-HASH'
|
curl -X GET 'https://comments.example.com/id/13/unsubscribe/alice@example.com/TODO-COMPUTE-HASH'
|
||||||
|
|
||||||
@apiSuccessExample {html} Using GET:
|
@apiSuccessExample {html} Using GET:
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@ -523,13 +529,15 @@ class API(object):
|
|||||||
Yo
|
Yo
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def unsubscribe(self, environ, request, id, key):
|
def unsubscribe(self, environ, request, id, email, key):
|
||||||
|
email = unquote(email)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
rv = self.isso.unsign(key, max_age=2**32)
|
rv = self.isso.unsign(key, max_age=2**32)
|
||||||
except (BadSignature, SignatureExpired):
|
except (BadSignature, SignatureExpired):
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
|
|
||||||
if rv[0] != 'unsubscribe' or rv[1] != id:
|
if rv[0] != 'unsubscribe' or rv[1] != email:
|
||||||
raise Forbidden
|
raise Forbidden
|
||||||
|
|
||||||
item = self.comments.get(id)
|
item = self.comments.get(id)
|
||||||
@ -538,7 +546,7 @@ class API(object):
|
|||||||
raise NotFound
|
raise NotFound
|
||||||
|
|
||||||
with self.isso.lock:
|
with self.isso.lock:
|
||||||
self.comments.unsubscribe(id)
|
self.comments.unsubscribe(email, id)
|
||||||
|
|
||||||
modal = (
|
modal = (
|
||||||
"<!DOCTYPE html>"
|
"<!DOCTYPE html>"
|
||||||
|
Loading…
Reference in New Issue
Block a user