diff options
author | Lukas Fleischer <archlinux@cryptocrack.de> | 2014-07-15 20:52:54 +0200 |
---|---|---|
committer | Lukas Fleischer <archlinux@cryptocrack.de> | 2014-07-15 22:56:57 +0200 |
commit | 03c6304e19d5d3ecd276dd3f42220db301ab511d (patch) | |
tree | 25f58ac23290a9e57f6bd93f6b5c8986bd9fcbef | |
parent | 9e6b861b6f40a90363c402b4d26602f33964cf41 (diff) | |
download | aurweb-03c6304e19d5d3ecd276dd3f42220db301ab511d.tar.xz |
Rework permission handling
Add a new function has_credential() that checks whether the currently
logged in user is allowed to perform a given action. Moving all
permission handling to this central place makes adding new user groups
and adjusting permissions much more convenient.
Signed-off-by: Lukas Fleischer <archlinux@cryptocrack.de>
-rw-r--r-- | web/html/account.php | 20 | ||||
-rw-r--r-- | web/html/addvote.php | 7 | ||||
-rw-r--r-- | web/html/packages.php | 7 | ||||
-rw-r--r-- | web/html/pkgbase.php | 31 | ||||
-rw-r--r-- | web/html/pkgdel.php | 8 | ||||
-rw-r--r-- | web/html/pkgmerge.php | 8 | ||||
-rw-r--r-- | web/html/pkgreq.php | 2 | ||||
-rw-r--r-- | web/html/tu.php | 9 | ||||
-rw-r--r-- | web/html/voters.php | 3 | ||||
-rw-r--r-- | web/lib/acctfuncs.inc.php | 37 | ||||
-rw-r--r-- | web/lib/aur.inc.php | 11 | ||||
-rw-r--r-- | web/lib/credentials.inc.php | 76 | ||||
-rw-r--r-- | web/lib/pkgbasefuncs.inc.php | 93 | ||||
-rw-r--r-- | web/lib/pkgfuncs.inc.php | 36 | ||||
-rw-r--r-- | web/lib/pkgreqfuncs.inc.php | 2 | ||||
-rw-r--r-- | web/template/account_details.php | 4 | ||||
-rw-r--r-- | web/template/account_edit_form.php | 7 | ||||
-rw-r--r-- | web/template/account_search_results.php | 11 | ||||
-rw-r--r-- | web/template/actions_form.php | 5 | ||||
-rw-r--r-- | web/template/header.php | 6 | ||||
-rw-r--r-- | web/template/pkg_comments.php | 3 | ||||
-rw-r--r-- | web/template/pkg_details.php | 14 | ||||
-rw-r--r-- | web/template/pkg_search_results.php | 10 | ||||
-rw-r--r-- | web/template/pkgbase_details.php | 14 |
24 files changed, 187 insertions, 237 deletions
diff --git a/web/html/account.php b/web/html/account.php index 47cf6d2..f212eab 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -18,18 +18,14 @@ echo " <h2>".__("Accounts")."</h2>\n"; $action = in_request("Action"); if (isset($_COOKIE["AURSID"])) { - # visitor is logged in - # - $atype = account_from_sid($_COOKIE["AURSID"]); - if ($action == "SearchAccounts") { # security check # - if ($atype == "Trusted User" || $atype == "Developer") { + if (has_credential(CRED_ACCOUNT_SEARCH)) { # the user has entered search criteria, find any matching accounts # - search_results_page($atype, in_request("O"), in_request("SB"), + search_results_page(in_request("O"), in_request("SB"), in_request("U"), in_request("T"), in_request("S"), in_request("E"), in_request("R"), in_request("I"), in_request("K")); @@ -48,8 +44,8 @@ if (isset($_COOKIE["AURSID"])) { print __("Could not retrieve information for the specified user."); } else { /* Verify user has permission to edit the account */ - if (can_edit_account($atype, $row, uid_from_sid($_COOKIE["AURSID"]))) { - display_account_form($atype, "UpdateAccount", $row["Username"], + if (can_edit_account($row)) { + display_account_form("UpdateAccount", $row["Username"], $row["AccountTypeID"], $row["Suspended"], $row["Email"], "", "", $row["RealName"], $row["LangPreference"], $row["IRCNick"], $row["PGPKey"], @@ -70,22 +66,20 @@ if (isset($_COOKIE["AURSID"])) { } } elseif ($action == "UpdateAccount") { - $uid = uid_from_sid($_COOKIE['AURSID']); - /* Details for account being updated */ $acctinfo = account_details(in_request('ID'), in_request('U')); /* Verify user permissions and that the request is a valid POST */ - if (can_edit_account($atype, $acctinfo, $uid) && check_token()) { + if (can_edit_account($acctinfo) && check_token()) { /* Update the details for the existing account */ - process_account_form($atype, "edit", "UpdateAccount", + process_account_form("edit", "UpdateAccount", in_request("U"), in_request("T"), in_request("S"), in_request("E"), in_request("P"), in_request("C"), in_request("R"), in_request("L"), in_request("I"), in_request("K"), in_request("J"), in_request("ID")); } } else { - if ($atype == "Trusted User" || $atype == "Developer") { + if (has_credential(CRED_ACCOUNT_SEARCH)) { # display the search page if they're a TU/dev # print __("Use this form to search existing accounts.")."<br />\n"; diff --git a/web/html/addvote.php b/web/html/addvote.php index 3ce99c0..0b6b9c6 100644 --- a/web/html/addvote.php +++ b/web/html/addvote.php @@ -11,13 +11,10 @@ $title = __("Add Proposal"); html_header($title); if (isset($_COOKIE["AURSID"])) { - $atype = account_from_sid($_COOKIE["AURSID"]); - $uid = uid_from_sid($_COOKIE["AURSID"]); -} else { - $atype = ""; + $uid = uid_from_sid($_COOKIE["AURSID"]); } -if ($atype == "Trusted User" || $atype == "Developer") { +if (has_credential(CRED_TU_ADD_VOTE)) { if (!empty($_POST['addVote']) && !check_token()) { $error = __("Invalid token for user action."); diff --git a/web/html/packages.php b/web/html/packages.php index 2fb9cbc..645806e 100644 --- a/web/html/packages.php +++ b/web/html/packages.php @@ -35,13 +35,6 @@ if (isset($pkgname)) { $title = __("Packages"); } -# Retrieve account type -if (isset($_COOKIE["AURSID"])) { - $atype = account_from_sid($_COOKIE["AURSID"]); -} else { - $atype = ""; -} - $details = array(); if (isset($pkgname)) { $details = pkg_get_details($pkgid); diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cf2b774..4f35a67 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -32,13 +32,6 @@ if (!isset($base_id) || !isset($pkgbase_name)) { /* Set the title to package base name. */ $title = $pkgbase_name; -/* Retrieve account type. */ -if (isset($_COOKIE["AURSID"])) { - $atype = account_from_sid($_COOKIE["AURSID"]); -} else { - $atype = ""; -} - /* Grab the list of package base IDs to be operated on. */ $ids = array(); if (isset($_POST['IDs'])) { @@ -55,29 +48,29 @@ $ret = false; $output = ""; if (check_token()) { if (current_action("do_Flag")) { - list($ret, $output) = pkgbase_flag($atype, $ids); + list($ret, $output) = pkgbase_flag($ids); } elseif (current_action("do_UnFlag")) { - list($ret, $output) = pkgbase_unflag($atype, $ids); + list($ret, $output) = pkgbase_unflag($ids); } elseif (current_action("do_Adopt")) { - list($ret, $output) = pkgbase_adopt($atype, $ids, true, NULL); + list($ret, $output) = pkgbase_adopt($ids, true, NULL); } elseif (current_action("do_Disown")) { $via = isset($_POST['via']) ? $_POST['via'] : NULL; - list($ret, $output) = pkgbase_adopt($atype, $ids, false, $via); + list($ret, $output) = pkgbase_adopt($ids, false, $via); } elseif (current_action("do_Vote")) { - list($ret, $output) = pkgbase_vote($atype, $ids, true); + list($ret, $output) = pkgbase_vote($ids, true); } elseif (current_action("do_UnVote")) { - list($ret, $output) = pkgbase_vote($atype, $ids, false); + list($ret, $output) = pkgbase_vote($ids, false); } elseif (current_action("do_Delete")) { if (isset($_POST['confirm_Delete'])) { $via = isset($_POST['via']) ? $_POST['via'] : NULL; if (!isset($_POST['merge_Into']) || empty($_POST['merge_Into'])) { - list($ret, $output) = pkgbase_delete($atype, $ids, NULL, $via); + list($ret, $output) = pkgbase_delete($ids, NULL, $via); unset($_GET['ID']); } else { $merge_base_id = pkgbase_from_name($_POST['merge_Into']); if ($merge_base_id) { - list($ret, $output) = pkgbase_delete($atype, $ids, $merge_base_id, $via); + list($ret, $output) = pkgbase_delete($ids, $merge_base_id, $via); unset($_GET['ID']); } else { $output = __("Cannot find package to merge votes and comments into."); @@ -90,13 +83,13 @@ if (check_token()) { $ret = false; } } elseif (current_action("do_Notify")) { - list($ret, $output) = pkgbase_notify($atype, $ids); + list($ret, $output) = pkgbase_notify($ids); } elseif (current_action("do_UnNotify")) { - list($ret, $output) = pkgbase_notify($atype, $ids, false); + list($ret, $output) = pkgbase_notify($ids, false); } elseif (current_action("do_DeleteComment")) { - list($ret, $output) = pkgbase_delete_comment($atype); + list($ret, $output) = pkgbase_delete_comment(); } elseif (current_action("do_ChangeCategory")) { - list($ret, $output) = pkgbase_change_category($base_id, $atype); + list($ret, $output) = pkgbase_change_category($base_id); } elseif (current_action("do_FileRequest")) { list($ret, $output) = pkgreq_file($ids, $_POST['type'], $_POST['merge_into'], $_POST['comments']); } elseif (current_action("do_CloseRequest")) { diff --git a/web/html/pkgdel.php b/web/html/pkgdel.php index 621c3c9..41900e4 100644 --- a/web/html/pkgdel.php +++ b/web/html/pkgdel.php @@ -10,13 +10,7 @@ check_sid(); html_header(__("Package Deletion")); -$atype = ""; - -if (isset($_COOKIE["AURSID"])) { - $atype = account_from_sid($_COOKIE["AURSID"]); -} - -if ($atype == "Trusted User" || $atype == "Developer"): ?> +if (has_credential(CRED_PKGBASE_DELETE)): ?> <div class="box"> <h2><?= __('Delete Package: %s', htmlspecialchars($pkgbase_name)) ?></h2> <p> diff --git a/web/html/pkgmerge.php b/web/html/pkgmerge.php index ba3f742..6a3b3c5 100644 --- a/web/html/pkgmerge.php +++ b/web/html/pkgmerge.php @@ -10,13 +10,7 @@ check_sid(); html_header(__("Package Merging")); -$atype = ""; - -if (isset($_COOKIE["AURSID"])) { - $atype = account_from_sid($_COOKIE["AURSID"]); -} - -if ($atype == "Trusted User" || $atype == "Developer"): ?> +if (has_credential(CRED_PKGBASE_DELETE)): ?> <div class="box"> <h2><?= __('Merge Package: %s', htmlspecialchars($pkgbase_name)) ?></h2> <p> diff --git a/web/html/pkgreq.php b/web/html/pkgreq.php index 9dec1f6..03b31b8 100644 --- a/web/html/pkgreq.php +++ b/web/html/pkgreq.php @@ -16,7 +16,7 @@ if (isset($base_id)) { $pkgbase_name = pkgreq_get_pkgbase_name($pkgreq_id); include('pkgreq_close_form.php'); } else { - if (!check_user_privileges()) { + if (!has_credential(CRED_PKGREQ_LIST)) { header('Location: /'); exit(); } diff --git a/web/html/tu.php b/web/html/tu.php index 5d4e37d..158632a 100644 --- a/web/html/tu.php +++ b/web/html/tu.php @@ -14,12 +14,7 @@ html_header($title); $pp = 10; $prev_Len = 75; -$atype = ""; -if (isset($_COOKIE["AURSID"])) { - $atype = account_from_sid($_COOKIE["AURSID"]); -} - -if ($atype == "Trusted User" || $atype == "Developer") { +if (has_credential(CRED_TU_LIST_VOTES)) { if (isset($_GET['id'])) { if (is_numeric($_GET['id'])) { @@ -39,7 +34,7 @@ if ($atype == "Trusted User" || $atype == "Developer") { if ($isrunning == 0) { $canvote = 0; $errorvote = __("Voting is closed for this proposal."); - } else if ($atype == "Developer") { + } else if (!has_credential(CRED_TU_VOTE)) { $canvote = 0; $errorvote = __("Only Trusted Users are allowed to vote."); } else if ($row['User'] == username_from_sid($_COOKIE["AURSID"])) { diff --git a/web/html/voters.php b/web/html/voters.php index bbcf547..8766fa7 100644 --- a/web/html/voters.php +++ b/web/html/voters.php @@ -6,11 +6,10 @@ include_once('pkgfuncs.inc.php'); $SID = $_COOKIE['AURSID']; $pkgname = htmlspecialchars($_GET['N']); $votes = pkgbase_votes_from_name($pkgname); -$atype = account_from_sid($SID); html_header(__("Voters")); -if ($atype == 'Trusted User' || $atype== 'Developer'): +if (has_credential(CRED_PKGBASE_LIST_VOTERS)): ?> <div class="box"> diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index 06d4311..e2e37b8 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -42,7 +42,6 @@ function html_format_pgp_fingerprint($fingerprint) { * Loads the account editing form, with any values that are already saved * * @global array $SUPPORTED_LANGS Languages that are supported by the AUR - * @param string $UTYPE User type of the account accessing the form * @param string $A Form to use, either UpdateAccount or NewAccount * @param string $U The username to display * @param string $T The account type of the displayed user @@ -59,7 +58,7 @@ function html_format_pgp_fingerprint($fingerprint) { * * @return void */ -function display_account_form($UTYPE,$A,$U="",$T="",$S="", +function display_account_form($A,$U="",$T="",$S="", $E="",$P="",$C="",$R="",$L="",$I="",$K="",$J="", $UID=0) { global $SUPPORTED_LANGS; @@ -71,7 +70,6 @@ function display_account_form($UTYPE,$A,$U="",$T="",$S="", * Process information given to new/edit account form * * @global array $SUPPORTED_LANGS Languages that are supported by the AUR - * @param string $UTYPE The account type of the user modifying the account * @param string $TYPE Either "edit" for editing or "new" for registering an account * @param string $A Form to use, either UpdateAccount or NewAccount * @param string $U The username for the account @@ -89,7 +87,7 @@ function display_account_form($UTYPE,$A,$U="",$T="",$S="", * * @return string|void Return void if successful, otherwise return error */ -function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="", +function process_account_form($TYPE,$A,$U="",$T="",$S="",$E="", $P="",$C="",$R="",$L="",$I="",$K="",$J="",$UID=0) { global $SUPPORTED_LANGS, $AUR_LOCATION; @@ -143,7 +141,8 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="", $error = __("The PGP key fingerprint is invalid."); } - if (($UTYPE == "User" && $T > 1) || ($UTYPE == "Trusted User" && $T > 2)) { + $atype = account_from_sid($_COOKIE['AURSID']); + if (($atype == "User" && $T > 1) || ($atype == "Trusted User" && $T > 2)) { $error = __("Cannot increase account permissions."); } if (!$error && !array_key_exists($L, $SUPPORTED_LANGS)) { @@ -188,7 +187,7 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="", if ($error) { print "<ul class='errorlist'><li>".$error."</li></ul>\n"; - display_account_form($UTYPE, $A, $U, $T, $S, $E, "", "", + display_account_form($A, $U, $T, $S, $E, "", "", $R, $L, $I, $K, $J, $UID); return; } @@ -299,7 +298,6 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="", /** * Display the search results page * - * @param string $UTYPE User type of the account accessing the form * @param string $O The offset for the results page * @param string $SB The column to sort the results page by * @param string $U The username search criteria @@ -312,7 +310,7 @@ function process_account_form($UTYPE,$TYPE,$A,$U="",$T="",$S="",$E="", * * @return void */ -function search_results_page($UTYPE,$O=0,$SB="",$U="",$T="", +function search_results_page($O=0,$SB="",$U="",$T="", $S="",$E="",$R="",$I="",$K="") { $HITS_PER_PAGE = 50; @@ -1098,28 +1096,15 @@ function cast_proposal_vote($voteid, $uid, $vote, $newtotal) { /** * Verify a user has the proper permissions to edit an account * - * @param string $atype Account type of the editing user * @param array $acctinfo User account information for edited account - * @param int $uid User ID of the editing user * * @return bool True if permission to edit the account, otherwise false */ -function can_edit_account($atype, $acctinfo, $uid) { - /* Developers can edit any account */ - if ($atype == 'Developer') { - return true; - } - - /* Trusted Users can edit all accounts except Developer accounts */ - if ($atype == 'Trusted User' && - $acctinfo['AccountType'] != 'Developer') { - return true; +function can_edit_account($acctinfo) { + if ($acctinfo['AccountType'] == 'Developer') { + return has_credential(CRED_ACCOUNT_EDIT_DEV); } - /* Users can edit only their own account */ - if ($acctinfo['ID'] == $uid) { - return true; - } - - return false; + $uid = uid_from_sid($_COOKIE['AURSID']); + return has_credential(CRED_ACCOUNT_EDIT, array($uid)); } diff --git a/web/lib/aur.inc.php b/web/lib/aur.inc.php index 7fa792b..82730bb 100644 --- a/web/lib/aur.inc.php +++ b/web/lib/aur.inc.php @@ -16,6 +16,7 @@ include_once("routing.inc.php"); include_once("version.inc.php"); include_once("acctfuncs.inc.php"); include_once("cachefuncs.inc.php"); +include_once("credentials.inc.php"); /** * Check if a visitor is logged in @@ -407,16 +408,6 @@ function uid_from_email($email) { } /** - * Determine if a user has TU or Developer privileges - * - * @return bool Return true if the user is a TU or developer, otherwise false - */ -function check_user_privileges() { - $type = account_from_sid($_COOKIE['AURSID']); - return ($type == 'Trusted User' || $type == 'Developer'); -} - -/** * Generate clean url with edited/added user values * * Makes a clean string of variables for use in URLs based on current $_GET and diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php new file mode 100644 index 0000000..22068e4 --- /dev/null +++ b/web/lib/credentials.inc.php @@ -0,0 +1,76 @@ +<?php +include_once("config.inc.php"); + +define("CRED_ACCOUNT_CHANGE_TYPE", 1); +define("CRED_ACCOUNT_EDIT", 2); +define("CRED_ACCOUNT_EDIT_DEV", 3); +define("CRED_ACCOUNT_LAST_LOGIN", 4); +define("CRED_ACCOUNT_SEARCH", 5); +define("CRED_COMMENT_DELETE", 6); +define("CRED_PKGBASE_ADOPT", 7); +define("CRED_PKGBASE_CHANGE_CATEGORY", 8); +define("CRED_PKGBASE_DELETE", 9); +define("CRED_PKGBASE_DISOWN", 10); +define("CRED_PKGBASE_FLAG", 11); +define("CRED_PKGBASE_LIST_VOTERS", 12); +define("CRED_PKGBASE_NOTIFY", 13); +define("CRED_PKGBASE_SUBMIT_BLACKLISTED", 14); +define("CRED_PKGBASE_UNFLAG", 15); +define("CRED_PKGBASE_VOTE", 16); +define("CRED_PKGREQ_CLOSE", 17); +define("CRED_PKGREQ_LIST", 18); +define("CRED_TU_ADD_VOTE", 19); +define("CRED_TU_LIST_VOTES", 20); +define("CRED_TU_VOTE", 21); + +/** + * Determine if a user has the permission to perform a given action + * + * @param int $credential The type of action to peform + * @param array $approved_users A user whitelist for this query + * + * @return bool Return true if the user has the permission, false if not + */ +function has_credential($credential, $approved_users=array()) { + if (!isset($_COOKIE['AURSID'])) { + return false; + } + + $uid = uid_from_sid($_COOKIE['AURSID']); + if (in_array($uid, $approved_users)) { + return true; + } + + $atype = account_from_sid($_COOKIE['AURSID']); + + switch ($credential) { + case CRED_PKGBASE_FLAG: + case CRED_PKGBASE_NOTIFY: + case CRED_PKGBASE_VOTE: + return ($atype == 'User' || $atype == 'Trusted User' || + $atype == 'Developer'); + case CRED_ACCOUNT_CHANGE_TYPE: + case CRED_ACCOUNT_EDIT: + case CRED_ACCOUNT_LAST_LOGIN: + case CRED_ACCOUNT_SEARCH: + case CRED_COMMENT_DELETE: + case CRED_PKGBASE_ADOPT: + case CRED_PKGBASE_CHANGE_CATEGORY: + case CRED_PKGBASE_DELETE: + case CRED_PKGBASE_DISOWN: + case CRED_PKGBASE_LIST_VOTERS: + case CRED_PKGBASE_SUBMIT_BLACKLISTED: + case CRED_PKGBASE_UNFLAG: + case CRED_PKGREQ_CLOSE: + case CRED_PKGREQ_LIST: + return ($atype == 'Trusted User' || $atype == 'Developer'); + case CRED_TU_ADD_VOTE: + case CRED_TU_LIST_VOTES: + case CRED_TU_VOTE: + return ($atype == 'Trusted User'); + case CRED_ACCOUNT_EDIT_DEV: + return ($atype == 'Developer'); + } + + return false; +} diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index b357dff..176b144 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -346,15 +346,14 @@ function pkgbase_maintainer_uid($base_id) { * Flag package(s) as out-of-date * * @global string $AUR_LOCATION The AUR's URL used for notification e-mails - * @param string $atype Account type, output of account_from_sid * @param array $base_ids Array of package base IDs to flag/unflag * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_flag($atype, $base_ids) { +function pkgbase_flag($base_ids) { global $AUR_LOCATION; - if (!$atype) { + if (!has_credential(CRED_PKGBASE_FLAG)) { return array(false, __("You must be logged in before you can flag packages.")); } @@ -404,13 +403,13 @@ function pkgbase_flag($atype, $base_ids) { /** * Unflag package(s) as out-of-date * - * @param string $atype Account type, output of account_from_sid * @param array $base_ids Array of package base IDs to flag/unflag * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_unflag($atype, $base_ids) { - if (!$atype) { +function pkgbase_unflag($base_ids) { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { return array(false, __("You must be logged in before you can unflag packages.")); } @@ -425,8 +424,8 @@ function pkgbase_unflag($atype, $base_ids) { $q.= "OutOfDateTS = NULL "; $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - if ($atype != "Trusted User" && $atype != "Developer") { - $q.= "AND MaintainerUID = " . uid_from_sid($_COOKIE["AURSID"]); + if (!has_credential(CRED_PKGBASE_UNFLAG)) { + $q.= "AND MaintainerUID = " . $uid; } $result = $dbh->exec($q); @@ -439,19 +438,14 @@ function pkgbase_unflag($atype, $base_ids) { /** * Delete package bases * - * @param string $atype Account type, output of account_from_sid * @param array $base_ids Array of package base IDs to delete * @param int $merge_base_id Package base to merge the deleted ones into * @param int $via Package request to close upon deletion * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_delete ($atype, $base_ids, $merge_base_id, $via) { - if (!$atype) { - return array(false, __("You must be logged in before you can delete packages.")); - } - - if ($atype != "Trusted User" && $atype != "Developer") { +function pkgbase_delete ($base_ids, $merge_base_id, $via) { + if (!has_credential(CRED_PKGBASE_DELETE)) { return array(false, __("You do not have permission to delete packages.")); } @@ -552,15 +546,15 @@ function pkgbase_delete ($atype, $base_ids, $merge_base_id, $via) { /** * Adopt or disown packages * - * @param string $atype Account type, output of account_from_sid * @param array $base_ids Array of package base IDs to adopt/disown * @param bool $action Adopts if true, disowns if false. Adopts by default * @param int $via Package request to close upon adoption * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_adopt ($atype, $base_ids, $action=true, $via) { - if (!$atype) { +function pkgbase_adopt ($base_ids, $action=true, $via) { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { if ($action) { return array(false, __("You must be logged in before you can adopt packages.")); } else { @@ -579,23 +573,21 @@ function pkgbase_adopt ($atype, $base_ids, $action=true, $via) { $dbh = DB::connect(); - $field = "MaintainerUID"; $q = "UPDATE PackageBases "; - if ($action) { - $user = uid_from_sid($_COOKIE["AURSID"]); + $q.= "SET MaintainerUID = $uid "; } else { - $user = 'NULL'; + $q.= "SET MaintainerUID = NULL "; } - - $q.= "SET $field = $user "; $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") "; - if ($action && $atype == "User") { + if ($action && !has_credential(CRED_PKGBASE_ADOPT)) { /* Regular users may only adopt orphan packages. */ - $q.= "AND $field IS NULL "; - } else if ($atype == "User") { - $q.= "AND $field = " . uid_from_sid($_COOKIE["AURSID"]); + $q.= "AND MaintainerUID IS NULL"; + } + if (!$action && !has_credential(CRED_PKGBASE_DISOWN)) { + /* Regular users may only disown their own packages. */ + $q.= "AND MaintainerUID = " . $uid; } $dbh->exec($q); @@ -615,14 +607,13 @@ function pkgbase_adopt ($atype, $base_ids, $action=true, $via) { /** * Vote and un-vote for packages * - * @param string $atype Account type, output of account_from_sid * @param array $base_ids Array of package base IDs to vote/un-vote * @param bool $action Votes if true, un-votes if false. Votes by default * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_vote ($atype, $base_ids, $action=true) { - if (!$atype) { +function pkgbase_vote ($base_ids, $action=true) { + if (!has_credential(CRED_PKGBASE_VOTE)) { if ($action) { return array(false, __("You must be logged in before you can vote for packages.")); } else { @@ -767,13 +758,12 @@ function pkgbase_user_notify($uid, $base_id) { /** * Toggle notification of packages * - * @param string $atype Account type, output of account_from_sid * @param array $base_ids Array of package base IDs to toggle * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_notify ($atype, $base_ids, $action=true) { - if (!$atype) { +function pkgbase_notify ($base_ids, $action=true) { + if (!has_credential(CRED_PKGBASE_NOTIFY)) { return; } @@ -845,12 +835,11 @@ function pkgbase_notify ($atype, $base_ids, $action=true) { /** * Delete a package comment * - * @param string $atype Account type, output of account_from_sid - * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_delete_comment($atype) { - if (!$atype) { +function pkgbase_delete_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { return array(false, __("You must be logged in before you can edit package information.")); } @@ -861,8 +850,7 @@ function pkgbase_delete_comment($atype) { } $dbh = DB::connect(); - $uid = uid_from_sid($_COOKIE["AURSID"]); - if (can_delete_comment($comment_id, $atype, $uid)) { + if (can_delete_comment($comment_id)) { $q = "UPDATE PackageComments "; $q.= "SET DelUsersID = ".$uid." "; $q.= "WHERE ID = ".intval($comment_id); @@ -877,12 +865,12 @@ function pkgbase_delete_comment($atype) { * Change package base category * * @param int Package base ID of the package base to modify - * @param string $atype Account type, output of account_from_sid * * @return array Tuple of success/failure indicator and error message */ -function pkgbase_change_category($base_id, $atype) { - if (!$atype) { +function pkgbase_change_category($base_id) { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { return array(false, __("You must be logged in before you can edit package information.")); } @@ -906,21 +894,16 @@ function pkgbase_change_category($base_id, $atype) { if ($result) { $row = $result->fetch(PDO::FETCH_ASSOC); } - else { - return array(false, __("You are not allowed to change this package category.")); - } - $uid = uid_from_sid($_COOKIE["AURSID"]); - if ($uid == $row["MaintainerUID"] || - ($atype == "Developer" || $atype == "Trusted User")) { - $q = "UPDATE PackageBases "; - $q.= "SET CategoryID = ".intval($category_id)." "; - $q.= "WHERE ID = ".intval($base_id); - $dbh->exec($q); - return array(true, __("Package category changed.")); - } else { + if (!$result || !has_credential(CRED_PKGBASE_CHANGE_CATEGORY, array($row["MaintainerUID"]))) { return array(false, __("You are not allowed to change this package category.")); } + + $q = "UPDATE PackageBases "; + $q.= "SET CategoryID = ".intval($category_id)." "; + $q.= "WHERE ID = ".intval($base_id); + $dbh->exec($q); + return array(true, __("Package category changed.")); } /** diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index a2b8a0d..29da97b 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -9,17 +9,15 @@ include_once("pkgbasefuncs.inc.php"); * comments. This function is used for the backend side of comment deletion. * * @param string $comment_id The comment ID in the database - * @param string $atype The account type of the user trying to delete a comment - * @param string|int $uid The user ID of the individual trying to delete a comment * * @return bool True if the user can delete the comment, otherwise false */ -function can_delete_comment($comment_id=0, $atype="", $uid=0) { - if (!$uid) { +function can_delete_comment($comment_id=0) { + if (!uid_from_sid($_COOKIE["AURSID"])) { /* Unauthenticated users cannot delete anything. */ return false; } - if ($atype == "Trusted User" || $atype == "Developer") { + if (has_credential(CRED_COMMENT_DELETE)) { /* TUs and developers can delete any comment. */ return true; } @@ -45,23 +43,11 @@ function can_delete_comment($comment_id=0, $atype="", $uid=0) { * comments. This function is used for the frontend side of comment deletion. * * @param array $comment All database information relating a specific comment - * @param string $atype The account type of the user trying to delete a comment - * @param string|int $uid The user ID of the individual trying to delete a comment * * @return bool True if the user can delete the comment, otherwise false */ -function can_delete_comment_array($comment, $atype="", $uid=0) { - if (!$uid) { - /* Unauthenticated users cannot delete anything. */ - return false; - } elseif ($atype == "Trusted User" || $atype == "Developer") { - /* TUs and developers can delete any comment. */ - return true; - } else if ($comment['UsersID'] == $uid) { - /* Users can delete their own comments. */ - return true; - } - return false; +function can_delete_comment_array($comment) { + return has_credential(CRED_COMMENT_DELETE, array($comment['UsersID'])); } /** @@ -70,18 +56,10 @@ function can_delete_comment_array($comment, $atype="", $uid=0) { * Only Trusted Users and Developers can delete blacklisted packages. Packages * are blacklisted if they are include in the official repositories. * - * @param string $atype The account type of the user - * * @return bool True if the user can submit blacklisted packages, otherwise false */ -function can_submit_blacklisted($atype = "") { - if ($atype == "Trusted User" || $atype == "Developer") { - /* Only TUs and developers can submit blacklisted packages. */ - return true; - } - else { - return false; - } +function can_submit_blacklisted() { + return has_credential(CRED_PKGBASE_SUBMIT_BLACKLISTED); } /** diff --git a/web/lib/pkgreqfuncs.inc.php b/web/lib/pkgreqfuncs.inc.php index 76780fe..09047eb 100644 --- a/web/lib/pkgreqfuncs.inc.php +++ b/web/lib/pkgreqfuncs.inc.php @@ -182,7 +182,7 @@ function pkgreq_close($id, $reason, $comments) { $dbh = DB::connect(); $id = intval($id); - if (!check_user_privileges()) { + if (!has_credential(CRED_PKGREQ_CLOSE)) { return array(false, __("Only TUs and developers can close requests.")); } diff --git a/web/template/account_details.php b/web/template/account_details.php index a4e20c9..c4263d7 100644 --- a/web/template/account_details.php +++ b/web/template/account_details.php @@ -43,7 +43,7 @@ <?= $row["InactivityTS"] ? __("Inactive since") . ' ' . date("Y-m-d H:i", $row["InactivityTS"]) : __("Active"); ?> </td> </tr> - <?php if ($atype == "Trusted User" || $atype == "Developer"): ?> + <?php if (has_credential(CRED_ACCOUNT_LAST_LOGIN)): ?> <tr> <th><?= __("Last Login") . ":" ?></th> <td> @@ -55,7 +55,7 @@ <th>Links:</th> <td><ul> <li><a href="<?= get_uri('/packages/'); ?>?K=<?= $row['Username'] ?>&SeB=m"><?= __("View this user's packages") ?></a></li> - <?php if (can_edit_account($atype, $row, uid_from_sid($_COOKIE['AURSID']))): ?> + <?php if (can_edit_account($row)): ?> <li><a href="<?= get_user_uri($row['Username']); ?>edit"><?= __("Edit this user's account") ?></a></li> <?php endif; ?> </ul></td> diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 30b26fd..9a99e78 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -17,7 +17,7 @@ </p> <?php # Only TUs or Devs can promote/demote/suspend a user - if ($UTYPE == "Trusted User" || $UTYPE == "Developer"): + if (has_credential(CRED_ACCOUNT_CHANGE_TYPE)): ?> <p> <label for="id_type"><?= __("Account Type") ?>:</label> @@ -32,10 +32,7 @@ <?php else: ?> <option value="2"><?= __("Trusted user") ?></option> <?php endif; ?> - <?php - # Only developers can make another account a developer - if ($UTYPE == "Developer"): - ?> + <?php if (has_credential(CRED_ACCOUNT_EDIT_DEV)): ?> <option value="3" <?php $T == 3 ? print " selected=\"selected\">" : print ">"; print __("Developer")."\n"; ?> diff --git a/web/template/account_search_results.php b/web/template/account_search_results.php index bd4ee29..43f2d1d 100644 --- a/web/template/account_search_results.php +++ b/web/template/account_search_results.php @@ -42,13 +42,10 @@ else: <td><?php $row["IRCNick"] ? print htmlspecialchars($row["IRCNick"],ENT_QUOTES) : print " " ?></td> <td><?php $row["PGPKey"] ? print html_format_pgp_fingerprint($row["PGPKey"]) : print " " ?></td> <td> - <?php - if ($UTYPE == "Trusted User" && $row["AccountType"] == "Developer"): - # TUs can't edit devs - print " "; - else: - ?> - <a href="<?= get_user_uri($row["Username"]) . "edit/" ?>"><?= __("Edit") ?></a> + <?php if (can_edit_account($row)): ?> + <a href="<?= get_user_uri($row["Username"]) . "edit/" ?>"><?= __("Edit") ?></a> + <?php else: ?> + <?php endif; ?> </td> </tr> diff --git a/web/template/actions_form.php b/web/template/actions_form.php index a69e40d..389297b 100644 --- a/web/template/actions_form.php +++ b/web/template/actions_form.php @@ -20,12 +20,11 @@ <?php if ($row["OutOfDateTS"] === NULL): ?> <input type="submit" class="button" name="do_Flag" value="<?= __("Flag Out-of-date") ?>" /> - <?php elseif (($row["OutOfDateTS"] !== NULL) && - ($uid == $row["MaintainerUID"] || $atype == "Trusted User" || $atype == "Developer")): ?> + <?php elseif (($row["OutOfDateTS"] !== NULL) && has_credential(CRED_PKGBASE_UNFLAG, array($row["MaintainerUID"]))): ?> <input type="submit" class="button" name="do_UnFlag" value="<?= __("UnFlag Out-of-date") ?>" /> <?php endif; ?> - <?php if ($atype == "Trusted User" || $atype == "Developer"): ?> + <?php if (has_credential(CRED_PKGBASE_DELETE)): ?> <input type="submit" class="button" name="do_Delete" value="<?= __("Delete Packages") ?>" /> <label for="merge_Into" ><?= __("Merge into") ?></label> <input type="text" id="merge_Into" name="merge_Into" /> diff --git a/web/template/header.php b/web/template/header.php index 03ce536..d10b162 100644 --- a/web/template/header.php +++ b/web/template/header.php @@ -57,15 +57,15 @@ <li><a href="<?= get_uri('/packages/'); ?>"><?= __("Packages"); ?></a></li> <?php if (isset($_COOKIE['AURSID'])): ?> <li><a href="<?= get_uri('/packages/'); ?>?SeB=m&K=<?= username_from_sid($_COOKIE["AURSID"]); ?>"><?= __("My Packages"); ?></a></li> - <?php if (check_user_privileges()): ?> + <?php if (has_credential(CRED_PKGREQ_LIST)): ?> <li><a href="<?= get_uri('/requests/') ; ?>"><?= __("Requests"); ?></a></li> <?php endif; ?> <li><a href="<?= get_uri('/submit/'); ?>"><?= __("Submit"); ?></a></li> - <?php if (check_user_privileges()): ?> + <?php if (has_credential(CRED_ACCOUNT_SEARCH)): ?> <li><a href="<?= get_uri('/accounts/') ; ?>"><?= __("Accounts"); ?></a></li> <?php endif; ?> <li><a href="<?= get_user_uri(username_from_sid($_COOKIE['AURSID'])) . 'edit/'; ?>"><?= __(" My Account"); ?></a></li> - <?php if (check_user_privileges()): ?><li><a href="<?= get_uri('/tu/'); ?>"><?= __("Trusted User"); ?></a></li><?php endif; ?> + <?php if (has_credential(CRED_TU_LIST_VOTES)): ?><li><a href="<?= get_uri('/tu/'); ?>"><?= __("Trusted User"); ?></a></li><?php endif; ?> <li><a href="<?= get_uri('/logout/'); ?>"><?= __("Logout"); ?></a></li> <?php else: ?> <li><a href="<?= get_uri('/register/'); ?>"><?= __("Register"); ?></a></li> diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index ca4abc6..20521a0 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -1,5 +1,4 @@ <?php -$uid = uid_from_sid($SID); $base_id = pkgbase_from_pkgid($row['ID']); $count = pkgbase_comments_count($base_id); ?> @@ -14,7 +13,7 @@ $count = pkgbase_comments_count($base_id); $row['UserName'] = "<a href=\"" . get_user_uri($row['UserName']) . "\">{$row['UserName']}</a>"; endif; ?> <h4> - <?php if (can_delete_comment_array($row, $atype, $uid)): ?> + <?php if (can_delete_comment_array($row)): ?> <form method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> <fieldset style="display:inline;"> <input type="hidden" name="action" value="do_DeleteComment" /> diff --git a/web/template/pkg_details.php b/web/template/pkg_details.php index 6f39514..7f01d2f 100644 --- a/web/template/pkg_details.php +++ b/web/template/pkg_details.php @@ -1,5 +1,4 @@ <?php -$atype = account_from_sid($SID); $uid = uid_from_sid($SID); $pkgid = intval($row['ID']); @@ -67,8 +66,7 @@ $sources = pkg_sources($row["ID"]); <input type="submit" class="button text-button" name="do_Flag" value="<?= __('Flag package out-of-date') ?>" /> </form> </li> - <?php elseif (($row["OutOfDateTS"] !== NULL) && - ($uid == $row["MaintainerUID"] || $atype == "Trusted User" || $atype == "Developer")): ?> + <?php elseif (($row["OutOfDateTS"] !== NULL) && has_credential(CRED_PKGBASE_UNFLAG, array($row["MaintainerUID"]))): ?> <li> <form action="<?= get_pkgbase_uri($row['BaseName']) . 'unflag/'; ?>" method="post"> <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> @@ -108,7 +106,7 @@ $sources = pkg_sources($row["ID"]); <?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 ($atype == "Trusted User" || $atype == "Developer"): ?> + <?php if (has_credential(CRED_PKGBASE_DELETE)): ?> <li><a href="<?= get_pkgbase_uri($row['BaseName']) . 'delete/'; ?>"><?= __('Delete Package'); ?></a></li> <li><a href="<?= get_pkgbase_uri($row['BaseName']) . 'merge/'; ?>"><?= __('Merge Package'); ?></a></li> <?php endif; ?> @@ -121,8 +119,7 @@ $sources = pkg_sources($row["ID"]); <input type="submit" class="button text-button" name="do_Adopt" value="<?= __('Adopt Package') ?>" /> </form> </li> - <?php elseif ($uid && $uid == $row["MaintainerUID"] || - $atype == "Trusted User" || $atype == "Developer"): ?> + <?php elseif (has_credential(CRED_PKGBASE_DISOWN, array($row["MaintainerUID"]))): ?> <li> <form action="<?= get_pkgbase_uri($row['BaseName']) . 'disown/'; ?>" method="post"> <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> @@ -150,8 +147,7 @@ $sources = pkg_sources($row["ID"]); <tr> <th><?= __('Category') . ': ' ?></th> <?php -if ($SID && ($uid == $row["MaintainerUID"] || - ($atype == "Developer" || $atype == "Trusted User"))): +if (has_credential(CRED_PKGBASE_CHANGE_CATEGORY, array($row["MaintainerUID"]))): ?> <td> <form method="post" action="<?= htmlspecialchars(get_pkgbase_uri($row['BaseName']), ENT_QUOTES); ?>"> @@ -312,7 +308,7 @@ if ($row["PackagerUID"]): </tr> <tr> <th><?= __('Votes') . ': ' ?></th> -<?php if ($atype == "Developer" || $atype == "Trusted User"): ?> +<?php if (has_credential(CRED_PKGBASE_LIST_VOTERS)): ?> <?php if ($USE_VIRTUAL_URLS): ?> <td><a href="<?= get_pkgbase_uri($row['BaseName']); ?>voters/"><?= $votes ?></a></td> <?php else: ?> diff --git a/web/template/pkg_search_results.php b/web/template/pkg_search_results.php index 75131fc..e901408 100644 --- a/web/template/pkg_search_results.php +++ b/web/template/pkg_search_results.php @@ -1,10 +1,4 @@ <?php -if (isset($_COOKIE['AURSID'])) { - $atype = account_from_sid($_COOKIE['AURSID']); -} else { - $atype = ""; -} - if (!$result): ?> <div class="box"><p><?= __("Error retrieving package list.") ?></p></div> <?php elseif ($total == 0): ?> @@ -119,13 +113,13 @@ if (!$result): ?> <option value="do_UnFlag"><?= __("Unflag Out-of-date") ?></option> <option value="do_Adopt"><?= __("Adopt Packages") ?></option> <option value="do_Disown"><?= __("Disown Packages") ?></option> - <?php if ($atype == "Trusted User" || $atype == "Developer"): ?> + <?php if (has_credential(CRED_PKGBASE_DELETE)): ?> <option value="do_Delete"><?= __("Delete Packages") ?></option> <?php endif; ?> <option value="do_Notify"><?= __("Notify") ?></option> <option value="do_UnNotify"><?= __("UnNotify") ?></option> </select> - <?php if ($atype == "Trusted User" || $atype == "Developer"): ?> + <?php if (has_credential(CRED_PKGBASE_DELETE)): ?> <label for="merge_Into"><?= __("Merge into") ?></label> <input type="text" id="merge_Into" name="merge_Into" /> <input type="checkbox" name="confirm_Delete" value="1" /> <?= __("Confirm") ?> diff --git a/web/template/pkgbase_details.php b/web/template/pkgbase_details.php index 64df72b..fb11e60 100644 --- a/web/template/pkgbase_details.php +++ b/web/template/pkgbase_details.php @@ -1,5 +1,4 @@ <?php -$atype = account_from_sid($SID); $uid = uid_from_sid($SID); $base_id = intval($row['ID']); @@ -42,8 +41,7 @@ $pkgs = pkgbase_get_pkgnames($base_id); <input type="submit" class="button text-button" name="do_Flag" value="<?= __('Flag package out-of-date') ?>" /> </form> </li> - <?php elseif (($row["OutOfDateTS"] !== NULL) && - ($uid == $row["MaintainerUID"] || $atype == "Trusted User" || $atype == "Developer")): ?> + <?php elseif (($row["OutOfDateTS"] !== NULL) && has_credential(CRED_PKGBASE_UNFLAG, array($row["MaintainerUID"]))): ?> <li> <form action="<?= get_pkgbase_uri($row['Name']) . 'unflag/'; ?>" method="post"> <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> @@ -83,7 +81,7 @@ $pkgs = pkgbase_get_pkgnames($base_id); <?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 ($atype == "Trusted User" || $atype == "Developer"): ?> + <?php if (has_credential(CRED_PKGBASE_DELETE)): ?> <li><a href="<?= get_pkgbase_uri($row['Name']) . 'delete/'; ?>"><?= __('Delete Package'); ?></a></li> <li><a href="<?= get_pkgbase_uri($row['Name']) . 'merge/'; ?>"><?= __('Merge Package'); ?></a></li> <?php endif; ?> @@ -96,8 +94,7 @@ $pkgs = pkgbase_get_pkgnames($base_id); <input type="submit" class="button text-button" name="do_Adopt" value="<?= __('Adopt Package') ?>" /> </form> </li> - <?php elseif ($uid && $uid == $row["MaintainerUID"] || - $atype == "Trusted User" || $atype == "Developer"): ?> + <?php elseif (has_credential(CRED_PKGBASE_DISOWN, array($row["MaintainerUID"]))): ?> <li> <form action="<?= get_pkgbase_uri($row['Name']) . 'disown/'; ?>" method="post"> <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> @@ -113,8 +110,7 @@ $pkgs = pkgbase_get_pkgnames($base_id); <tr> <th><?= __('Category') . ': ' ?></th> <?php -if ($SID && ($uid == $row["MaintainerUID"] || - ($atype == "Developer" || $atype == "Trusted User"))): +if (has_credential(CRED_PKGBASE_CHANGE_CATEGORY, array($row["MaintainerUID"]))): ?> <td> <form method="post" action="<?= htmlspecialchars(get_pkgbase_uri($row['Name']), ENT_QUOTES); ?>"> @@ -195,7 +191,7 @@ if ($row["PackagerUID"]): </tr> <tr> <th><?= __('Votes') . ': ' ?></th> -<?php if ($atype == "Developer" || $atype == "Trusted User"): ?> +<?php if (has_credential(CRED_PKGBASE_LIST_VOTERS)): ?> <?php if ($USE_VIRTUAL_URLS): ?> <td><a href="<?= get_pkgbase_uri($row['Name']); ?>voters/"><?= $votes ?></a></td> <?php else: ?> |