Commit 64072461 authored by Lukas Fleischer's avatar Lukas Fleischer
Browse files

Add support for package update notifications



Introduce a new notification option to receive notifications when a new
commit is pushed to a package repository.

Implements FS#30109.

Signed-off-by: Lukas Fleischer's avatarLukas Fleischer <lfleischer@archlinux.org>
parent aa5e58db
...@@ -5,6 +5,7 @@ import mysql.connector ...@@ -5,6 +5,7 @@ import mysql.connector
import os import os
import pygit2 import pygit2
import re import re
import subprocess
import sys import sys
import srcinfo.parse import srcinfo.parse
...@@ -19,6 +20,8 @@ aur_db_user = config.get('database', 'user') ...@@ -19,6 +20,8 @@ aur_db_user = config.get('database', 'user')
aur_db_pass = config.get('database', 'password') aur_db_pass = config.get('database', 'password')
aur_db_socket = config.get('database', 'socket') aur_db_socket = config.get('database', 'socket')
notify_cmd = config.get('notifications', 'notify-cmd')
repo_path = config.get('serve', 'repo-path') repo_path = config.get('serve', 'repo-path')
repo_regex = config.get('serve', 'repo-regex') repo_regex = config.get('serve', 'repo-regex')
...@@ -169,6 +172,13 @@ def save_metadata(metadata, db, cur, user): ...@@ -169,6 +172,13 @@ def save_metadata(metadata, db, cur, user):
db.commit() db.commit()
def update_notify(db, cur, user, pkgbase_id):
# Obtain the user ID of the new maintainer.
cur.execute("SELECT ID FROM Users WHERE Username = %s", [user])
user_id = int(cur.fetchone()[0])
# Execute the notification script.
subprocess.Popen((notify_cmd, 'update', str(user_id), str(pkgbase_id)))
def die(msg): def die(msg):
sys.stderr.write("error: {:s}\n".format(msg)) sys.stderr.write("error: {:s}\n".format(msg))
...@@ -336,8 +346,6 @@ for pkgname in srcinfo.utils.get_package_names(metadata): ...@@ -336,8 +346,6 @@ for pkgname in srcinfo.utils.get_package_names(metadata):
# Store package base details in the database. # Store package base details in the database.
save_metadata(metadata, db, cur, user) save_metadata(metadata, db, cur, user)
db.close()
# Create (or update) a branch with the name of the package base for better # Create (or update) a branch with the name of the package base for better
# accessibility. # accessibility.
repo.create_reference('refs/heads/' + pkgbase, sha1_new, True) repo.create_reference('refs/heads/' + pkgbase, sha1_new, True)
...@@ -347,3 +355,9 @@ repo.create_reference('refs/heads/' + pkgbase, sha1_new, True) ...@@ -347,3 +355,9 @@ repo.create_reference('refs/heads/' + pkgbase, sha1_new, True)
# http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html # http://git.661346.n2.nabble.com/PATCH-receive-pack-Create-a-HEAD-ref-for-ref-namespace-td7632149.html
# for details. # for details.
repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', sha1_new, True) repo.create_reference('refs/namespaces/' + pkgbase + '/HEAD', sha1_new, True)
# Send package update notifications.
update_notify(db, cur, user, pkgbase_id)
# Close the database.
db.close()
...@@ -39,6 +39,7 @@ CREATE TABLE Users ( ...@@ -39,6 +39,7 @@ CREATE TABLE Users (
InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0, InactivityTS BIGINT UNSIGNED NOT NULL DEFAULT 0,
RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, RegistrationTS TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CommentNotify TINYINT(1) NOT NULL DEFAULT 1, CommentNotify TINYINT(1) NOT NULL DEFAULT 1,
UpdateNotify TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (ID), PRIMARY KEY (ID),
UNIQUE (Username), UNIQUE (Username),
UNIQUE (Email), UNIQUE (Email),
......
...@@ -105,6 +105,16 @@ def get_comment_recipients(cur, pkgbase_id, uid): ...@@ -105,6 +105,16 @@ def get_comment_recipients(cur, pkgbase_id, uid):
return [row[0] for row in cur.fetchall()] return [row[0] for row in cur.fetchall()]
def get_update_recipients(cur, pkgbase_id, uid):
cur.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageNotifications ' +
'ON PackageNotifications.UserID = Users.ID WHERE ' +
'Users.UpdateNotify = 1 AND ' +
'PackageNotifications.UserID != %s AND ' +
'PackageNotifications.PackageBaseID = %s', [uid, pkgbase_id])
return [row[0] for row in cur.fetchall()]
def get_request_recipients(cur, pkgbase_id, uid): def get_request_recipients(cur, pkgbase_id, uid):
cur.execute('SELECT DISTINCT Users.Email FROM Users ' + cur.execute('SELECT DISTINCT Users.Email FROM Users ' +
'INNER JOIN PackageBases ' + 'INNER JOIN PackageBases ' +
...@@ -189,6 +199,28 @@ def comment(cur, uid, pkgbase_id, comment_id): ...@@ -189,6 +199,28 @@ def comment(cur, uid, pkgbase_id, comment_id):
send_notification(to, subject, body, refs, headers) send_notification(to, subject, body, refs, headers)
def update(cur, uid, pkgbase_id):
user = username_from_id(cur, uid)
pkgbase = pkgbase_from_id(cur, pkgbase_id)
to = get_update_recipients(cur, 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(cur, uid, pkgbase_id): def flag(cur, uid, pkgbase_id):
user = username_from_id(cur, uid) user = username_from_id(cur, uid)
pkgbase = pkgbase_from_id(cur, pkgbase_id) pkgbase = pkgbase_from_id(cur, pkgbase_id)
...@@ -327,6 +359,7 @@ if __name__ == '__main__': ...@@ -327,6 +359,7 @@ if __name__ == '__main__':
'send-resetkey': send_resetkey, 'send-resetkey': send_resetkey,
'welcome': welcome, 'welcome': welcome,
'comment': comment, 'comment': comment,
'update': update,
'flag': flag, 'flag': flag,
'comaintainer-add': comaintainer_add, 'comaintainer-add': comaintainer_add,
'comaintainer-remove': comaintainer_remove, 'comaintainer-remove': comaintainer_remove,
......
...@@ -52,5 +52,6 @@ ALTER TABLE CommentNotify RENAME TO PackageNotifications; ...@@ -52,5 +52,6 @@ ALTER TABLE CommentNotify RENAME TO PackageNotifications;
---- ----
ALTER TABLE Users ALTER TABLE Users
ADD COLUMN CommentNotify TINYINT(1) NOT NULL DEFAULT 1; ADD COLUMN CommentNotify TINYINT(1) NOT NULL DEFAULT 1,
ADD COLUMN UpdateNotify TINYINT(1) NOT NULL DEFAULT 0;
---- ----
...@@ -35,8 +35,8 @@ if ($action == "UpdateAccount") { ...@@ -35,8 +35,8 @@ if ($action == "UpdateAccount") {
in_request("E"), in_request("H"), in_request("P"), in_request("E"), in_request("H"), in_request("P"),
in_request("C"), in_request("R"), in_request("L"), in_request("C"), in_request("R"), in_request("L"),
in_request("I"), in_request("K"), in_request("PK"), in_request("I"), in_request("K"), in_request("PK"),
in_request("J"), in_request("CN"), in_request("ID"), in_request("J"), in_request("CN"), in_request("UN"),
$row["Username"]); in_request("ID"), $row["Username"]);
} }
} }
...@@ -83,7 +83,7 @@ if (isset($_COOKIE["AURSID"])) { ...@@ -83,7 +83,7 @@ if (isset($_COOKIE["AURSID"])) {
$row["HideEmail"], "", "", $row["RealName"], $row["HideEmail"], "", "", $row["RealName"],
$row["LangPreference"], $row["IRCNick"], $row["PGPKey"], $PK, $row["LangPreference"], $row["IRCNick"], $row["PGPKey"], $PK,
$row["InactivityTS"] ? 1 : 0, $row["CommentNotify"], $row["InactivityTS"] ? 1 : 0, $row["CommentNotify"],
$row["ID"], $row["Username"]); $row["UpdateNotify"], $row["ID"], $row["Username"]);
} else { } else {
print __("You do not have permission to edit this account."); print __("You do not have permission to edit this account.");
} }
...@@ -123,8 +123,8 @@ if (isset($_COOKIE["AURSID"])) { ...@@ -123,8 +123,8 @@ if (isset($_COOKIE["AURSID"])) {
in_request("R"), in_request("L"), in_request("R"), in_request("L"),
in_request("I"), in_request("K"), in_request("I"), in_request("K"),
in_request("PK"), in_request("J"), in_request("PK"), in_request("J"),
in_request("CN"), in_request("ID"), in_request("CN"), in_request("UN"),
$row["Username"]); in_request("ID"), $row["Username"]);
} }
} else { } else {
......
...@@ -23,7 +23,7 @@ if (in_request("Action") == "NewAccount") { ...@@ -23,7 +23,7 @@ if (in_request("Action") == "NewAccount") {
"new", "NewAccount", in_request("U"), 1, 0, "new", "NewAccount", in_request("U"), 1, 0,
in_request("E"), in_request("H"), '', '', in_request("R"), in_request("E"), in_request("H"), '', '', in_request("R"),
in_request("L"), in_request("I"), in_request("K"), in_request("L"), in_request("I"), in_request("K"),
in_request("PK"), 0, in_request("CN")); in_request("PK"), 0, in_request("CN"), in_request("UN"));
print $message; print $message;
...@@ -31,7 +31,7 @@ if (in_request("Action") == "NewAccount") { ...@@ -31,7 +31,7 @@ if (in_request("Action") == "NewAccount") {
display_account_form("NewAccount", in_request("U"), 1, 0, display_account_form("NewAccount", in_request("U"), 1, 0,
in_request("E"), in_request("H"), '', '', in_request("R"), in_request("E"), in_request("H"), '', '', in_request("R"),
in_request("L"), in_request("I"), in_request("K"), in_request("L"), in_request("I"), in_request("K"),
in_request("PK"), 0, in_request("CN")); in_request("PK"), 0, in_request("CN"), in_request("UN"));
} }
} else { } else {
print '<p>' . __("Use this form to create an account.") . '</p>'; print '<p>' . __("Use this form to create an account.") . '</p>';
......
...@@ -57,13 +57,14 @@ function html_format_pgp_fingerprint($fingerprint) { ...@@ -57,13 +57,14 @@ function html_format_pgp_fingerprint($fingerprint) {
* @param string $PK The list of SSH public keys * @param string $PK The list of SSH public keys
* @param string $J The inactivity status of the displayed user * @param string $J The inactivity status of the displayed user
* @param string $CN Whether to notify of new comments * @param string $CN Whether to notify of new comments
* @param string $UN Whether to notify of package updates
* @param string $UID The user ID of the displayed user * @param string $UID The user ID of the displayed user
* @param string $N The username as present in the database * @param string $N The username as present in the database
* *
* @return void * @return void
*/ */
function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="", function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="",
$L="",$I="",$K="",$PK="",$J="",$CN="",$UID=0,$N="") { $L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$UID=0,$N="") {
global $SUPPORTED_LANGS; global $SUPPORTED_LANGS;
include("account_edit_form.php"); include("account_edit_form.php");
...@@ -90,13 +91,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R="" ...@@ -90,13 +91,14 @@ function display_account_form($A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",$R=""
* @param string $PK The list of public SSH keys * @param string $PK The list of public SSH keys
* @param string $J The inactivity status of the user * @param string $J The inactivity status of the user
* @param string $CN Whether to notify of new comments * @param string $CN Whether to notify of new comments
* @param string $UN Whether to notify of package updates
* @param string $UID The user ID of the modified account * @param string $UID The user ID of the modified account
* @param string $N The username as present in the database * @param string $N The username as present in the database
* *
* @return array Boolean indicating success and message to be printed * @return array Boolean indicating success and message to be printed
*/ */
function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="", function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="",
$R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UID=0,$N="") { $R="",$L="",$I="",$K="",$PK="",$J="",$CN="",$UN="",$UID=0,$N="") {
global $SUPPORTED_LANGS; global $SUPPORTED_LANGS;
$error = ''; $error = '';
...@@ -344,6 +346,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C="" ...@@ -344,6 +346,7 @@ function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="",$H="",$P="",$C=""
$q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K)); $q.= ", PGPKey = " . $dbh->quote(str_replace(" ", "", $K));
$q.= ", InactivityTS = " . $inactivity_ts; $q.= ", InactivityTS = " . $inactivity_ts;
$q.= ", CommentNotify = " . ($CN ? "1" : "0"); $q.= ", CommentNotify = " . ($CN ? "1" : "0");
$q.= ", UpdateNotify = " . ($UN ? "1" : "0");
$q.= " WHERE ID = ".intval($UID); $q.= " WHERE ID = ".intval($UID);
$result = $dbh->exec($q); $result = $dbh->exec($q);
......
...@@ -139,6 +139,10 @@ ...@@ -139,6 +139,10 @@
<label for="id_commentnotify"><?= __("Notify of new comments") ?>:</label> <label for="id_commentnotify"><?= __("Notify of new comments") ?>:</label>
<input type="checkbox" name="CN" id="id_commentnotify" <?= $CN ? 'checked="checked"' : '' ?> /> <input type="checkbox" name="CN" id="id_commentnotify" <?= $CN ? 'checked="checked"' : '' ?> />
</p> </p>
<p>
<label for="id_updatenotify"><?= __("Notify of package updates") ?>:</label>
<input type="checkbox" name="UN" id="id_updatenotify" <?= $UN ? 'checked="checked"' : '' ?> />
</p>
</fieldset> </fieldset>
<fieldset> <fieldset>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment