[aur-dev] [PATCH 1/2] Add capability to pin comments above others
Adds functions and credential information to pin comments before others. This needs two extra columns (PinnedTS and PinnedUsersID) to the PackageComments table. Signed-off-by: Mark Weiman <mark.weiman@markzz.com> --- web/html/pkgbase.php | 4 ++ web/lib/credentials.inc.php | 2 + web/lib/pkgbasefuncs.inc.php | 123 ++++++++++++++++++++++++++++++++++++++++++- web/lib/pkgfuncs.inc.php | 54 +++++++++++++++++++ 4 files changed, 182 insertions(+), 1 deletion(-) diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cbbf3cc..3ca6e55 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -99,6 +99,10 @@ if (check_token()) { list($ret, $output) = pkgbase_notify($ids, false); } elseif (current_action("do_DeleteComment")) { list($ret, $output) = pkgbase_delete_comment(); + } elseif (current_action("do_PinComment")) { + list($ret, $output) = pkgbase_pin_comment(); + } elseif (current_action("do_UnpinComment")) { + list($ret, $output) = pkgbase_unpin_comment(); } elseif (current_action("do_SetKeywords")) { list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); } elseif (current_action("do_FileRequest")) { diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index 648d78c..71bf5ff 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -8,6 +8,7 @@ define("CRED_ACCOUNT_SEARCH", 5); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_VIEW_DELETED", 22); define("CRED_COMMENT_EDIT", 25); +define("CRED_COMMENT_PIN", 26); define("CRED_PKGBASE_ADOPT", 7); define("CRED_PKGBASE_SET_KEYWORDS", 8); define("CRED_PKGBASE_DELETE", 9); @@ -60,6 +61,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_COMMENT_DELETE: case CRED_COMMENT_VIEW_DELETED: case CRED_COMMENT_EDIT: + case CRED_COMMENT_PIN: case CRED_PKGBASE_ADOPT: case CRED_PKGBASE_SET_KEYWORDS: case CRED_PKGBASE_DELETE: diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index afccc7d..0a4176f 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -49,10 +49,12 @@ function pkgbase_comments($base_id, $limit, $include_deleted) { $dbh = DB::connect(); $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments "; + $q.= "DelUsersID, C.UserName AS DelUserName, "; + $q.= "PinnedUsersID, D.UserName AS PinnedUserName FROM PackageComments "; $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; + $q.= "LEFT JOIN Users D ON PackageComments.PinnedUsersID = D.ID "; $q.= "WHERE PackageBaseID = " . $base_id . " "; if (!$include_deleted) { $q.= "AND DelUsersID IS NULL "; @@ -111,6 +113,65 @@ function pkgbase_add_comment($base_id, $uid, $comment) { } /** + * Get all pinned package comment information for a specific package base + * + * @param int $base_id The package base ID to get comments for + * @param int $limit Maximum number of comments to return (0 means unlimited) + * @param bool $include_deleted True if deleted comments should be included + * + * @return array Pinned package comment information for specific package base + */ +function pkgbase_pinned_comments($base_id, $limit, $include_deleted) { + $base_id = intval($base_id); + $limit = intval($limit); + if (!$base_id) { + return null; + } + + $dbh = DB::connect(); + $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; + $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, "; + $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments "; + $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; + $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; + $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; + $q.= "WHERE PackageBaseID = " . $base_id . " "; + $q.= "AND PinnedUsersID IS NOT NULL "; + + if (!$include_deleted) { + $q.= "AND DelUsersID IS NULL "; + } + $q.= "ORDER BY CommentTS DESC"; + if ($limit > 0) { + $q.=" LIMIT " . $limit; + } + $result = $dbh->query($q); + if (!$result) { + return null; + } + + return $result->fetchAll(); +} + +/** + * Display pinned comments before the other comments on a package page + * + * @param string $base_id The package base ID to add the comment on + * @param string $uid The user ID of the individual who pinned the comment + * @param string $comment_id The comment id to be pinned + * + * @return void + */ +function pkgbase_disp_pin_comment($base_id, $uid, $comment_id) { + $dbh = DB::connect(); + + $q = "UPDATE PackageComments "; + $q.= "SET PinnedTS = UNIXTIMESTAMP()), PinnedUsersID=" . $uid . " "; + $q.= "WHERE ID = " . intval($comment_id); + $dbh->exec($q); +} + +/** * Get a list of all packages a logged-in user has voted for * * @param string $sid The session ID of the visitor @@ -906,6 +967,66 @@ function pkgbase_edit_comment($comment) { } /** + * Pin a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_pin_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_pin_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET PinnedUsersID = ".$uid.", "; + $q.= "PinnedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been pinned.")); + } else { + return array(false, __("You are not allowed to pin this comment.")); + } +} + +/** + * Unpin a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_unpin_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_pin_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET PinnedUsersID = NULL, "; + $q.= "PinnedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been unpinned.")); + } else { + return array(false, __("You are not allowed to unpin this comment.")); + } +} + +/** * Get a list of package base keywords * * @param int $base_id The package base ID to retrieve the keywords for diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index cedc360..8e8f5d2 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -83,6 +83,60 @@ function can_edit_comment_array($comment) { } /** + * Determine if the user can pin a specific package comment + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the backend side of comment pinning. + * + * @param string $comment_id The comment ID in the database + * + * @return bool True if the user can pin the comment, otherwise false + */ +function can_pin_comment($comment_id=0) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment_id); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} + +/** + * Determine if the user can edit a specific package comment using an array + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the frontend side of comment pinning. + * + * @param array $comment All database information relating a specific comment + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_pin_comment_array($comment) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment['ID']); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} + +/** * Check to see if the package name already exists in the database * * @param string $name The package name to check -- 2.6.2
Implements FS#10863 Signed-off-by: Mark Weiman <mark.weiman@markzz.com> --- web/html/css/aurweb.css | 18 +++++- web/lib/pkgbasefuncs.inc.php | 7 +++ web/lib/pkgfuncs.inc.php | 9 ++- web/template/pkg_comments.php | 22 +++++++ web/template/pkg_pinned_comments.php | 112 +++++++++++++++++++++++++++++++++++ 5 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 web/template/pkg_pinned_comments.php diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 11af747..9912c56 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -101,7 +101,7 @@ color: #999; } -.delete-comment-form, .edit-comment { +.delete-comment-form, .pin-comment-form, .edit-comment { float: right; margin-left: 8px; } @@ -118,12 +118,26 @@ opacity: 0.6; } -.delete-comment:hover, .edit-comment:hover { +.delete-comment:hover, .edit-comment:hover, .pin-comment:hover { -webkit-filter: none; filter: none; opacity: 1; } +.pin-comment { + float: right; + font-weight: 600; + background: none!important; + border: none; + padding: 0!important; + font: inherit; + cursor: pointer; + color: #3366aa; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + opacity: 0.6; +} + .ajax-loader { float: right; position: relative; diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index 0a4176f..87f5dcb 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -257,6 +257,13 @@ function pkgbase_display_details($base_id, $row, $SID="") { if ($SID) { include('pkg_comment_box.php'); } + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $include_del_pinned = has_credential(CRED_COMMENT_VIEW_DELETED); + $pinned = pkgbase_pinned_comments($base_id, $limit_pinned, $include_del_pinned); + if (!empty($pinned)) { + include('pkg_pinned_comments.php'); + } $limit = isset($_GET['comments']) ? 0 : 10; $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index 8e8f5d2..0019706 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -635,7 +635,14 @@ function pkg_display_details($id=0, $row, $SID="") { if ($SID) { include('pkg_comment_box.php'); } - + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $include_del_pinned = has_credential(CRED_COMMENT_VIEW_DELETED); + $pinned = pkgbase_pinned_comments($base_id, $limit_pinned, $include_del_pinned); + if (!empty($pinned)) { + include('pkg_pinned_comments.php'); + } + $limit = isset($_GET['comments']) ? 0 : 10; $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); $comments = pkgbase_comments($base_id, $limit, $include_deleted); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 21ce16f..a0afc64 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -56,6 +56,28 @@ $count = pkgbase_comments_count($base_id, $include_deleted); <?php if (!$row['DelUsersID'] && can_edit_comment_array($row)): ?> <a href="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name) . 'edit-comment/?comment_id=' . $row['ID'], ENT_QUOTES) ?>" class="edit-comment" title="<?= __('Edit comment') ?>"><img src="/images/pencil.min.svg" alt="<?= __('Edit comment') ?>" width="11" height="11"></a> <?php endif; ?> + + <?php if (!$row['DelUsersID'] && !$row['PinnedUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_PinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Pin') ?>" width="11" height="11" alt="<?= __('Pin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> + + <?php if (!$row['DelUsersID'] && $row['PinnedUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_UnpinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Unpin') ?>" width="11" height="11" alt="<?= __('Unin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> </h4> <div class="article-content<?php if ($row['DelUsersID']): ?> comment-deleted<?php endif; ?>"> <p> diff --git a/web/template/pkg_pinned_comments.php b/web/template/pkg_pinned_comments.php new file mode 100644 index 0000000..9d87082 --- /dev/null +++ b/web/template/pkg_pinned_comments.php @@ -0,0 +1,112 @@ +<?php +if (isset($row['BaseID'])) { + /* On a package details page. */ + $base_id = $row['BaseID']; +} else { + /* On a package base details page. */ + $base_id = $row['ID']; +} +$include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); +$count = pkgbase_comments_count($base_id, $include_deleted); +?> +<div id="news"> + <h3> + <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all pinned comments' , $count) ?> (<?= $count ?>)"><?= __('Pinned Comments') ?></a> + <span class="arrow"></span> + </h3> + + <?php while (list($indx, $row) = each($pinned)): ?> + <?php + $date_fmtd = gmdate('Y-m-d H:i', $row['CommentTS']); + if ($row['UserName']) { + $user_fmtd = html_format_username($row['UserName']); + $heading = __('%s commented on %s', $user_fmtd, $date_fmtd); + } else { + $heading = __('Anonymous comment on %s', $date_fmtd); + } + + if ($row['EditedTS']) { + $date_fmtd = gmdate('Y-m-d H:i', $row['EditedTS']); + $heading .= ' <span class="edited">('; + if ($row['DelUsersID']) { + $user_fmtd = html_format_username($row['DelUserName']); + $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); + } else { + $user_fmtd = html_format_username($row['EditUserName']); + $heading .= __('last edited on %s by %s', $date_fmtd, $user_fmtd); + } + $heading .= ')</span>'; + } + + $row['DelUserName'] = html_format_username($row['DelUserName']); + $row['EditUserName'] = html_format_username($row['EditUserName']); + ?> + <h4 id="comment-<?= $row['ID'] ?>"<?php if ($row['DelUsersID']): ?> class="comment-deleted"<?php endif; ?>> + <?= $heading ?> + <?php if (!$row['DelUsersID'] && can_delete_comment_array($row)): ?> + <form class="delete-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_DeleteComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="image" class="delete-comment" src="/images/x.min.svg" width="11" height="11" alt="<?= __('Delete comment') ?>" title="<?= __('Delete comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> + <?php if (!$row['DelUsersID'] && can_edit_comment_array($row)): ?> + <a href="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name) . 'edit-comment/?comment_id=' . $row['ID'], ENT_QUOTES) ?>" class="edit-comment" title="<?= __('Edit comment') ?>"><img src="/images/pencil.min.svg" alt="<?= __('Edit comment') ?>" width="11" height="11"></a> + <?php endif; ?> + + <?php if (!$row['DelUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_UnpinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Unpin') ?>" width="11" height="11" alt="<?= __('Unpin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> + </h4> + <div class="article-content<?php if ($row['DelUsersID']): ?> comment-deleted<?php endif; ?>"> + <p> + <?= parse_comment($row['Comments']) ?> + </p> + </div> + <?php endwhile; ?> +</div> +<script> +$(document).ready(function() { + $('.edit-comment').click(function () { + var parent_element = this.parentElement, + parent_id = parent_element.id, + comment_id = parent_id.substr(parent_id.indexOf('-') + 1), + edit_form = $(parent_element).next(), + _this = $(this); + add_busy_indicator(_this); + $.getJSON('<?= get_uri('/rpc') ?>', { + type: 'get-comment-form', + arg: comment_id, + base_id: <?= intval($base_id) ?>, + pkgbase_name: <?= json_encode($pkgbase_name) ?> + }, function (data) { + remove_busy_indicator(_this); + if (data.success) { + edit_form.html(data.form); + edit_form.find('textarea').focus(); + } else { + alert(data.error); + } + }); + return false; + }); + + function add_busy_indicator(sibling) { + sibling.after('<img src="/images/ajax-loader.gif" class="ajax-loader" width="16" height="11" alt="Busy..." />'); + } + + function remove_busy_indicator(sibling) { + sibling.next().remove(); + } +}); +</script> -- 2.6.2
On Sat, 28 Nov 2015 at 01:44:26, Mark Weiman wrote:
Adds functions and credential information to pin comments before others.
This needs two extra columns (PinnedTS and PinnedUsersID) to the PackageComments table.
Signed-off-by: Mark Weiman <mark.weiman@markzz.com> --- web/html/pkgbase.php | 4 ++ web/lib/credentials.inc.php | 2 + web/lib/pkgbasefuncs.inc.php | 123 ++++++++++++++++++++++++++++++++++++++++++- web/lib/pkgfuncs.inc.php | 54 +++++++++++++++++++ 4 files changed, 182 insertions(+), 1 deletion(-)
First of all, thanks for working on this! I planned on implementing this for a while but never got around to doing it. The main difference of this series to what I had in mind is that you allow for pinning multiple comments whereas I planned to have a single pinned comment (per package base) only. Can you think of a use case where having several pinned comments is desirable? Can't the maintainer simply edit the pinned comment and add new information? Would we ever want to pin a comment from a user other than the current maintainer? More comments on the implementation below.
[...] /** + * Get all pinned package comment information for a specific package base + * + * @param int $base_id The package base ID to get comments for + * @param int $limit Maximum number of comments to return (0 means unlimited) + * @param bool $include_deleted True if deleted comments should be included + * + * @return array Pinned package comment information for specific package base + */ +function pkgbase_pinned_comments($base_id, $limit, $include_deleted) { [...]
I did not have a very detailed look at the second patch in this series but is this really needed? Can't we simply retrieve all comments by calling pkgbase_comments() and order them such that pinned comments are displayed first?
[...] +/** + * Display pinned comments before the other comments on a package page + * + * @param string $base_id The package base ID to add the comment on + * @param string $uid The user ID of the individual who pinned the comment + * @param string $comment_id The comment id to be pinned + * + * @return void + */ +function pkgbase_disp_pin_comment($base_id, $uid, $comment_id) { + $dbh = DB::connect(); + + $q = "UPDATE PackageComments "; + $q.= "SET PinnedTS = UNIXTIMESTAMP()), PinnedUsersID=" . $uid . " "; + $q.= "WHERE ID = " . intval($comment_id);
After having read the function name and the comment, I would have expected this function to print a pinned comment but that does not seem to be what this function does... Anyway, what is the difference between this function and pkgbase_pin_comment() below? Can't we somehow merge those functions?
[...] /** + * Determine if the user can pin a specific package comment + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the backend side of comment pinning. + * + * @param string $comment_id The comment ID in the database + * + * @return bool True if the user can pin the comment, otherwise false + */ +function can_pin_comment($comment_id=0) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment_id); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} + +/** + * Determine if the user can edit a specific package comment using an array + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the frontend side of comment pinning. + * + * @param array $comment All database information relating a specific comment + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_pin_comment_array($comment) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment['ID']); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} [...]
Isn't this equivalent to function can_pin_comment_array($comment) { return can_pin_comment($comment['ID']); } ...? I also think that the function name is slightly misleading. I would have expected that can_pin_comment_array() accepts an array of comment IDs and returns an array of boolean values. Do we need that function at all? Can't we simply call can_pin_comment($comment['ID']) instead? Regards, Lukas
On Sat, 2015-11-28 at 13:06 +0100, Lukas Fleischer wrote:
First of all, thanks for working on this! I planned on implementing this for a while but never got around to doing it.
The main difference of this series to what I had in mind is that you allow for pinning multiple comments whereas I planned to have a single pinned comment (per package base) only. Can you think of a use case where having several pinned comments is desirable? Can't the maintainer simply edit the pinned comment and add new information? Would we ever want to pin a comment from a user other than the current maintainer?
More comments on the implementation below.
No problem! I was thinking that rather than having to retype the same information (or copy and paste), we could just pin a comment from anyone and if multiple comments have good information, we can pin all of them. Only 5 get displayed unless you go to the "comments=all" page.
I did not have a very detailed look at the second patch in this series but is this really needed? Can't we simply retrieve all comments by calling pkgbase_comments() and order them such that pinned comments are displayed first?
To begin, the only reason I made two patches is because my Postfix server would complain when the patch got too long (lost connection after DATA error) while using git-send-email, so I made two smaller patches to get around that issue. Nothing I did could solve that problem. The idea I was going for was rather than removing the comment order below (preserving the readability of a conversation), just make a copy of it above. While doing that, make a new header above that says "Pinned Comments" above the pinned comments, then do the normal "Latest Comments" section. If you think it should be a single comment from the maintainer that is displaced, I can make that change.
After having read the function name and the comment, I would have expected this function to print a pinned comment but that does not seem to be what this function does... Anyway, what is the difference between this function and pkgbase_pin_comment() below? Can't we somehow merge those functions?
You know what, I cannot tell what I was thinking about when I made this and it appears I never actually use this function. I removed it on my own local instance of aurweb and nothing appears to be broken as a result. The next patch revision will have this removed completely.
Isn't this equivalent to
function can_pin_comment_array($comment) { return can_pin_comment($comment['ID']); }
...? I also think that the function name is slightly misleading. I would have expected that can_pin_comment_array() accepts an array of comment IDs and returns an array of boolean values. Do we need that function at all? Can't we simply call can_pin_comment($comment['ID']) instead?
Wow, I cannot believe that I didn't think of that. Whoops. The reason I did this is it follows how it was done for editing and deleting comments. Even the comments are similar wording (all I really did was a copy and paste from the others). I initially thought about doing just the can_pin_comment() function, but I didn't want to differ too much from editing and deleting. I will for sure simplify that function, but if you think it's better to delete it altogether, I'll get to work on making it work. Perhaps also a rework the other two "array" functions (can_edit_comment_array() and can_delete_comment_array()) should be done in the future if the can_pin_comment_array() function is removed or the comment is changed. Mark Weiman
On Sat, 28 Nov 2015 at 16:01:06, Mark Weiman wrote:
[...] I was thinking that rather than having to retype the same information (or copy and paste), we could just pin a comment from anyone and if multiple comments have good information, we can pin all of them. Only 5 get displayed unless you go to the "comments=all" page.
Sounds good to me.
[...] To begin, the only reason I made two patches is because my Postfix server would complain when the patch got too long (lost connection after DATA error) while using git-send-email, so I made two smaller patches to get around that issue. Nothing I did could solve that problem.
Note that there is a patch size limit on this mailing list as well. However, there is nothing wrong with splitting such a large a patch into back and front end changes.
The idea I was going for was rather than removing the comment order below (preserving the readability of a conversation), just make a copy of it above. While doing that, make a new header above that says "Pinned Comments" above the pinned comments, then do the normal "Latest Comments" section. If you think it should be a single comment from the maintainer that is displaced, I can make that change.
Okay. Maybe we can still share a lot of code between the function that retrieves all comments and the function to retrieve pinned comments?
[...] I will for sure simplify that function, but if you think it's better to delete it altogether, I'll get to work on making it work. Perhaps also a rework the other two "array" functions (can_edit_comment_array() and can_delete_comment_array()) should be done in the future if the can_pin_comment_array() function is removed or the comment is changed. [...]
I am fine with simplifying the function. We can still refactor all the can_*_comment_array() functions in another patch series. Regards, Lukas
Adds functions and credential information to pin comments before others. This needs two extra columns (PinnedTS and PinnedUsersID) to the PackageComments table. Implements FS#10863 Signed-off-by: Mark Weiman <mark.weiman@markzz.com> --- web/html/css/aurweb.css | 18 ++++++++-- web/html/pkgbase.php | 4 +++ web/lib/credentials.inc.php | 2 ++ web/lib/pkgbasefuncs.inc.php | 82 +++++++++++++++++++++++++++++++++++++++++-- web/lib/pkgfuncs.inc.php | 51 ++++++++++++++++++++++++++- web/template/pkg_comments.php | 41 +++++++++++++++++++--- 6 files changed, 187 insertions(+), 11 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 11af747..5b36df0 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -101,7 +101,7 @@ color: #999; } -.delete-comment-form, .edit-comment { +.delete-comment-form, .pin-comment-form, .edit-comment { float: right; margin-left: 8px; } @@ -118,12 +118,26 @@ opacity: 0.6; } -.delete-comment:hover, .edit-comment:hover { +.delete-comment:hover, .edit-comment:hover, .pin-comment:hover { -webkit-filter: none; filter: none; opacity: 1; } +.pin-comment { + float: right; + font-weight: 600; + background: none!important; + border: none; + padding: 0!important; + font: inherit; + cursor: pointer; + color: #3366aa; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + opacity: 0.6; +} + .ajax-loader { float: right; position: relative; diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cbbf3cc..6f0de08 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -99,6 +99,10 @@ if (check_token()) { list($ret, $output) = pkgbase_notify($ids, false); } elseif (current_action("do_DeleteComment")) { list($ret, $output) = pkgbase_delete_comment(); + } elseif (current_action("do_PinComment")) { + list($ret, $output) = pkgbase_pin_comment(); + } elseif (current_action("do_UnpinComment")) { + list($ret, $output) = pkgbase_unpin_comment(); } elseif (current_action("do_SetKeywords")) { list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); } elseif (current_action("do_FileRequest")) { diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index 648d78c..71bf5ff 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -8,6 +8,7 @@ define("CRED_ACCOUNT_SEARCH", 5); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_VIEW_DELETED", 22); define("CRED_COMMENT_EDIT", 25); +define("CRED_COMMENT_PIN", 26); define("CRED_PKGBASE_ADOPT", 7); define("CRED_PKGBASE_SET_KEYWORDS", 8); define("CRED_PKGBASE_DELETE", 9); @@ -60,6 +61,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_COMMENT_DELETE: case CRED_COMMENT_VIEW_DELETED: case CRED_COMMENT_EDIT: + case CRED_COMMENT_PIN: case CRED_PKGBASE_ADOPT: case CRED_PKGBASE_SET_KEYWORDS: case CRED_PKGBASE_DELETE: diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index afccc7d..ea3ce0d 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -36,10 +36,11 @@ function pkgbase_comments_count($base_id, $include_deleted) { * @param int $base_id The package base ID to get comments for * @param int $limit Maximum number of comments to return (0 means unlimited) * @param bool $include_deleted True if deleted comments should be included + * @param bool $show_only_pinned True when only pinned comments are to be included * * @return array All package comment information for a specific package base */ -function pkgbase_comments($base_id, $limit, $include_deleted) { +function pkgbase_comments($base_id, $limit, $include_deleted, $show_only_pinned=false) { $base_id = intval($base_id); $limit = intval($limit); if (!$base_id) { @@ -49,11 +50,17 @@ function pkgbase_comments($base_id, $limit, $include_deleted) { $dbh = DB::connect(); $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments "; + $q.= "DelUsersID, C.UserName AS DelUserName, "; + $q.= "PinnedUsersID, D.UserName AS PinnedUserName FROM PackageComments "; $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; + $q.= "LEFT JOIN Users D ON PackageComments.PinnedUsersID = D.ID "; $q.= "WHERE PackageBaseID = " . $base_id . " "; + + if ($show_only_pinned) { + $q.= "AND PinnedUsersID IS NOT NULL "; + } if (!$include_deleted) { $q.= "AND DelUsersID IS NULL "; } @@ -111,6 +118,67 @@ function pkgbase_add_comment($base_id, $uid, $comment) { } /** + * Pin a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_pin_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_pin_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET PinnedUsersID = ".$uid.", "; + $q.= "PinnedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been pinned.")); + } else { + return array(false, __("You are not allowed to pin this comment.")); + } +} + +/** + * Unpin a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_unpin_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_pin_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET PinnedUsersID = NULL, "; + $q.= "PinnedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been unpinned.")); + } else { + return array(false, __("You are not allowed to unpin this comment.")); + } +} + +/** + * Get a list of all packages a logged-in user has voted for * * @param string $sid The session ID of the visitor @@ -196,9 +264,17 @@ function pkgbase_display_details($base_id, $row, $SID="") { if ($SID) { include('pkg_comment_box.php'); } + + $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); + if (!empty($pinned)) { + include('pkg_comments.php'); + unset($pinned); + } $limit = isset($_GET['comments']) ? 0 : 10; - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); $comments = pkgbase_comments($base_id, $limit, $include_deleted); if (!empty($comments)) { include('pkg_comments.php'); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index cedc360..c0ed99c 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -83,6 +83,47 @@ function can_edit_comment_array($comment) { } /** + * Determine if the user can pin a specific package comment + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the backend side of comment pinning. + * + * @param string $comment_id The comment ID in the database + * + * @return bool True if the user can pin the comment, otherwise false + */ +function can_pin_comment($comment_id=0) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment_id); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} + +/** + * Determine if the user can edit a specific package comment using an array + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the frontend side of comment pinning. + * + * @param array $comment All database information relating a specific comment + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_pin_comment_array($comment) { + return can_pin_comment($comment['ID']); +} + +/** * Check to see if the package name already exists in the database * * @param string $name The package name to check @@ -581,9 +622,17 @@ function pkg_display_details($id=0, $row, $SID="") { if ($SID) { include('pkg_comment_box.php'); } + + $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); + if (!empty($pinned)) { + include('pkg_comments.php'); + unset($pinned); + } $limit = isset($_GET['comments']) ? 0 : 10; - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); $comments = pkgbase_comments($base_id, $limit, $include_deleted); if (!empty($comments)) { include('pkg_comments.php'); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 21ce16f..8f1fb9f 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -6,13 +6,20 @@ if (isset($row['BaseID'])) { /* On a package base details page. */ $base_id = $row['ID']; } -$include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); -$count = pkgbase_comments_count($base_id, $include_deleted); +if (!isset($count)) { + $count = pkgbase_comments_count($base_id, $include_deleted); +} ?> <div id="news"> <h3> - <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments' , $count) ?> (<?= $count ?>)"><?= __('Latest Comments') ?></a> - <span class="arrow"></span> + <?php if (!isset($comments)): ?> + <?php $comments = $pinned ?> + <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments' , $count) ?> (<?= $count ?>)"><?= __('Pinned Comments') ?></a> + <span class="arrow"></span> + <?php else: ?> + <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments' , $count) ?> (<?= $count ?>)"><?= __('Latest Comments') ?></a> + <span class="arrow"></span> + <?php endif; ?> </h3> <?php while (list($indx, $row) = each($comments)): ?> @@ -56,6 +63,30 @@ $count = pkgbase_comments_count($base_id, $include_deleted); <?php if (!$row['DelUsersID'] && can_edit_comment_array($row)): ?> <a href="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name) . 'edit-comment/?comment_id=' . $row['ID'], ENT_QUOTES) ?>" class="edit-comment" title="<?= __('Edit comment') ?>"><img src="/images/pencil.min.svg" alt="<?= __('Edit comment') ?>" width="11" height="11"></a> <?php endif; ?> + + <?php if (!$row['DelUsersID'] && !$row['PinnedUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_PinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Pin') ?>" width="11" height="11" + alt="<?= __('Pin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> + + <?php if (!$row['DelUsersID'] && $row['PinnedUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_UnpinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Unpin') ?>" width="11" height="11" + alt="<?= __('Unin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> </h4> <div class="article-content<?php if ($row['DelUsersID']): ?> comment-deleted<?php endif; ?>"> <p> @@ -64,7 +95,7 @@ $count = pkgbase_comments_count($base_id, $include_deleted); </div> <?php endwhile; ?> -<?php if ($count > 10 && !isset($_GET['comments'])): ?> +<?php if ($count > 10 && !isset($_GET['comments']) && !isset($pinned)): ?> <h3> <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments') ?> (<?= $count ?>)"><?= __('All comments', $count) ?></a> </h3> -- 2.6.3
Adds functions and credential information to pin comments before others. This needs two extra columns (PinnedTS and PinnedUsersID) to the PackageComments table. Implements FS#10863 Signed-off-by: Mark Weiman <mark.weiman@markzz.com> --- web/html/css/aurweb.css | 18 ++++++++-- web/html/pkgbase.php | 4 +++ web/lib/credentials.inc.php | 2 ++ web/lib/pkgbasefuncs.inc.php | 82 +++++++++++++++++++++++++++++++++++++++++-- web/lib/pkgfuncs.inc.php | 51 ++++++++++++++++++++++++++- web/template/pkg_comments.php | 41 +++++++++++++++++++--- 6 files changed, 187 insertions(+), 11 deletions(-) diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index 11af747..5b36df0 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -101,7 +101,7 @@ color: #999; } -.delete-comment-form, .edit-comment { +.delete-comment-form, .pin-comment-form, .edit-comment { float: right; margin-left: 8px; } @@ -118,12 +118,26 @@ opacity: 0.6; } -.delete-comment:hover, .edit-comment:hover { +.delete-comment:hover, .edit-comment:hover, .pin-comment:hover { -webkit-filter: none; filter: none; opacity: 1; } +.pin-comment { + float: right; + font-weight: 600; + background: none!important; + border: none; + padding: 0!important; + font: inherit; + cursor: pointer; + color: #3366aa; + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + opacity: 0.6; +} + .ajax-loader { float: right; position: relative; diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cbbf3cc..6f0de08 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -99,6 +99,10 @@ if (check_token()) { list($ret, $output) = pkgbase_notify($ids, false); } elseif (current_action("do_DeleteComment")) { list($ret, $output) = pkgbase_delete_comment(); + } elseif (current_action("do_PinComment")) { + list($ret, $output) = pkgbase_pin_comment(); + } elseif (current_action("do_UnpinComment")) { + list($ret, $output) = pkgbase_unpin_comment(); } elseif (current_action("do_SetKeywords")) { list($ret, $output) = pkgbase_set_keywords($base_id, preg_split("/[\s,;]+/", $_POST['keywords'], -1, PREG_SPLIT_NO_EMPTY)); } elseif (current_action("do_FileRequest")) { diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index 648d78c..71bf5ff 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -8,6 +8,7 @@ define("CRED_ACCOUNT_SEARCH", 5); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_VIEW_DELETED", 22); define("CRED_COMMENT_EDIT", 25); +define("CRED_COMMENT_PIN", 26); define("CRED_PKGBASE_ADOPT", 7); define("CRED_PKGBASE_SET_KEYWORDS", 8); define("CRED_PKGBASE_DELETE", 9); @@ -60,6 +61,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_COMMENT_DELETE: case CRED_COMMENT_VIEW_DELETED: case CRED_COMMENT_EDIT: + case CRED_COMMENT_PIN: case CRED_PKGBASE_ADOPT: case CRED_PKGBASE_SET_KEYWORDS: case CRED_PKGBASE_DELETE: diff --git a/web/lib/pkgbasefuncs.inc.php b/web/lib/pkgbasefuncs.inc.php index afccc7d..ea3ce0d 100644 --- a/web/lib/pkgbasefuncs.inc.php +++ b/web/lib/pkgbasefuncs.inc.php @@ -36,10 +36,11 @@ function pkgbase_comments_count($base_id, $include_deleted) { * @param int $base_id The package base ID to get comments for * @param int $limit Maximum number of comments to return (0 means unlimited) * @param bool $include_deleted True if deleted comments should be included + * @param bool $show_only_pinned True when only pinned comments are to be included * * @return array All package comment information for a specific package base */ -function pkgbase_comments($base_id, $limit, $include_deleted) { +function pkgbase_comments($base_id, $limit, $include_deleted, $show_only_pinned=false) { $base_id = intval($base_id); $limit = intval($limit); if (!$base_id) { @@ -49,11 +50,17 @@ function pkgbase_comments($base_id, $limit, $include_deleted) { $dbh = DB::connect(); $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, "; $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, "; - $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments "; + $q.= "DelUsersID, C.UserName AS DelUserName, "; + $q.= "PinnedUsersID, D.UserName AS PinnedUserName FROM PackageComments "; $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID "; $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID "; + $q.= "LEFT JOIN Users D ON PackageComments.PinnedUsersID = D.ID "; $q.= "WHERE PackageBaseID = " . $base_id . " "; + + if ($show_only_pinned) { + $q.= "AND PinnedUsersID IS NOT NULL "; + } if (!$include_deleted) { $q.= "AND DelUsersID IS NULL "; } @@ -111,6 +118,67 @@ function pkgbase_add_comment($base_id, $uid, $comment) { } /** + * Pin a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_pin_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_pin_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET PinnedUsersID = ".$uid.", "; + $q.= "PinnedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been pinned.")); + } else { + return array(false, __("You are not allowed to pin this comment.")); + } +} + +/** + * Unpin a package comment + * + * @return array Tuple of success/failure indicator and error message + */ +function pkgbase_unpin_comment() { + $uid = uid_from_sid($_COOKIE["AURSID"]); + if (!$uid) { + return array(false, __("You must be logged in before you can edit package information.")); + } + + if (isset($_POST["comment_id"])) { + $comment_id = $_POST["comment_id"]; + } else { + return array(false, __("Missing comment ID.")); + } + + $dbh = DB::connect(); + if (can_pin_comment($comment_id)) { + $q = "UPDATE PackageComments "; + $q.= "SET PinnedUsersID = NULL, "; + $q.= "PinnedTS = UNIX_TIMESTAMP() "; + $q.= "WHERE ID = ".intval($comment_id); + $dbh->exec($q); + return array(true, __("Comment has been unpinned.")); + } else { + return array(false, __("You are not allowed to unpin this comment.")); + } +} + +/** + * Get a list of all packages a logged-in user has voted for * * @param string $sid The session ID of the visitor @@ -196,9 +264,17 @@ function pkgbase_display_details($base_id, $row, $SID="") { if ($SID) { include('pkg_comment_box.php'); } + + $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); + if (!empty($pinned)) { + include('pkg_comments.php'); + unset($pinned); + } $limit = isset($_GET['comments']) ? 0 : 10; - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); $comments = pkgbase_comments($base_id, $limit, $include_deleted); if (!empty($comments)) { include('pkg_comments.php'); diff --git a/web/lib/pkgfuncs.inc.php b/web/lib/pkgfuncs.inc.php index cedc360..c0ed99c 100644 --- a/web/lib/pkgfuncs.inc.php +++ b/web/lib/pkgfuncs.inc.php @@ -83,6 +83,47 @@ function can_edit_comment_array($comment) { } /** + * Determine if the user can pin a specific package comment + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the backend side of comment pinning. + * + * @param string $comment_id The comment ID in the database + * + * @return bool True if the user can pin the comment, otherwise false + */ +function can_pin_comment($comment_id=0) { + $dbh = DB::connect(); + + $q = "SELECT MaintainerUID FROM PackageBases AS pb "; + $q.= "LEFT JOIN PackageComments AS pc ON pb.ID = pc.PackageBaseID "; + $q.= "WHERE pc.ID = " . intval($comment_id); + $result = $dbh->query($q); + + if (!$result) { + return false; + } + + $uid = $result->fetch(PDO::FETCH_COLUMN, 0); + + return has_credential(CRED_COMMENT_PIN, array($uid)); +} + +/** + * Determine if the user can edit a specific package comment using an array + * + * Only the Package Maintainer, Trusted Users, and Developers can pin + * comments. This function is used for the frontend side of comment pinning. + * + * @param array $comment All database information relating a specific comment + * + * @return bool True if the user can edit the comment, otherwise false + */ +function can_pin_comment_array($comment) { + return can_pin_comment($comment['ID']); +} + +/** * Check to see if the package name already exists in the database * * @param string $name The package name to check @@ -581,9 +622,17 @@ function pkg_display_details($id=0, $row, $SID="") { if ($SID) { include('pkg_comment_box.php'); } + + $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); + + $limit_pinned = isset($_GET['pinned']) ? 0 : 5; + $pinned = pkgbase_comments($base_id, $limit_pinned, false, true); + if (!empty($pinned)) { + include('pkg_comments.php'); + unset($pinned); + } $limit = isset($_GET['comments']) ? 0 : 10; - $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); $comments = pkgbase_comments($base_id, $limit, $include_deleted); if (!empty($comments)) { include('pkg_comments.php'); diff --git a/web/template/pkg_comments.php b/web/template/pkg_comments.php index 21ce16f..8f1fb9f 100644 --- a/web/template/pkg_comments.php +++ b/web/template/pkg_comments.php @@ -6,13 +6,20 @@ if (isset($row['BaseID'])) { /* On a package base details page. */ $base_id = $row['ID']; } -$include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED); -$count = pkgbase_comments_count($base_id, $include_deleted); +if (!isset($count)) { + $count = pkgbase_comments_count($base_id, $include_deleted); +} ?> <div id="news"> <h3> - <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments' , $count) ?> (<?= $count ?>)"><?= __('Latest Comments') ?></a> - <span class="arrow"></span> + <?php if (!isset($comments)): ?> + <?php $comments = $pinned ?> + <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments' , $count) ?> (<?= $count ?>)"><?= __('Pinned Comments') ?></a> + <span class="arrow"></span> + <?php else: ?> + <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments' , $count) ?> (<?= $count ?>)"><?= __('Latest Comments') ?></a> + <span class="arrow"></span> + <?php endif; ?> </h3> <?php while (list($indx, $row) = each($comments)): ?> @@ -56,6 +63,30 @@ $count = pkgbase_comments_count($base_id, $include_deleted); <?php if (!$row['DelUsersID'] && can_edit_comment_array($row)): ?> <a href="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name) . 'edit-comment/?comment_id=' . $row['ID'], ENT_QUOTES) ?>" class="edit-comment" title="<?= __('Edit comment') ?>"><img src="/images/pencil.min.svg" alt="<?= __('Edit comment') ?>" width="11" height="11"></a> <?php endif; ?> + + <?php if (!$row['DelUsersID'] && !$row['PinnedUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_PinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Pin') ?>" width="11" height="11" + alt="<?= __('Pin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> + + <?php if (!$row['DelUsersID'] && $row['PinnedUsersID'] && can_pin_comment_array($row)): ?> + <form class="pin-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($pkgbase_name), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_UnpinComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="submit" class="pin-comment" value="<?= __('Unpin') ?>" width="11" height="11" + alt="<?= __('Unin comment') ?>" title="<?= __('Pin comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif; ?> </h4> <div class="article-content<?php if ($row['DelUsersID']): ?> comment-deleted<?php endif; ?>"> <p> @@ -64,7 +95,7 @@ $count = pkgbase_comments_count($base_id, $include_deleted); </div> <?php endwhile; ?> -<?php if ($count > 10 && !isset($_GET['comments'])): ?> +<?php if ($count > 10 && !isset($_GET['comments']) && !isset($pinned)): ?> <h3> <a href="<?= htmlentities(get_pkgbase_uri($pkgbase_name), ENT_QUOTES) . '?' . mkurl('comments=all') ?>" title="<?= __('View all comments') ?> (<?= $count ?>)"><?= __('All comments', $count) ?></a> </h3> -- 2.6.3
participants (2)
-
Lukas Fleischer
-
Mark Weiman