Signed-off-by: Johannes Löthberg <johannes@kyriasis.com> --- v2: Actually add the new template, d'oh. web/html/account.php | 69 +++++++++++++++- web/html/css/aurweb.css | 17 ++++ web/html/index.php | 2 + web/html/pkgbase.php | 7 +- web/lib/acctfuncs.inc.php | 41 ++++++++++ web/lib/credentials.inc.php | 2 + web/template/account_comments.php | 125 +++++++++++++++++++++++++++++ web/template/account_edit_form.php | 1 + 8 files changed, 261 insertions(+), 3 deletions(-) create mode 100644 web/template/account_comments.php diff --git a/web/html/account.php b/web/html/account.php index c30a89a..955aa4d 100644 --- a/web/html/account.php +++ b/web/html/account.php @@ -8,7 +8,7 @@ include_once('acctfuncs.inc.php'); # access Account specific functions $action = in_request("Action"); $need_userinfo = array( - "DisplayAccount", "DeleteAccount", "AccountInfo", "UpdateAccount" + "DisplayAccount", "DeleteAccount", "AccountInfo", "UpdateAccount", "ListComments" ); if (in_array($action, $need_userinfo)) { @@ -54,6 +54,8 @@ if ($action == "UpdateAccount") { if ($action == "AccountInfo") { html_header(__('Account') . ' ' . $row['Username']); +} elseif ($action == "ListComments") { + html_header(__('Comments for') . ' ' . $row['Username']); } else { html_header(__('Accounts')); } @@ -61,7 +63,11 @@ if ($action == "AccountInfo") { # Main page processing here # echo "<div class=\"box\">\n"; -echo " <h2>".__("Accounts")."</h2>\n"; +if ($action == "ListComments") { + echo " <h2>".__("Comments for").' '.$row['Username']."</h2>\n"; +} else { + echo " <h2>".__("Accounts")."</h2>\n"; +} if (isset($_COOKIE["AURSID"])) { if ($action == "SearchAccounts") { @@ -166,6 +172,65 @@ if (isset($_COOKIE["AURSID"])) { $row["Username"]); } + } elseif ($action == "ListComments") { + if (has_credential(CRED_ACCOUNT_LIST_COMMENTS)) { + # display the comment list if they're a TU/dev + # + + /* Sanitize paging variables. */ + if (isset($_GET["O"])) { + $_GET["O"] = max(intval($_GET["O"]), 0); + } else { + $_GET["O"] = 0; + } + + if (isset($_GET["PP"])) { + $_GET["PP"] = bound(intval($_GET["PP"]), 5, 250); + } else { + $_GET["PP"] = 10; + } + + $total = account_comments_count($row["ID"]); + + /* Calculate the results to use. */ + $first = $_GET['O'] + 1; + + /* Calculation of pagination links. */ + $per_page = ($_GET['PP'] > 0) ? $_GET['PP'] : 50; + $current = ceil($first / $per_page); + $pages = ceil($total / $per_page); + $templ_pages = array(); + + if ($current > 1) { + $templ_pages['« ' . __('First')] = 0; + $templ_pages['‹ ' . __('Previous')] = ($current - 2) * $per_page; + } + + if ($current - 5 > 1) + $templ_pages["..."] = false; + + for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) { + $templ_pages[$i] = ($i - 1) * $per_page; + } + + if ($current + 5 < $pages) + $templ_pages["... "] = false; + + if ($current < $pages) { + $templ_pages[__('Next') . ' ›'] = $current * $per_page; + $templ_pages[__('Last') . ' »'] = ($pages - 1) * $per_page; + } + + $username = $row["Username"]; + $userid = $row["ID"]; + $comments = account_comments($row["ID"], $_GET["PP"], $_GET["O"]); + + include('account_comments.php'); + + } else { + print __("You are not allowed to access this area."); + } + } else { if (has_credential(CRED_ACCOUNT_SEARCH)) { # display the search page if they're a TU/dev diff --git a/web/html/css/aurweb.css b/web/html/css/aurweb.css index f5e1037..ce54a28 100644 --- a/web/html/css/aurweb.css +++ b/web/html/css/aurweb.css @@ -148,3 +148,20 @@ label.confirmation, color: red; font-weight: bold; } + +.commentlist-nav .page { + margin: 0 .25em; +} + +#commentlist-results .commentlist-nav { + float: right; + margin-top: -2.2em; +} + +.commentlist-nav .prev { + margin-right: 1em; +} + +.commentlist-nav .next { + margin-right: 1em; +} diff --git a/web/html/index.php b/web/html/index.php index 2c53cdd..b2cd840 100644 --- a/web/html/index.php +++ b/web/html/index.php @@ -142,6 +142,8 @@ if (!empty($tokens[1]) && '/' . $tokens[1] == get_pkg_route()) { $_REQUEST['Action'] = "UpdateAccount"; } elseif ($tokens[3] == 'delete') { $_REQUEST['Action'] = "DeleteAccount"; + } elseif ($tokens[3] == 'comments') { + $_REQUEST['Action'] = "ListComments"; } else { header("HTTP/1.0 404 Not Found"); include "./404.php"; diff --git a/web/html/pkgbase.php b/web/html/pkgbase.php index cf9a6c6..8a0c363 100644 --- a/web/html/pkgbase.php +++ b/web/html/pkgbase.php @@ -43,6 +43,7 @@ if (isset($_POST['IDs'])) { /* Perform package base actions. */ $via = isset($_POST['via']) ? $_POST['via'] : NULL; +$return_to = isset($_POST['return_to']) ? $_POST['return_to'] : NULL; $ret = false; $output = ""; $fragment = ""; @@ -133,7 +134,11 @@ if (check_token()) { /* Redirect back to package request page on success. */ header('Location: ' . get_pkgreq_route()); exit(); - } if (isset($base_id)) { + } elseif ((current_action("do_DeleteComment") || + current_action("do_UndeleteComment")) && $return_to) { + header('Location: ' . $return_to); + exit(); + } elseif (isset($base_id)) { /* Redirect back to package base page on success. */ header('Location: ' . get_pkgbase_uri($pkgbase_name) . $fragment); exit(); diff --git a/web/lib/acctfuncs.inc.php b/web/lib/acctfuncs.inc.php index df57375..9536139 100644 --- a/web/lib/acctfuncs.inc.php +++ b/web/lib/acctfuncs.inc.php @@ -1403,3 +1403,44 @@ function accept_terms($uid, $termrev) { $dbh->exec($q); } } + +function account_comments($uid, $limit, $offset=0) { + $dbh = DB::connect(); + $q = "SELECT PackageComments.ID, Comments, "; + $q.= "PackageBaseId, CommentTS, DelTS, EditedTS, B.UserName AS EditUserName, "; + $q.= "C.UserName as DelUserName, RenderedComment, "; + $q.= "PB.ID as PackageBaseID, PB.Name as PackageBaseName "; + $q.= "FROM PackageComments "; + $q.= "LEFT JOIN PackageBases PB ON PackageComments.PackageBaseID = PB.ID "; + $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 A.ID = " . $dbh->quote($uid) . " "; + $q.= "ORDER BY CommentTS DESC"; + + if ($limit > 0) { + $q.=" LIMIT " . $limit; + } + + if ($offset > 0) { + $q.=" OFFSET " . $offset; + } + + $result = $dbh->query($q); + if (!$result) { + return null; + } + + return $result->fetchAll(); +} + +function account_comments_count($uid) { + $dbh = DB::connect(); + $q = "SELECT COUNT(*) "; + $q.= "FROM PackageComments "; + $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID "; + $q.= "WHERE A.ID = " . $dbh->quote($uid); + + $result = $dbh->query($q); + return $result->fetch(PDO::FETCH_NUM)[0]; +} diff --git a/web/lib/credentials.inc.php b/web/lib/credentials.inc.php index d8698a8..5d90cfc 100644 --- a/web/lib/credentials.inc.php +++ b/web/lib/credentials.inc.php @@ -5,6 +5,7 @@ define("CRED_ACCOUNT_EDIT", 2); define("CRED_ACCOUNT_EDIT_DEV", 3); define("CRED_ACCOUNT_LAST_LOGIN", 4); define("CRED_ACCOUNT_SEARCH", 5); +define("CRED_ACCOUNT_LIST_COMMENTS", 28); define("CRED_COMMENT_DELETE", 6); define("CRED_COMMENT_UNDELETE", 27); define("CRED_COMMENT_VIEW_DELETED", 22); @@ -59,6 +60,7 @@ function has_credential($credential, $approved_users=array()) { case CRED_ACCOUNT_EDIT: case CRED_ACCOUNT_LAST_LOGIN: case CRED_ACCOUNT_SEARCH: + case CRED_ACCOUNT_LIST_COMMENTS: case CRED_COMMENT_DELETE: case CRED_COMMENT_UNDELETE: case CRED_COMMENT_VIEW_DELETED: diff --git a/web/template/account_comments.php b/web/template/account_comments.php new file mode 100644 index 0000000..aedcc55 --- /dev/null +++ b/web/template/account_comments.php @@ -0,0 +1,125 @@ +<div id="commentlist-results"> +<?php if (count($templ_pages) > 1): ?> +<p class="commentlist-nav"> + <?php foreach ($templ_pages as $pagenr => $pagestart): ?> + <?php if ($pagestart === false): ?> + <span class="page"><?= $pagenr ?></span> + <?php elseif ($pagestart + 1 == $first): ?> + <span class="page"><?= $pagenr ?></span> + <?php else: ?> + <a class="page" href="<?= get_uri('/account/' . $username . '/comments/'); ?>?<?= mkurl('O=' . $pagestart) ?>"><?= $pagenr ?></a> + <?php endif; ?> + <?php endforeach; ?> +</p> +<?php endif; ?> +</div> + +<?php while (list($indx, $row) = each($comments)): ?> + <?php + $date_fmtd = date('Y-m-d H:i', $row['CommentTS']); + $pkg_uri = '<a href=' . htmlspecialchars(get_pkg_uri($row['PackageBaseName']), ENT_QUOTES) . '>' . htmlspecialchars($row['PackageBaseName']) . '</a></td>'; + $heading = __('Commented on package %s on %s', $pkg_uri, $date_fmtd); + + $is_deleted = $row['DelTS']; + $is_edited = $row['EditedTS']; + + if ($userid && $is_deleted) { + $date_fmtd = date('Y-m-d H:i', $row['DelTS']); + $heading .= ' <span class="edited">('; + if ($row['DelUserName']) { + $user_fmtd = html_format_username($row['DelUserName']); + $heading .= __('deleted on %s by %s', $date_fmtd, $user_fmtd); + } else { + $heading .= __('deleted on %s', $date_fmtd); + } + $heading .= ')</span>'; + } elseif ($userid && $is_edited) { + $date_fmtd = date('Y-m-d H:i', $row['EditedTS']); + $heading .= ' <span class="edited">('; + if ($row['EditUserName']) { + $user_fmtd = html_format_username($row['EditUserName']); + $heading .= __('edited on %s by %s', $date_fmtd, $user_fmtd); + } else { + $heading .= __('edited on %s', $date_fmtd); + } + $heading .= ')</span>'; + } + ?> + <h4 id="<?= isset($pinned) ? "pinned-" : "comment-" ?><?= $row['ID'] ?>"<?php if ($is_deleted): ?> class="comment-deleted"<?php endif; ?>> + <?= $heading ?> + <?php if ($is_deleted && has_credential(CRED_COMMENT_UNDELETE)): ?> + <form class="undelete-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($row['PackageBaseName']), ENT_QUOTES); ?>"> + <fieldset style="display:inline;"> + <input type="hidden" name="action" value="do_UndeleteComment" /> + <input type="hidden" name="comment_id" value="<?= $row['ID'] ?>" /> + <input type="hidden" name="token" value="<?= htmlspecialchars($_COOKIE['AURSID']) ?>" /> + <input type="hidden" name="return_to" value="<?= htmlspecialchars($_SERVER["REQUEST_URI"], ENT_QUOTES) ?>" /> + <input type="image" class="undelete-comment" src="/images/action-undo.min.svg" width="11" height="11" alt="<?= __('Undelete comment') ?>" title="<?= __('Undelete comment') ?>" name="submit" value="1" /> + </fieldset> + </form> + <?php endif;?> + + <?php if (!$is_deleted && can_delete_comment_array(array('UsersID' => $userid))): ?> + <form class="delete-comment-form" method="post" action="<?= htmlspecialchars(get_pkgbase_uri($row['PackageBaseName']), 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="hidden" name="return_to" value="<?= htmlspecialchars($_SERVER["REQUEST_URI"], ENT_QUOTES) ?>" /> + <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 (!$is_deleted && can_edit_comment_array(array('UsersID' => $userid))): ?> + <a href="<?= htmlspecialchars(get_pkgbase_uri($row['PackageBaseName']) . '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; ?> + </h4> + + <div id="<?= isset($pinned) ? "pinned-" : "comment-" ?><?= $row['ID'] ?>-content" class="article-content<?php if ($is_deleted): ?> comment-deleted<?php endif; ?>"> + <div> + <?php if (!empty($row['RenderedComment'])): ?> + <?= $row['RenderedComment'] ?> + <?php else: ?> + <p> + <?= parse_comment($row['Comments']) ?> + </p> + <?php endif; ?> + </div> + </div> +<?php endwhile; ?> +<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($row["PackageBaseID"]) ?>, + base_name: <?= json_encode($row['PackageBaseName']) ?> + }, 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> diff --git a/web/template/account_edit_form.php b/web/template/account_edit_form.php index 6eff81b..38d5274 100644 --- a/web/template/account_edit_form.php +++ b/web/template/account_edit_form.php @@ -2,6 +2,7 @@ <p> <?= __('Click %shere%s if you want to permanently delete this account.', '<a href="' . get_user_uri($N) . 'delete/' . '">', '</a>') ?> <?= __('Click %shere%s for user details.', '<a href="' . get_user_uri($N) . '">', '</a>') ?> + <?= __('Click %shere%s to list the comments made by this account.', '<a href="' . get_user_uri($N) . 'comments/' . '">', '</a>') ?> </p> <form id="edit-profile-form" action="<?= get_user_uri($N) . 'update/'; ?>" method="post"> -- 2.18.0