[aur-dev] [PATCH v2] Add support for package base co-maintainers

Lukas Fleischer archlinux at cryptocrack.de
Wed Jan 7 11:33:32 UTC 2015


This allows for having multiple co-maintainers for AUR packages.
Co-maintainers have push access to the package base Git repository but
are not allowed to change the package base category, disown the package
or modify the list of co-maintainers. The primary maintainer of an AUR
package can edit the list of co-maintainers from the Package Actions
box.

Implements FS#17911.

Signed-off-by: Lukas Fleischer <archlinux at cryptocrack.de>
---
 schema/aur-schema.sql                 | 11 ++++++
 scripts/git-integration/git-serve.py  | 11 +++---
 scripts/git-integration/git-update.py |  8 +++--
 upgrading/4.0.0.txt                   | 15 +++++++-
 web/html/comaintainers.php            | 21 ++++++++++++
 web/html/index.php                    |  3 ++
 web/html/pkgbase.php                  |  4 ++-
 web/lib/credentials.inc.php           |  2 ++
 web/lib/pkgbasefuncs.inc.php          | 64 +++++++++++++++++++++++++++++++++++
 web/template/comaintainers_form.php   | 20 +++++++++++
 web/template/pkg_details.php          |  3 ++
 web/template/pkgbase_details.php      |  3 ++
 12 files changed, 156 insertions(+), 9 deletions(-)
 create mode 100644 web/html/comaintainers.php
 create mode 100644 web/template/comaintainers_form.php

diff --git a/schema/aur-schema.sql b/schema/aur-schema.sql
index dfd158f..9c647d8 100644
--- a/schema/aur-schema.sql
+++ b/schema/aur-schema.sql
@@ -276,6 +276,17 @@ CREATE TABLE PackageComments (
 	FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE
 ) ENGINE = InnoDB;
 
+-- Package base co-maintainers
+--
+CREATE TABLE PackageComaintainers (
+	UsersID INTEGER UNSIGNED NOT NULL,
+	PackageBaseID INTEGER UNSIGNED NOT NULL,
+	INDEX (UsersID),
+	INDEX (PackageBaseID),
+	FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE,
+	FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE
+) ENGINE = InnoDB;
+
 -- Comment addition notifications
 --
 CREATE TABLE CommentNotify (
diff --git a/scripts/git-integration/git-serve.py b/scripts/git-integration/git-serve.py
index a1c6e3a..d551dba 100755
--- a/scripts/git-integration/git-serve.py
+++ b/scripts/git-integration/git-serve.py
@@ -92,10 +92,13 @@ def check_permissions(pkgbase, user):
                                  unix_socket=aur_db_socket, buffered=True)
     cur = db.cursor()
 
-    cur.execute("SELECT COUNT(*) FROM PackageBases INNER JOIN Users " +
-                "ON Users.ID = PackageBases.MaintainerUID OR " +
-                "PackageBases.MaintainerUID IS NULL WHERE " +
-                "Name = %s AND Username = %s", [pkgbase, user])
+    cur.execute("SELECT COUNT(*) FROM PackageBases " +
+                "LEFT JOIN PackageComaintainers " +
+                "ON PackageComaintainers.PackageBaseID = PackageBases.ID " +
+                "INNER JOIN Users ON Users.ID = PackageBases.MaintainerUID " +
+                "OR PackageBases.MaintainerUID IS NULL " +
+                "OR Users.ID = PackageComaintainers.UsersID " +
+                "WHERE Name = %s AND Username = %s", [pkgbase, user])
     return cur.fetchone()[0] > 0
 
 def die(msg):
diff --git a/scripts/git-integration/git-update.py b/scripts/git-integration/git-update.py
index 1ff09b8..b20c0a2 100755
--- a/scripts/git-integration/git-update.py
+++ b/scripts/git-integration/git-update.py
@@ -47,9 +47,11 @@ def save_srcinfo(srcinfo, db, cur, user):
 
     # Update package base details and delete current packages.
     cur.execute("UPDATE PackageBases SET ModifiedTS = UNIX_TIMESTAMP(), " +
-                "MaintainerUID = %s, PackagerUID = %s, " +
-                "OutOfDateTS = NULL WHERE ID = %s",
-                [user_id, user_id, pkgbase_id])
+                "PackagerUID = %s, OutOfDateTS = NULL WHERE ID = %s",
+                [user_id, pkgbase_id])
+    cur.execute("UPDATE PackageBases SET MaintainerUID = %s " +
+                "WHERE ID = %s AND MaintainerUID IS NULL",
+                [user_id, pkgbase_id])
     cur.execute("DELETE FROM Packages WHERE PackageBaseID = %s",
                 [pkgbase_id])
 
diff --git a/upgrading/4.0.0.txt b/upgrading/4.0.0.txt
index f990c37..b1582f2 100644
--- a/upgrading/4.0.0.txt
+++ b/upgrading/4.0.0.txt
@@ -16,4 +16,17 @@ init-repos.py to initialize them.
 UPDATE PackageBases SET PackagerUID = NULL;
 ----
 
