Refactor the notification script

Reimplement most of the notification script logic. Create a separate
class for each notification type. Each class provides methods for
generating the list of recipients, the message subject, the message
body, the references to add at the end of the message and the message
headers. Additionally, a method for sending notification emails is
provided.

One major benefit of the new implementation is that both the generation
of recipients and message contents are much more flexible. For example,
it is now easily possible to make user-specific adjustments to every
single notification of a batch.

Signed-off-by: Lukas Fleischer <lfleischer@archlinux.org>
This commit is contained in:
Lukas Fleischer 2018-05-17 19:49:34 +02:00
parent fec253a65d
commit f3b4c5c6bc

View file

@ -9,11 +9,6 @@ import aurweb.config
import aurweb.db
aur_location = aurweb.config.get('options', 'aur_location')
aur_request_ml = aurweb.config.get('options', 'aur_request_ml')
sendmail = aurweb.config.get('notifications', 'sendmail')
sender = aurweb.config.get('notifications', 'sender')
reply_to = aurweb.config.get('notifications', 'reply-to')
def headers_cc(cclist):
@ -28,29 +23,6 @@ def headers_reply(thread_id):
return {'In-Reply-To': thread_id, 'References': thread_id}
def send_notification(to, subject, body, refs, headers={}):
wrapped = ''
for line in body.splitlines():
wrapped += textwrap.fill(line, break_long_words=False) + '\n'
if refs:
body = wrapped + '\n' + refs
else:
body = wrapped.rstrip()
for recipient in to:
msg = email.mime.text.MIMEText(body, 'plain', 'utf-8')
msg['Subject'] = subject
msg['From'] = sender
msg['Reply-to'] = reply_to
msg['To'] = recipient
for key, value in headers.items():
msg[key] = value
p = subprocess.Popen([sendmail, '-t', '-oi'], stdin=subprocess.PIPE)
p.communicate(msg.as_bytes())
def username_from_id(conn, uid):
cur = conn.execute('SELECT UserName FROM Users WHERE ID = ?', [uid])
return cur.fetchone()[0]
@ -73,380 +45,444 @@ def get_user_email(conn, uid):
return cur.fetchone()[0]
def get_flag_recipients(conn, pkgbase_id):
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'LEFT JOIN PackageComaintainers ' +
'ON PackageComaintainers.UsersID = Users.ID ' +
'INNER JOIN PackageBases ' +
'ON PackageBases.MaintainerUID = Users.ID OR ' +
'PackageBases.ID = PackageComaintainers.PackageBaseID ' +
'WHERE PackageBases.ID = ?', [pkgbase_id])
return [row[0] for row in cur.fetchall()]
def get_recipients(conn, pkgbase_id, uid):
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
return [row[0] for row in cur.fetchall()]
def get_comment_recipients(conn, pkgbase_id, uid):
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.CommentNotify = 1 AND ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
return [row[0] for row in cur.fetchall()]
def get_update_recipients(conn, pkgbase_id, uid):
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.UpdateNotify = 1 AND ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
return [row[0] for row in cur.fetchall()]
def get_ownership_recipients(conn, pkgbase_id, uid):
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.OwnershipNotify = 1 AND ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
return [row[0] for row in cur.fetchall()]
def get_request_recipients(conn, reqid):
cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' +
'INNER JOIN PackageBases ' +
'ON PackageBases.ID = PackageRequests.PackageBaseID ' +
'INNER JOIN Users ' +
'ON Users.ID = PackageRequests.UsersID ' +
'OR Users.ID = PackageBases.MaintainerUID ' +
'WHERE PackageRequests.ID = ?', [reqid])
return [row[0] for row in cur.fetchall()]
def get_tu_vote_reminder_recipients(conn, vote_id):
cur = conn.execute('SELECT Email FROM Users ' +
'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' +
'(SELECT UserID FROM TU_Votes ' +
'WHERE TU_Votes.VoteID = ?)', [vote_id])
return [row[0] for row in cur.fetchall()]
def get_comment(conn, comment_id):
cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?',
[comment_id])
return cur.fetchone()[0]
def get_flagger_comment(conn, pkgbase_id):
cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ID = ?',
[pkgbase_id])
return cur.fetchone()[0]
def get_request_comment(conn, reqid):
cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?',
[reqid])
return cur.fetchone()[0]
def get_request_closure_comment(conn, reqid):
cur = conn.execute('SELECT ClosureComment FROM PackageRequests ' +
'WHERE ID = ?', [reqid])
return cur.fetchone()[0]
def send_resetkey(conn, uid):
cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' +
'WHERE ID = ?', [uid])
username, to, resetkey = cur.fetchone()
subject = 'AUR Password Reset'
body = 'A password reset request was submitted for the account %s ' \
'associated with your email address. If you wish to reset your ' \
'password follow the link [1] below, otherwise ignore this ' \
'message and nothing will happen.' % (username)
refs = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey
send_notification([to], subject, body, refs)
def welcome(conn, uid):
cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' +
'WHERE ID = ?', [uid])
username, to, resetkey = cur.fetchone()
subject = 'Welcome to the Arch User Repository'
body = 'Welcome to the Arch User Repository! In order to set an initial ' \
'password for your new account, please click the link [1] below. ' \
'If the link does not work, try copying and pasting it into your ' \
'browser.'
refs = '[1] ' + aur_location + '/passreset/?resetkey=' + resetkey
send_notification([to], subject, body, refs)
def comment(conn, uid, pkgbase_id, comment_id):
user = username_from_id(conn, uid)
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = get_comment_recipients(conn, pkgbase_id, uid)
text = get_comment(conn, comment_id)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Comment for %s' % (pkgbase)
body = '%s [1] added the following comment to %s [2]:' % (user, pkgbase)
body += '\n\n' + text + '\n\n'
body += 'If you no longer wish to receive notifications about this ' \
'package, please go to the package page [2] and select "%s".' % \
('Disable notifications')
refs = '[1] ' + user_uri + '\n'
refs += '[2] ' + pkgbase_uri
thread_id = '<pkg-notifications-' + pkgbase + '@aur.archlinux.org>'
headers = headers_reply(thread_id)
send_notification(to, subject, body, refs, headers)
def update(conn, uid, pkgbase_id):
user = username_from_id(conn, uid)
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = get_update_recipients(conn, pkgbase_id, uid)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Package Update: %s' % (pkgbase)
body = '%s [1] pushed a new commit to %s [2].' % (user, pkgbase)
body += '\n\n'
body += 'If you no longer wish to receive notifications about this ' \
'package, please go to the package page [2] and select "%s".' % \
('Disable notifications')
refs = '[1] ' + user_uri + '\n'
refs += '[2] ' + pkgbase_uri
thread_id = '<pkg-notifications-' + pkgbase + '@aur.archlinux.org>'
headers = headers_reply(thread_id)
send_notification(to, subject, body, refs, headers)
def flag(conn, uid, pkgbase_id):
user = username_from_id(conn, uid)
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = get_flag_recipients(conn, pkgbase_id)
text = get_flagger_comment(conn, pkgbase_id)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Out-of-date Notification for %s' % (pkgbase)
body = 'Your package %s [1] has been flagged out-of-date by %s [2]:' % \
(pkgbase, user)
body += '\n\n' + text
refs = '[1] ' + pkgbase_uri + '\n'
refs += '[2] ' + user_uri
send_notification(to, subject, body, refs)
def adopt(conn, pkgbase_id, uid):
user = username_from_id(conn, uid)
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = get_ownership_recipients(conn, pkgbase_id, uid)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Ownership Notification for %s' % (pkgbase)
body = 'The package %s [1] was adopted by %s [2].' % (pkgbase, user)
refs = '[1] ' + pkgbase_uri + '\n'
refs += '[2] ' + user_uri
send_notification(to, subject, body, refs)
def disown(conn, pkgbase_id, uid):
user = username_from_id(conn, uid)
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = get_ownership_recipients(conn, pkgbase_id, uid)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Ownership Notification for %s' % (pkgbase)
body = 'The package %s [1] was disowned by %s [2].' % (pkgbase, user)
refs = '[1] ' + pkgbase_uri + '\n'
refs += '[2] ' + user_uri
send_notification(to, subject, body, refs)
def comaintainer_add(conn, pkgbase_id, uid):
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = [get_user_email(conn, uid)]
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase)
body = 'You were added to the co-maintainer list of %s [1].' % (pkgbase)
refs = '[1] ' + pkgbase_uri
send_notification(to, subject, body, refs)
def comaintainer_remove(conn, pkgbase_id, uid):
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = [get_user_email(conn, uid)]
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = 'AUR Co-Maintainer Notification for %s' % (pkgbase)
body = ('You were removed from the co-maintainer list of %s [1].' %
(pkgbase))
refs = '[1] ' + pkgbase_uri
send_notification(to, subject, body, refs)
def delete(conn, uid, old_pkgbase_id, new_pkgbase_id=None):
user = username_from_id(conn, uid)
old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id)
if new_pkgbase_id:
new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id)
to = get_recipients(conn, old_pkgbase_id, uid)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + old_pkgbase + '/'
subject = 'AUR Package deleted: %s' % (old_pkgbase)
if new_pkgbase_id:
new_pkgbase_uri = aur_location + '/pkgbase/' + new_pkgbase + '/'
body = '%s [1] merged %s [2] into %s [3].\n\n' \
'If you no longer wish receive notifications about the new ' \
'package, please go to [3] and click "%s".' %\
(user, old_pkgbase, new_pkgbase, 'Disable notifications')
refs = '[1] ' + user_uri + '\n'
refs += '[2] ' + pkgbase_uri + '\n'
refs += '[3] ' + new_pkgbase_uri
else:
body = '%s [1] deleted %s [2].\n\n' \
'You will no longer receive notifications about this ' \
'package.' % (user, old_pkgbase)
refs = '[1] ' + user_uri + '\n'
refs += '[2] ' + pkgbase_uri
send_notification(to, subject, body, refs)
def request_open(conn, uid, reqid, reqtype, pkgbase_id, merge_into=None):
user = username_from_id(conn, uid)
pkgbase = pkgbase_from_id(conn, pkgbase_id)
to = [aur_request_ml]
cc = get_request_recipients(conn, reqid)
text = get_request_comment(conn, reqid)
user_uri = aur_location + '/account/' + user + '/'
pkgbase_uri = aur_location + '/pkgbase/' + pkgbase + '/'
subject = '[PRQ#%d] %s Request for %s' % \
(int(reqid), reqtype.title(), pkgbase)
if merge_into:
merge_into_uri = aur_location + '/pkgbase/' + merge_into + '/'
body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \
(user, pkgbase, merge_into)
body += '\n\n' + text
refs = '[1] ' + user_uri + '\n'
refs += '[2] ' + pkgbase_uri + '\n'
refs += '[3] ' + merge_into_uri
else:
body = '%s [1] filed a %s request for %s [2]:' % \
(user, reqtype, pkgbase)
body += '\n\n' + text
refs = '[1] ' + user_uri + '\n'
refs += '[2] ' + pkgbase_uri
thread_id = '<pkg-request-' + reqid + '@aur.archlinux.org>'
# Use a deterministic Message-ID for the first email referencing a request.
headers = headers_msgid(thread_id)
headers.update(headers_cc(cc))
send_notification(to, subject, body, refs, headers)
def request_close(conn, uid, reqid, reason):
to = [aur_request_ml]
cc = get_request_recipients(conn, reqid)
text = get_request_closure_comment(conn, reqid)
subject = '[PRQ#%d] Request %s' % (int(reqid), reason.title())
if int(uid):
user = username_from_id(conn, uid)
user_uri = aur_location + '/account/' + user + '/'
body = 'Request #%d has been %s by %s [1]' % (int(reqid), reason, user)
refs = '[1] ' + user_uri
else:
body = 'Request #%d has been %s automatically by the Arch User ' \
'Repository package request system' % (int(reqid), reason)
refs = None
if text.strip() == '':
body += '.'
else:
body += ':\n\n' + text
thread_id = '<pkg-request-' + reqid + '@aur.archlinux.org>'
headers = headers_reply(thread_id)
headers.update(headers_cc(cc))
send_notification(to, subject, body, refs, headers)
def tu_vote_reminder(conn, vote_id):
to = get_tu_vote_reminder_recipients(conn, vote_id)
vote_uri = aur_location + '/tu/?id=' + vote_id
subject = 'TU Vote Reminder: Proposal %d' % (int(vote_id))
body = 'Please remember to cast your vote on proposal %d [1]. ' \
'The voting period ends in less than 48 hours.' % (int(vote_id))
refs = '[1] ' + vote_uri
send_notification(to, subject, body, refs)
class Notification:
def get_refs(self):
return ()
def get_headers(self):
return {}
def send(self):
body = ''
for line in self.get_body().splitlines():
body += textwrap.fill(line, break_long_words=False) + '\n'
for i, ref in enumerate(self.get_refs()):
body += '\n' + '[%d] %s' % (i + 1, ref)
body = body.rstrip()
sendmail = aurweb.config.get('notifications', 'sendmail')
sender = aurweb.config.get('notifications', 'sender')
reply_to = aurweb.config.get('notifications', 'reply-to')
for recipient in self.get_recipients():
msg = email.mime.text.MIMEText(body, 'plain', 'utf-8')
msg['Subject'] = self.get_subject()
msg['From'] = sender
msg['Reply-to'] = reply_to
msg['To'] = recipient
for key, value in self.get_headers().items():
msg[key] = value
p = subprocess.Popen([sendmail, '-t', '-oi'],
stdin=subprocess.PIPE)
p.communicate(msg.as_bytes())
class ResetKeyNotification(Notification):
def __init__(self, conn, uid):
cur = conn.execute('SELECT UserName, Email, ResetKey FROM Users ' +
'WHERE ID = ?', [uid])
self._username, self._to, self._resetkey = cur.fetchone()
def get_recipients(self):
return [self._to]
def get_subject(self):
return 'AUR Password Reset'
def get_body(self):
return 'A password reset request was submitted for the account %s ' \
'associated with your email address. If you wish to reset ' \
'your password follow the link [1] below, otherwise ignore ' \
'this message and nothing will happen.' % (self._username)
def get_refs(self):
return (aur_location + '/passreset/?resetkey=' + self._resetkey,)
class WelcomeNotification(ResetKeyNotification):
def get_subject(self):
return 'Welcome to the Arch User Repository'
def get_body(self):
return 'Welcome to the Arch User Repository! In order to set an ' \
'initial password for your new account, please click the ' \
'link [1] below. If the link does not work, try copying and ' \
'pasting it into your browser.'
class CommentNotification(Notification):
def __init__(self, conn, uid, pkgbase_id, comment_id):
self._user = username_from_id(conn, uid)
self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.CommentNotify = 1 AND ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
self._to = [row[0] for row in cur.fetchall()]
cur = conn.execute('SELECT Comments FROM PackageComments WHERE ID = ?',
[comment_id])
self._text = cur.fetchone()[0]
def get_recipients(self):
return self._to
def get_subject(self):
return 'AUR Comment for %s' % (self._pkgbase)
def get_body(self):
body = '%s [1] added the following comment to %s [2]:' % \
(self._user, self._pkgbase)
body += '\n\n' + self._text + '\n\n'
body += 'If you no longer wish to receive notifications about this ' \
'package, please go to the package page [2] and select ' \
'"%s".' % ('Disable notifications')
return body
def get_refs(self):
return (aur_location + '/account/' + self._user + '/',
aur_location + '/pkgbase/' + self._pkgbase + '/')
def get_headers(self):
thread_id = '<pkg-notifications-' + self._pkgbase + \
'@aur.archlinux.org>'
return headers_reply(thread_id)
class UpdateNotification(Notification):
def __init__(self, conn, uid, pkgbase_id):
self._user = username_from_id(conn, uid)
self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.UpdateNotify = 1 AND ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
self._to = [row[0] for row in cur.fetchall()]
def get_recipients(self):
return self._to
def get_subject(self):
return 'AUR Package Update: %s' % (self._pkgbase)
def get_body(self):
body = '%s [1] pushed a new commit to %s [2].' % \
(self._user, self._pkgbase)
body += '\n\n'
body += 'If you no longer wish to receive notifications about this ' \
'package, please go to the package page [2] and select ' \
'"%s".' % ('Disable notifications')
return body
def get_refs(self):
return (aur_location + '/account/' + self._user + '/',
aur_location + '/pkgbase/' + self._pkgbase + '/')
def get_headers(self):
thread_id = '<pkg-notifications-' + self._pkgbase + \
'@aur.archlinux.org>'
return headers_reply(thread_id)
class FlagNotification(Notification):
def __init__(self, conn, uid, pkgbase_id):
self._user = username_from_id(conn, uid)
self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'LEFT JOIN PackageComaintainers ' +
'ON PackageComaintainers.UsersID = Users.ID ' +
'INNER JOIN PackageBases ' +
'ON PackageBases.MaintainerUID = Users.ID OR ' +
'PackageBases.ID = PackageComaintainers.PackageBaseID ' +
'WHERE PackageBases.ID = ?', [pkgbase_id])
self._to = [row[0] for row in cur.fetchall()]
cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' +
'ID = ?', [pkgbase_id])
self._text = cur.fetchone()[0]
def get_recipients(self):
return self._to
def get_subject(self):
return 'AUR Out-of-date Notification for %s' % (self._pkgbase)
def get_body(self):
body = 'Your package %s [1] has been flagged out-of-date by ' \
'%s [2]:' % (self._pkgbase, self._user)
body += '\n\n' + self._text
return body
def get_refs(self):
return (aur_location + '/pkgbase/' + self._pkgbase + '/',
aur_location + '/account/' + self._user + '/')
class OwnershipEventNotification(Notification):
def __init__(self, conn, uid, pkgbase_id):
self._user = username_from_id(conn, uid)
self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.OwnershipNotify = 1 AND ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, pkgbase_id])
self._to = [row[0] for row in cur.fetchall()]
cur = conn.execute('SELECT FlaggerComment FROM PackageBases WHERE ' +
'ID = ?', [pkgbase_id])
self._text = cur.fetchone()[0]
def get_recipients(self):
return self._to
def get_subject(self):
return 'AUR Ownership Notification for %s' % (self._pkgbase)
def get_refs(self):
return (aur_location + '/pkgbase/' + self._pkgbase + '/',
aur_location + '/account/' + self._user + '/')
class AdoptNotification(OwnershipEventNotification):
def get_body(self):
return 'The package %s [1] was adopted by %s [2].' % \
(self._pkgbase, self._user)
class DisownNotification(OwnershipEventNotification):
def get_body(self):
return 'The package %s [1] was disowned by %s [2].' % \
(self._pkgbase, self._user)
class ComaintainershipEventNotification(Notification):
def __init__(self, conn, uid, pkgbase_id):
self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
self._to = get_user_email(conn, uid)
def get_recipients(self):
return [self._to]
def get_subject(self):
return 'AUR Co-Maintainer Notification for %s' % (self._pkgbase)
def get_refs(self):
return (aur_location + '/pkgbase/' + self._pkgbase + '/',)
class ComaintainerAddNotification(ComaintainershipEventNotification):
def get_body(self):
return 'You were added to the co-maintainer list of %s [1].' % \
(self._pkgbase)
class ComaintainerRemoveNotification(ComaintainershipEventNotification):
def get_body(self):
return 'You were removed from the co-maintainer list of %s [1].' % \
(self._pkgbase)
class DeleteNotification(Notification):
def __init__(self, conn, uid, old_pkgbase_id, new_pkgbase_id=None):
self._user = username_from_id(conn, uid)
self._old_pkgbase = pkgbase_from_id(conn, old_pkgbase_id)
if new_pkgbase_id:
self._new_pkgbase = pkgbase_from_id(conn, new_pkgbase_id)
else:
self._new_pkgbase = None
cur = conn.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'PackageNotifications.UserID != ? AND ' +
'PackageNotifications.PackageBaseID = ?',
[uid, old_pkgbase_id])
self._to = [row[0] for row in cur.fetchall()]
def get_recipients(self):
return self._to
def get_subject(self):
return 'AUR Package deleted: %s' % (self._old_pkgbase)
def get_body(self):
if self._new_pkgbase:
return '%s [1] merged %s [2] into %s [3].\n\n' \
'If you no longer wish receive notifications about the ' \
'new package, please go to [3] and click "%s".' % \
(self._user, self._old_pkgbase, self._new_pkgbase,
'Disable notifications')
else:
return '%s [1] deleted %s [2].\n\n' \
'You will no longer receive notifications about this ' \
'package.' % (self._user, self._old_pkgbase)
def get_refs(self):
refs = (aur_location + '/account/' + self._user + '/',
aur_location + '/pkgbase/' + self._old_pkgbase + '/')
if self._new_pkgbase:
refs += (aur_location + '/pkgbase/' + self._new_pkgbase + '/',)
return refs
class RequestOpenNotification(Notification):
def __init__(self, conn, uid, reqid, reqtype, pkgbase_id, merge_into=None):
self._user = username_from_id(conn, uid)
self._pkgbase = pkgbase_from_id(conn, pkgbase_id)
cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' +
'INNER JOIN PackageBases ' +
'ON PackageBases.ID = PackageRequests.PackageBaseID ' +
'INNER JOIN Users ' +
'ON Users.ID = PackageRequests.UsersID ' +
'OR Users.ID = PackageBases.MaintainerUID ' +
'WHERE PackageRequests.ID = ?', [reqid])
self._to = aurweb.config.get('options', 'aur_request_ml')
self._cc = [row[0] for row in cur.fetchall()]
cur = conn.execute('SELECT Comments FROM PackageRequests WHERE ID = ?',
[reqid])
self._text = cur.fetchone()[0]
self._reqid = int(reqid)
self._reqtype = reqtype
self._merge_into = merge_into
def get_recipients(self):
return [self._to]
def get_subject(self):
return '[PRQ#%d] %s Request for %s' % \
(self._reqid, self._reqtype.title(), self._pkgbase)
def get_body(self):
if self._merge_into:
body = '%s [1] filed a request to merge %s [2] into %s [3]:' % \
(self._user, self._pkgbase, self._merge_into)
body += '\n\n' + self._text
else:
body = '%s [1] filed a %s request for %s [2]:' % \
(self._user, self._reqtype, self._pkgbase)
body += '\n\n' + self._text
return body
def get_refs(self):
refs = (aur_location + '/account/' + self._user + '/',
aur_location + '/pkgbase/' + self._pkgbase + '/')
if self._merge_into:
refs += (aur_location + '/pkgbase/' + self._merge_into + '/',)
return refs
def get_headers(self):
thread_id = '<pkg-request-' + str(self._reqid) + '@aur.archlinux.org>'
# Use a deterministic Message-ID for the first email referencing a
# request.
headers = headers_msgid(thread_id)
headers.update(headers_cc(self._cc))
return headers
class RequestCloseNotification(Notification):
def __init__(self, conn, uid, reqid, reason):
self._user = username_from_id(conn, uid) if int(uid) else None
cur = conn.execute('SELECT DISTINCT Users.Email FROM PackageRequests ' +
'INNER JOIN PackageBases ' +
'ON PackageBases.ID = PackageRequests.PackageBaseID ' +
'INNER JOIN Users ' +
'ON Users.ID = PackageRequests.UsersID ' +
'OR Users.ID = PackageBases.MaintainerUID ' +
'WHERE PackageRequests.ID = ?', [reqid])
self._to = aurweb.config.get('options', 'aur_request_ml')
self._cc = [row[0] for row in cur.fetchall()]
cur = conn.execute('SELECT ClosureComment FROM PackageRequests ' +
'WHERE ID = ?', [reqid])
self._text = cur.fetchone()[0]
self._reqid = int(reqid)
self._reason = reason
def get_recipients(self):
return [self._to]
def get_subject(self):
return '[PRQ#%d] Request %s' % (self._reqid, self._reason.title())
def get_body(self):
if self._user:
body = 'Request #%d has been %s by %s [1]' % \
(self._reqid, self._reason, self._user)
else:
body = 'Request #%d has been %s automatically by the Arch User ' \
'Repository package request system' % \
(self._reqid, self._reason)
if self._text.strip() == '':
body += '.'
else:
body += ':\n\n' + self._text
return body
def get_refs(self):
if self._user:
return (aur_location + '/account/' + self._user + '/',)
else:
return ()
def get_headers(self):
thread_id = '<pkg-request-' + str(self._reqid) + '@aur.archlinux.org>'
headers = headers_reply(thread_id)
headers.update(headers_cc(self._cc))
return headers
class TUVoteReminderNotification(Notification):
def __init__(self, conn, vote_id):
self._vote_id = int(vote_id)
cur = conn.execute('SELECT Email FROM Users ' +
'WHERE AccountTypeID IN (2, 4) AND ID NOT IN ' +
'(SELECT UserID FROM TU_Votes ' +
'WHERE TU_Votes.VoteID = ?)', [vote_id])
self._to = [row[0] for row in cur.fetchall()]
def get_recipients(self):
return self._to
def get_subject(self):
return 'TU Vote Reminder: Proposal %d' % (self._vote_id)
def get_body(self):
return 'Please remember to cast your vote on proposal %d [1]. ' \
'The voting period ends in less than 48 hours.' % \
(self._vote_id)
def get_refs(self):
return (aur_location + '/tu/?id=' + str(self._vote_id),)
def main():
action = sys.argv[1]
action_map = {
'send-resetkey': send_resetkey,
'welcome': welcome,
'comment': comment,
'update': update,
'flag': flag,
'adopt': adopt,
'disown': disown,
'comaintainer-add': comaintainer_add,
'comaintainer-remove': comaintainer_remove,
'delete': delete,
'request-open': request_open,
'request-close': request_close,
'tu-vote-reminder': tu_vote_reminder,
'send-resetkey': ResetKeyNotification,
'welcome': WelcomeNotification,
'comment': CommentNotification,
'update': UpdateNotification,
'flag': FlagNotification,
'adopt': AdoptNotification,
'disown': DisownNotification,
'comaintainer-add': ComaintainerAddNotification,
'comaintainer-remove': ComaintainerRemoveNotification,
'delete': DeleteNotification,
'request-open': RequestOpenNotification,
'request-close': RequestCloseNotification,
'tu-vote-reminder': TUVoteReminderNotification,
}
conn = aurweb.db.Connection()
action_map[action](conn, *sys.argv[2:])
notification = action_map[action](conn, *sys.argv[2:])
notification.send()
conn.commit()
conn.close()