-5. (optional) Setup cgit to browse the Git repositories via HTTP.
+5. Create a new table for package base co-maintainers:
+
+----
+CREATE TABLE PackageComaintainers (
+	UsersID INTEGER UNSIGNED NOT NULL,
+	PackageBaseID INTEGER UNSIGNED NOT NULL,
+	INDEX (UsersID),
+	INDEX (PackageBaseID),
+	FOREIGN KEY (UsersID) REFERENCES Users(ID) ON DELETE CASCADE,
+	FOREIGN KEY (PackageBaseID) REFERENCES PackageBases(ID) ON DELETE CASCADE
+) ENGINE = InnoDB;
+----
+
+6. (optional) Setup cgit to browse the Git repositories via HTTP.
diff --git a/web/html/comaintainers.php b/web/html/comaintainers.php
new file mode 100644
index 0000000..591fcad
--- /dev/null
+++ b/web/html/comaintainers.php
@@ -0,0 +1,21 @@
+<?php
+
+set_include_path(get_include_path() . PATH_SEPARATOR . '../lib');
+
+include_once("aur.inc.php");
+include_once("pkgbasefuncs.inc.php");
+
+set_lang();
+check_sid();
+
+if (!isset($base_id) || !has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) {
+	header('Location: /');
+	exit();
+}
+
+html_header(__("Manage Co-maintainers"));
+$users = pkgbase_get_comaintainers($base_id);
+include('comaintainers_form.php');
+html_footer(AUR_VERSION);
+
+
diff --git a/web/html/index.php b/web/html/index.php
index 9c321fa..cfd6598 100644
--- a/web/html/index.php
+++ b/web/html/index.php
@@ -78,6 +78,9 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) {
 			case "request":
 				include('pkgreq.php');
 				return;
+			case "comaintainers":
+				include('comaintainers.php');
+				return;
 			default:
 				header("HTTP/1.0 404 Not Found");
 				include "./404.php";
diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php
index bdce516..201749e 100644
--- a/web/html/pkgbase.php
+++ b/web/html/pkgbase.php
@@ -97,6 +97,8 @@ if (check_token()) {
 		list($ret, $output) = pkgreq_file($ids, $_POST['type'], $_POST['merge_into'], $_POST['comments']);
 	} elseif (current_action("do_CloseRequest")) {
 		list($ret, $output) = pkgreq_close($_POST['reqid'], $_POST['reason'], $_POST['comments']);
+	} elseif (current_action("do_EditComaintainers")) {
+		list($ret, $output) = pkgbase_set_comaintainers($base_id, explode("\n", $_POST['users']));
 	}
 
 	if (isset($_REQUEST['comment'])) {
@@ -124,7 +126,7 @@ if (check_token()) {
 }
 
 $pkgs = pkgbase_get_pkgnames($base_id);
-if (count($pkgs) == 1) {
+if (!$output && count($pkgs) == 1) {
 	/* Not a split package. Redirect to the package page. */
 	if (empty($_SERVER['QUERY_STRING'])) {
 		header('Location: ' . get_pkg_uri($pkgs[0]));
diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php
index 6c70ede..b813b90 100644
--- a/web/lib/credentials.inc.php
+++ b/web/lib/credentials.inc.php
@@ -11,6 +11,7 @@ define("CRED_PKGBASE_ADOPT", 7);
 define("CRED_PKGBASE_CHANGE_CATEGORY", 8);
 define("CRED_PKGBASE_DELETE", 9);
 define("CRED_PKGBASE_DISOWN", 10);
+define("CRED_PKGBASE_EDIT_COMAINTAINERS", 24);
 define("CRED_PKGBASE_FLAG", 11);
 define("CRED_PKGBASE_LIST_VOTERS", 12);
 define("CRED_PKGBASE_NOTIFY", 13);
@@ -61,6 +62,7 @@ function has_credential($credential, $approved_users=array()) {
 	case CRED_PKGBASE_ADOPT:
 	case CRED_PKGBASE_CHANGE_CATEGORY:
 	case CRED_PKGBASE_DELETE:
+	case CRED_PKGBASE_EDIT_COMAINTAINERS:
 	case CRED_PKGBASE_DISOWN:
 	case CRED_PKGBASE_LIST_VOTERS:
 	case CRED_PKGBASE_SUBMIT_BLACKLISTED:
diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php
index 655856b..5741b01 100644
--- a/web/lib/pkgbasefuncs.inc.php
+++ b/web/lib/pkgbasefuncs.inc.php
@@ -928,3 +928,67 @@ function pkgbase_update_category($base_id, $category_id) {
 		$category_id, $base_id);
 	$dbh->exec($q);
 }
+
+/**
+ * Get a list of package base co-maintainers
+ *
+ * @param int $base_id The package base ID to retrieve the co-maintainers for
+ *
+ * @return array An array of co-maintainer user names
+ */
+function pkgbase_get_comaintainers($base_id) {
+	$dbh = DB::connect();
+	$q = "SELECT UserName FROM PackageComaintainers ";
+	$q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID ";
+	$q .= "WHERE PackageComaintainers.PackageBaseID = " . intval($base_id);
+	$result = $dbh->query($q);
+
+	if ($result) {
+		return $result->fetchAll(PDO::FETCH_COLUMN, 0);
+	} else {
+		return array();
+	}
+}
+
+/**
+ * Update the list of co-maintainers of a package base
+ *
+ * @param int $base_id The package base ID to update the co-maintainers of
+ * @param array $users Array of co-maintainer user names
+ *
+ * @return array Tuple of success/failure indicator and error message
+ */
+function pkgbase_set_comaintainers($base_id, $users) {
+	if (!has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) {
+		return array(false, __("You are not allowed to manage co-maintainers of this package base."));
+	}
+
+	/* Remove empty and duplicate user names. */
+	$users = array_unique(array_filter(array_map('trim', $users)));
+
+	$dbh = DB::connect();
+
+	$uids = array();
+	foreach($users as $user) {
+		$q = "SELECT ID FROM Users ";
+		$q .= "WHERE UserName = " . $dbh->quote($user);
+		$result = $dbh->query($q);
+		$uid = $result->fetchColumn(0);
+
+		if (!$uid) {
+			return array(false, __("Invalid user name: %s", $user));
+		}
+
+		$uids[] = $uid;
+	}
+
+	$q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id);
+	$dbh->exec($q);
+
+	foreach ($uids as $uid) {
+		$q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID) VALUES (%d, %d)", $base_id, $uid);
+		$dbh->exec($q);
+	}
+
+	return array(true, __("The package base co-maintainers have been updated."));
+}
diff --git a/web/template/comaintainers_form.php b/web/template/comaintainers_form.php
new file mode 100644
index 0000000..050f255
--- /dev/null
+++ b/web/template/comaintainers_form.php
@@ -0,0 +1,20 @@
+<div class="box">
+	<h2><?= __('Manage Co-maintainers: %s', htmlspecialchars($pkgbase_name)) ?></h2>
+	<p>
+		<?= __('Use this form to add co-maintainers for %s%s%s (one user name per line):',
+			'<strong>', htmlspecialchars($pkgbase_name), '</strong>'); ?>
+	</p>
+	<form action="<?= get_pkgbase_uri($pkgbase_name); ?>" method="post">
+		<fieldset>
+			<input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" />
+			<p>
+				<label for="id_users"><?= __("Users") ?>:</label>
+				<textarea name="users" id="id_users" rows="5" cols="50"><?= htmlspecialchars(implode("\n", $users)) ?></textarea>
+			</p>
+			<p>
+				<input type="submit" class="button" name="do_EditComaintainers" value="<?= __("Save") ?>" />
+			</p>
+		</fieldset>
+	</form>
+</div>
+
diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php
index ecb081c..359ea3c 100644
--- a/web/template/pkg_details.php
+++ b/web/template/pkg_details.php
@@ -131,6 +131,9 @@ $sources = pkg_sources($row["ID"]);
 					</form>
 				</li>
 				<?php endif; ?>
+				<?php if (has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array($row["MaintainerUID"]))): ?>
+				<li><a href="<?= get_pkgbase_uri($row['BaseName']) . 'comaintainers/'; ?>"><?= __('Manage Co-Maintainers'); ?></a></li>
+				<?php endif; ?>
 				<li><span class="flagged"><?php if ($row["RequestCount"] > 0) { echo _n('%d pending request', '%d pending requests', $row["RequestCount"]); } ?></span></li>
 				<li><a href="<?= get_pkgbase_uri($row['BaseName']) . 'request/'; ?>"><?= __('File Request'); ?></a></li>
 				<?php if (has_credential(CRED_PKGBASE_DELETE)): ?>
diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php
index e698fb0..ae363fd 100644
--- a/web/template/pkgbase_details.php
+++ b/web/template/pkgbase_details.php
@@ -82,6 +82,9 @@ $pkgs = pkgbase_get_pkgnames($base_id);
 					</form>
 				</li>
 				<?php endif; ?>
+				<?php if (has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array($row["MaintainerUID"]))): ?>
+				<li><a href="<?= get_pkgbase_uri($row['Name']) . 'comaintainers/'; ?>"><?= __('Manage Co-Maintainers'); ?></a></li>
+				<?php endif; ?>
 				<li><span class="flagged"><?php if ($row["RequestCount"] > 0) { echo _n('%d pending request', '%d pending requests', $row["RequestCount"]); } ?></span></li>
 				<li><a href="<?= get_pkgbase_uri($row['Name']) . 'request/'; ?>"><?= __('File Request'); ?></a></li>
 				<?php if (has_credential(CRED_PKGBASE_DELETE)): ?>
-- 
2.2.1


More information about the aur-dev mailing list