Implement capability to pin comments above others
[aur.git] / web / lib / pkgbasefuncs.inc.php
blob7076c3157bcb6178cf6a1242147bbf3532d0bd33
1 <?php
3 include_once("pkgreqfuncs.inc.php");
5 /**
6 * Get the number of non-deleted comments for a specific package base
8 * @param string $base_id The package base ID to get comment count for
9 * @param bool $include_deleted True if deleted comments should be included
10 * @param bool $only_pinned True if only pinned comments should be included
12 * @return string The number of comments left for a specific package
14 function pkgbase_comments_count($base_id, $include_deleted, $only_pinned=false) {
15 $base_id = intval($base_id);
16 if (!$base_id) {
17 return null;
20 $dbh = DB::connect();
21 $q = "SELECT COUNT(*) FROM PackageComments ";
22 $q.= "WHERE PackageBaseID = " . $base_id . " ";
23 if (!$include_deleted) {
24 $q.= "AND DelUsersID IS NULL";
26 if ($only_pinned) {
27 $q.= "AND NOT PinnedTS = 0";
29 $result = $dbh->query($q);
30 if (!$result) {
31 return null;
34 return $result->fetchColumn(0);
37 /**
38 * Get all package comment information for a specific package base
40 * @param int $base_id The package base ID to get comments for
41 * @param int $limit Maximum number of comments to return (0 means unlimited)
42 * @param bool $include_deleted True if deleted comments should be included
43 * @param bool $only_pinned True when only pinned comments are to be included
45 * @return array All package comment information for a specific package base
47 function pkgbase_comments($base_id, $limit, $include_deleted, $only_pinned=false) {
48 $base_id = intval($base_id);
49 $limit = intval($limit);
50 if (!$base_id) {
51 return null;
54 $dbh = DB::connect();
55 $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, ";
56 $q.= "PackageBaseID, CommentTS, EditedTS, B.UserName AS EditUserName, ";
57 $q.= "DelUsersID, C.UserName AS DelUserName, ";
58 $q.= "PinnedTS FROM PackageComments ";
59 $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID ";
60 $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID ";
61 $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID ";
62 $q.= "WHERE PackageBaseID = " . $base_id . " ";
64 if (!$include_deleted) {
65 $q.= "AND DelUsersID IS NULL ";
67 if ($only_pinned) {
68 $q.= "AND NOT PinnedTS = 0 ";
70 $q.= "ORDER BY CommentTS DESC";
71 if ($limit > 0) {
72 $q.=" LIMIT " . $limit;
74 $result = $dbh->query($q);
75 if (!$result) {
76 return null;
79 return $result->fetchAll();
82 /**
83 * Add a comment to a package page and send out appropriate notifications
85 * @param string $base_id The package base ID to add the comment on
86 * @param string $uid The user ID of the individual who left the comment
87 * @param string $comment The comment left on a package page
89 * @return void
91 function pkgbase_add_comment($base_id, $uid, $comment) {
92 $dbh = DB::connect();
94 if (trim($comment) == '') {
95 return array(false, __('Comment cannot be empty.'));
98 $q = "INSERT INTO PackageComments ";
99 $q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES (";
100 $q.= intval($base_id) . ", " . $uid . ", ";
101 $q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())";
102 $dbh->exec($q);
104 notify(array('comment', $uid, $base_id), $comment);
106 return array(true, __('Comment has been added.'));
110 * Pin/unpin a package comment
112 * @param bool $unpin True if unpinning rather than pinning
114 * @return array Tuple of success/failure indicator and error message
116 function pkgbase_pin_comment($unpin=false) {
117 $uid = uid_from_sid($_COOKIE["AURSID"]);
119 if (!$uid) {
120 return array(false, __("You must be logged in before you can edit package information."));
123 if (isset($_POST["comment_id"])) {
124 $comment_id = $_POST["comment_id"];
125 } else {
126 return array(false, __("Missing comment ID."));
129 if (!$unpin) {
130 if (pkgbase_comments_count($_POST['package_base'], false, true) >= 5){
131 return array(false, __("No more than 5 comments can be pinned."));
135 if (!can_pin_comment($comment_id)) {
136 if (!$unpin) {
137 return array(false, __("You are not allowed to pin this comment."));
138 } else {
139 return array(false, __("You are not allowed to unpin this comment."));
143 $dbh = DB::connect();
144 $q = "UPDATE PackageComments ";
145 if (!$unpin) {
146 $q.= "SET PinnedTS = UNIX_TIMESTAMP() ";
147 } else {
148 $q.= "SET PinnedTS = 0 ";
150 $q.= "WHERE ID = " . intval($comment_id);
151 $dbh->exec($q);
153 if (!$unpin) {
154 return array(true, __("Comment has been pinned."));
155 } else {
156 return array(true, __("Comment has been unpinned."));
162 * Get a list of all packages a logged-in user has voted for
164 * @param string $sid The session ID of the visitor
166 * @return array All packages the visitor has voted for
168 function pkgbase_votes_from_sid($sid="") {
169 $pkgs = array();
170 if (!$sid) {return $pkgs;}
171 $dbh = DB::connect();
172 $q = "SELECT PackageBaseID ";
173 $q.= "FROM PackageVotes, Users, Sessions ";
174 $q.= "WHERE Users.ID = Sessions.UsersID ";
175 $q.= "AND Users.ID = PackageVotes.UsersID ";
176 $q.= "AND Sessions.SessionID = " . $dbh->quote($sid);
177 $result = $dbh->query($q);
178 if ($result) {
179 while ($row = $result->fetch(PDO::FETCH_NUM)) {
180 $pkgs[$row[0]] = 1;
183 return $pkgs;
187 * Get the package base details
189 * @param string $id The package base ID to get description for
191 * @return array The package base's details OR error message
193 function pkgbase_get_details($base_id) {
194 $dbh = DB::connect();
196 $q = "SELECT PackageBases.ID, PackageBases.Name, ";
197 $q.= "PackageBases.NumVotes, PackageBases.Popularity, ";
198 $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, ";
199 $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, ";
200 $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, ";
201 $q.= "PackageBases.FlaggerUID, ";
202 $q.= "(SELECT COUNT(*) FROM PackageRequests ";
203 $q.= " WHERE PackageRequests.PackageBaseID = PackageBases.ID ";
204 $q.= " AND PackageRequests.Status = 0) AS RequestCount ";
205 $q.= "FROM PackageBases ";
206 $q.= "WHERE PackageBases.ID = " . intval($base_id);
207 $result = $dbh->query($q);
209 $row = array();
211 if (!$result) {
212 $row['error'] = __("Error retrieving package details.");
214 else {
215 $row = $result->fetch(PDO::FETCH_ASSOC);
216 if (empty($row)) {
217 $row['error'] = __("Package details could not be found.");
221 return $row;
225 * Display the package base details page
227 * @param string $id The package base ID to get details page for
228 * @param array $row Package base details retrieved by pkgbase_get_details()
229 * @param string $SID The session ID of the visitor
231 * @return void
233 function pkgbase_display_details($base_id, $row, $SID="") {
234 $dbh = DB::connect();
236 if (isset($row['error'])) {
237 print "<p>" . $row['error'] . "</p>\n";
239 else {
240 $pkgbase_name = pkgbase_name_from_id($base_id);
242 include('pkgbase_details.php');
244 if ($SID) {
245 include('pkg_comment_box.php');
248 $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED);
250 $limit_pinned = isset($_GET['pinned']) ? 0 : 5;
251 $pinned = pkgbase_comments($base_id, $limit_pinned, false, true);
252 if (!empty($pinned)) {
253 include('pkg_comments.php');
254 unset($pinned);
257 $limit = isset($_GET['comments']) ? 0 : 10;
258 $comments = pkgbase_comments($base_id, $limit, $include_deleted);
259 if (!empty($comments)) {
260 include('pkg_comments.php');
266 * Convert a list of package IDs into a list of corresponding package bases.
268 * @param array|int $ids Array of package IDs to convert
270 * @return array|int List of package base IDs
272 function pkgbase_from_pkgid($ids) {
273 $dbh = DB::connect();
275 if (is_array($ids)) {
276 $q = "SELECT PackageBaseID FROM Packages ";
277 $q.= "WHERE ID IN (" . implode(",", $ids) . ")";
278 $result = $dbh->query($q);
279 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
280 } else {
281 $q = "SELECT PackageBaseID FROM Packages ";
282 $q.= "WHERE ID = " . $ids;
283 $result = $dbh->query($q);
284 return $result->fetch(PDO::FETCH_COLUMN, 0);
289 * Retrieve ID of a package base by name
291 * @param string $name The package base name to retrieve the ID for
293 * @return int The ID of the package base
295 function pkgbase_from_name($name) {
296 $dbh = DB::connect();
297 $q = "SELECT ID FROM PackageBases WHERE Name = " . $dbh->quote($name);
298 $result = $dbh->query($q);
299 return $result->fetch(PDO::FETCH_COLUMN, 0);
303 * Retrieve the name of a package base given its ID
305 * @param int $base_id The ID of the package base to query
307 * @return string The name of the package base
309 function pkgbase_name_from_id($base_id) {
310 $dbh = DB::connect();
311 $q = "SELECT Name FROM PackageBases WHERE ID = " . intval($base_id);
312 $result = $dbh->query($q);
313 return $result->fetch(PDO::FETCH_COLUMN, 0);
317 * Get the names of all packages belonging to a package base
319 * @param int $base_id The ID of the package base
321 * @return array The names of all packages belonging to the package base
323 function pkgbase_get_pkgnames($base_id) {
324 $dbh = DB::connect();
325 $q = "SELECT Name FROM Packages WHERE PackageBaseID = " . intval($base_id);
326 $result = $dbh->query($q);
327 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
331 * Delete all packages belonging to a package base
333 * @param int $base_id The ID of the package base
335 * @return void
337 function pkgbase_delete_packages($base_id) {
338 $dbh = DB::connect();
339 $q = "DELETE FROM Packages WHERE PackageBaseID = " . intval($base_id);
340 $dbh->exec($q);
344 * Retrieve the maintainer of a package base given its ID
346 * @param int $base_id The ID of the package base to query
348 * @return int The user ID of the current package maintainer
350 function pkgbase_maintainer_uid($base_id) {
351 $dbh = DB::connect();
352 $q = "SELECT MaintainerUID FROM PackageBases WHERE ID = " . intval($base_id);
353 $result = $dbh->query($q);
354 return $result->fetch(PDO::FETCH_COLUMN, 0);
358 * Retrieve the maintainers of an array of package bases given by their ID
360 * @param int $base_ids The array of IDs of the package bases to query
362 * @return int The user ID of the current package maintainer
364 function pkgbase_maintainer_uids($base_ids) {
365 $dbh = DB::connect();
366 $q = "SELECT MaintainerUID FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")";
367 $result = $dbh->query($q);
368 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
372 * Flag package(s) as out-of-date
374 * @param array $base_ids Array of package base IDs to flag/unflag
375 * @param string $comment The comment to add
377 * @return array Tuple of success/failure indicator and error message
379 function pkgbase_flag($base_ids, $comment) {
380 if (!has_credential(CRED_PKGBASE_FLAG)) {
381 return array(false, __("You must be logged in before you can flag packages."));
384 $base_ids = sanitize_ids($base_ids);
385 if (empty($base_ids)) {
386 return array(false, __("You did not select any packages to flag."));
389 if (strlen($comment) < 3) {
390 return array(false, __("The selected packages have not been flagged, please enter a comment."));
393 $uid = uid_from_sid($_COOKIE['AURSID']);
394 $dbh = DB::connect();
396 $q = "UPDATE PackageBases SET ";
397 $q.= "OutOfDateTS = UNIX_TIMESTAMP(), FlaggerUID = " . $uid . ", ";
398 $q.= "FlaggerComment = " . $dbh->quote($comment) . " ";
399 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
400 $q.= "AND OutOfDateTS IS NULL";
401 $dbh->exec($q);
403 foreach ($base_ids as $base_id) {
404 notify(array('flag', $uid, $base_id), $comment);
407 return array(true, __("The selected packages have been flagged out-of-date."));
411 * Unflag package(s) as out-of-date
413 * @param array $base_ids Array of package base IDs to flag/unflag
415 * @return array Tuple of success/failure indicator and error message
417 function pkgbase_unflag($base_ids) {
418 $uid = uid_from_sid($_COOKIE["AURSID"]);
419 if (!$uid) {
420 return array(false, __("You must be logged in before you can unflag packages."));
423 $base_ids = sanitize_ids($base_ids);
424 if (empty($base_ids)) {
425 return array(false, __("You did not select any packages to unflag."));
428 $dbh = DB::connect();
430 $q = "UPDATE PackageBases SET ";
431 $q.= "OutOfDateTS = NULL ";
432 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
434 $maintainers = array_merge(pkgbase_maintainer_uids($base_ids), pkgbase_get_comaintainer_uids($base_ids));
435 if (!has_credential(CRED_PKGBASE_UNFLAG, $maintainers)) {
436 $q.= "AND (MaintainerUID = " . $uid . " OR FlaggerUID = " . $uid. ")";
439 $result = $dbh->exec($q);
441 if ($result) {
442 return array(true, __("The selected packages have been unflagged."));
447 * Delete package bases
449 * @param array $base_ids Array of package base IDs to delete
450 * @param int $merge_base_id Package base to merge the deleted ones into
451 * @param int $via Package request to close upon deletion
452 * @param bool $grant Allow anyone to delete the package base
454 * @return array Tuple of success/failure indicator and error message
456 function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) {
457 if (!$grant && !has_credential(CRED_PKGBASE_DELETE)) {
458 return array(false, __("You do not have permission to delete packages."));
461 $base_ids = sanitize_ids($base_ids);
462 if (empty($base_ids)) {
463 return array(false, __("You did not select any packages to delete."));
466 $dbh = DB::connect();
468 if ($merge_base_id) {
469 $merge_base_name = pkgbase_name_from_id($merge_base_id);
472 $uid = uid_from_sid($_COOKIE['AURSID']);
473 foreach ($base_ids as $base_id) {
474 if ($merge_base_id) {
475 notify(array('delete', $uid, $base_id, $merge_base_id));
476 } else {
477 notify(array('delete', $uid, $base_id));
482 * Close package request if the deletion was initiated through the
483 * request interface. NOTE: This needs to happen *before* the actual
484 * deletion. Otherwise, the former maintainer will not be included in
485 * the Cc list of the request notification email.
487 if ($via) {
488 pkgreq_close(intval($via), 'accepted', '');
491 /* Scan through pending deletion requests and close them. */
492 if (!$action) {
493 $username = username_from_sid($_COOKIE['AURSID']);
494 foreach ($base_ids as $base_id) {
495 $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id));
496 foreach ($pkgreq_ids as $pkgreq_id) {
497 pkgreq_close(intval($pkgreq_id), 'accepted',
498 'The user ' . $username .
499 ' deleted the package.', true);
504 if ($merge_base_id) {
505 /* Merge comments */
506 $q = "UPDATE PackageComments ";
507 $q.= "SET PackageBaseID = " . intval($merge_base_id) . " ";
508 $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")";
509 $dbh->exec($q);
511 /* Merge notifications */
512 $q = "SELECT DISTINCT UserID FROM CommentNotify cn ";
513 $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") ";
514 $q.= "AND NOT EXISTS (SELECT * FROM CommentNotify cn2 ";
515 $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " ";
516 $q.= "AND cn2.UserID = cn.UserID)";
517 $result = $dbh->query($q);
519 while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) {
520 $q = "INSERT INTO CommentNotify (UserID, PackageBaseID) ";
521 $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")";
522 $dbh->exec($q);
525 /* Merge votes */
526 foreach ($base_ids as $base_id) {
527 $q = "UPDATE PackageVotes ";
528 $q.= "SET PackageBaseID = " . intval($merge_base_id) . " ";
529 $q.= "WHERE PackageBaseID = " . $base_id . " ";
530 $q.= "AND UsersID NOT IN (";
531 $q.= "SELECT * FROM (SELECT UsersID ";
532 $q.= "FROM PackageVotes ";
533 $q.= "WHERE PackageBaseID = " . intval($merge_base_id);
534 $q.= ") temp)";
535 $dbh->exec($q);
538 $q = "UPDATE PackageBases ";
539 $q.= "SET NumVotes = (SELECT COUNT(*) FROM PackageVotes ";
540 $q.= "WHERE PackageBaseID = " . intval($merge_base_id) . ") ";
541 $q.= "WHERE ID = " . intval($merge_base_id);
542 $dbh->exec($q);
545 $q = "DELETE FROM Packages WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")";
546 $dbh->exec($q);
548 $q = "DELETE FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")";
549 $dbh->exec($q);
551 return array(true, __("The selected packages have been deleted."));
555 * Adopt or disown packages
557 * @param array $base_ids Array of package base IDs to adopt/disown
558 * @param bool $action Adopts if true, disowns if false. Adopts by default
559 * @param int $via Package request to close upon adoption
561 * @return array Tuple of success/failure indicator and error message
563 function pkgbase_adopt ($base_ids, $action=true, $via) {
564 $dbh = DB::connect();
566 $uid = uid_from_sid($_COOKIE["AURSID"]);
567 if (!$uid) {
568 if ($action) {
569 return array(false, __("You must be logged in before you can adopt packages."));
570 } else {
571 return array(false, __("You must be logged in before you can disown packages."));
575 /* Verify package ownership. */
576 $base_ids = sanitize_ids($base_ids);
578 $q = "SELECT ID FROM PackageBases ";
579 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
581 if ($action && !has_credential(CRED_PKGBASE_ADOPT)) {
582 /* Regular users may only adopt orphan packages. */
583 $q.= "AND MaintainerUID IS NULL";
585 if (!$action && !has_credential(CRED_PKGBASE_DISOWN)) {
586 /* Regular users may only disown their own packages. */
587 $q.= "AND MaintainerUID = " . $uid;
590 $result = $dbh->query($q);
591 $base_ids = $result->fetchAll(PDO::FETCH_COLUMN, 0);
593 /* Error out if the list of remaining packages is empty. */
594 if (empty($base_ids)) {
595 if ($action) {
596 return array(false, __("You did not select any packages to adopt."));
597 } else {
598 return array(false, __("You did not select any packages to disown."));
603 * Close package request if the disownment was initiated through the
604 * request interface. NOTE: This needs to happen *before* the actual
605 * disown operation. Otherwise, the former maintainer will not be
606 * included in the Cc list of the request notification email.
608 if ($via) {
609 pkgreq_close(intval($via), 'accepted', '');
612 /* Scan through pending orphan requests and close them. */
613 if (!$action) {
614 $username = username_from_sid($_COOKIE['AURSID']);
615 foreach ($base_ids as $base_id) {
616 $pkgreq_ids = pkgreq_by_pkgbase($base_id, 'orphan');
617 foreach ($pkgreq_ids as $pkgreq_id) {
618 pkgreq_close(intval($pkgreq_id), 'accepted',
619 'The user ' . $username .
620 ' disowned the package.', true);
625 /* Adopt or disown the package. */
626 if ($action) {
627 $q = "UPDATE PackageBases ";
628 $q.= "SET MaintainerUID = $uid ";
629 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
630 $dbh->exec($q);
631 } else {
632 /* Update the co-maintainer list when disowning a package. */
633 if (has_credential(CRED_PKGBASE_DISOWN)) {
634 foreach ($base_ids as $base_id) {
635 pkgbase_set_comaintainers($base_id, array());
638 $q = "UPDATE PackageBases ";
639 $q.= "SET MaintainerUID = NULL ";
640 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
641 $dbh->exec($q);
642 } else {
643 foreach ($base_ids as $base_id) {
644 $comaintainers = pkgbase_get_comaintainers($base_id);
646 if (count($comaintainers) > 0) {
647 $uid = uid_from_username($comaintainers[0]);
648 $comaintainers = array_diff($comaintainers, array($comaintainers[0]));
649 pkgbase_set_comaintainers($base_id, $comaintainers);
650 } else {
651 $uid = "NULL";
654 $q = "UPDATE PackageBases ";
655 $q.= "SET MaintainerUID = " . $uid . " ";
656 $q.= "WHERE ID = " . $base_id;
657 $dbh->exec($q);
662 if ($action) {
663 pkgbase_notify($base_ids);
664 return array(true, __("The selected packages have been adopted."));
665 } else {
666 return array(true, __("The selected packages have been disowned."));
671 * Vote and un-vote for packages
673 * @param array $base_ids Array of package base IDs to vote/un-vote
674 * @param bool $action Votes if true, un-votes if false. Votes by default
676 * @return array Tuple of success/failure indicator and error message
678 function pkgbase_vote ($base_ids, $action=true) {
679 if (!has_credential(CRED_PKGBASE_VOTE)) {
680 if ($action) {
681 return array(false, __("You must be logged in before you can vote for packages."));
682 } else {
683 return array(false, __("You must be logged in before you can un-vote for packages."));
687 $base_ids = sanitize_ids($base_ids);
688 if (empty($base_ids)) {
689 if ($action) {
690 return array(false, __("You did not select any packages to vote for."));
691 } else {
692 return array(false, __("Your votes have been removed from the selected packages."));
696 $dbh = DB::connect();
697 $my_votes = pkgbase_votes_from_sid($_COOKIE["AURSID"]);
698 $uid = uid_from_sid($_COOKIE["AURSID"]);
700 $first = 1;
701 foreach ($base_ids as $pid) {
702 if ($action) {
703 $check = !isset($my_votes[$pid]);
704 } else {
705 $check = isset($my_votes[$pid]);
708 if ($check) {
709 if ($first) {
710 $first = 0;
711 $vote_ids = $pid;
712 if ($action) {
713 $vote_clauses = "($uid, $pid, UNIX_TIMESTAMP())";
715 } else {
716 $vote_ids .= ", $pid";
717 if ($action) {
718 $vote_clauses .= ", ($uid, $pid, UNIX_TIMESTAMP())";
724 /* Only add votes for packages the user hasn't already voted for. */
725 $op = $action ? "+" : "-";
726 $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 ";
727 $q.= "WHERE ID IN ($vote_ids)";
729 $dbh->exec($q);
731 if ($action) {
732 $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES ";
733 $q.= $vote_clauses;
734 } else {
735 $q = "DELETE FROM PackageVotes WHERE UsersID = $uid ";
736 $q.= "AND PackageBaseID IN ($vote_ids)";
739 $dbh->exec($q);
741 if ($action) {
742 return array(true, __("Your votes have been cast for the selected packages."));
743 } else {
744 return array(true, __("Your votes have been removed from the selected packages."));
749 * Get all usernames and IDs that voted for a specific package base
751 * @param string $pkgbase_name The package base to retrieve votes for
753 * @return array User IDs and usernames that voted for a specific package base
755 function pkgbase_votes_from_name($pkgbase_name) {
756 $dbh = DB::connect();
758 $q = "SELECT UsersID, Username, Name, VoteTS FROM PackageVotes ";
759 $q.= "LEFT JOIN Users ON UsersID = Users.ID ";
760 $q.= "LEFT JOIN PackageBases ";
761 $q.= "ON PackageVotes.PackageBaseID = PackageBases.ID ";
762 $q.= "WHERE PackageBases.Name = ". $dbh->quote($pkgbase_name) . " ";
763 $q.= "ORDER BY Username";
764 $result = $dbh->query($q);
766 if (!$result) {
767 return;
770 $votes = array();
771 while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
772 $votes[] = $row;
775 return $votes;
779 * Determine if a user has already voted for a specific package base
781 * @param string $uid The user ID to check for an existing vote
782 * @param string $base_id The package base ID to check for an existing vote
784 * @return bool True if the user has already voted, otherwise false
786 function pkgbase_user_voted($uid, $base_id) {
787 $dbh = DB::connect();
788 $q = "SELECT COUNT(*) FROM PackageVotes WHERE ";
789 $q.= "UsersID = ". $dbh->quote($uid) . " AND ";
790 $q.= "PackageBaseID = " . $dbh->quote($base_id);
791 $result = $dbh->query($q);
792 if (!$result) {
793 return null;
796 return ($result->fetch(PDO::FETCH_COLUMN, 0) > 0);
800 * Determine if a user wants notifications for a specific package base
802 * @param string $uid User ID to check in the database
803 * @param string $base_id Package base ID to check notifications for
805 * @return bool True if the user wants notifications, otherwise false
807 function pkgbase_user_notify($uid, $base_id) {
808 $dbh = DB::connect();
810 $q = "SELECT * FROM CommentNotify WHERE UserID = " . $dbh->quote($uid);
811 $q.= " AND PackageBaseID = " . $dbh->quote($base_id);
812 $result = $dbh->query($q);
814 if ($result->fetch(PDO::FETCH_NUM)) {
815 return true;
817 else {
818 return false;
823 * Toggle notification of packages
825 * @param array $base_ids Array of package base IDs to toggle
827 * @return array Tuple of success/failure indicator and error message
829 function pkgbase_notify ($base_ids, $action=true) {
830 if (!has_credential(CRED_PKGBASE_NOTIFY)) {
831 return;
834 $base_ids = sanitize_ids($base_ids);
835 if (empty($base_ids)) {
836 return array(false, __("Couldn't add to notification list."));
839 $dbh = DB::connect();
840 $uid = uid_from_sid($_COOKIE["AURSID"]);
842 $output = "";
844 $first = true;
847 * There currently shouldn't be multiple requests here, but the format
848 * in which it's sent requires this.
850 foreach ($base_ids as $bid) {
851 $q = "SELECT Name FROM PackageBases WHERE ID = $bid";
852 $result = $dbh->query($q);
853 if ($result) {
854 $row = $result->fetch(PDO::FETCH_NUM);
855 $basename = $row[0];
857 else {
858 $basename = '';
861 if ($first)
862 $first = false;
863 else
864 $output .= ", ";
867 if ($action) {
868 $q = "SELECT COUNT(*) FROM CommentNotify WHERE ";
869 $q .= "UserID = $uid AND PackageBaseID = $bid";
871 /* Notification already added. Don't add again. */
872 $result = $dbh->query($q);
873 if ($result->fetchColumn() == 0) {
874 $q = "INSERT INTO CommentNotify (PackageBaseID, UserID) VALUES ($bid, $uid)";
875 $dbh->exec($q);
878 $output .= $basename;
880 else {
881 $q = "DELETE FROM CommentNotify WHERE PackageBaseID = $bid ";
882 $q .= "AND UserID = $uid";
883 $dbh->exec($q);
885 $output .= $basename;
889 if ($action) {
890 $output = __("You have been added to the comment notification list for %s.", $output);
892 else {
893 $output = __("You have been removed from the comment notification list for %s.", $output);
896 return array(true, $output);
900 * Delete a package comment
902 * @return array Tuple of success/failure indicator and error message
904 function pkgbase_delete_comment() {
905 $uid = uid_from_sid($_COOKIE["AURSID"]);
906 if (!$uid) {
907 return array(false, __("You must be logged in before you can edit package information."));
910 if (isset($_POST["comment_id"])) {
911 $comment_id = $_POST["comment_id"];
912 } else {
913 return array(false, __("Missing comment ID."));
916 $dbh = DB::connect();
917 if (can_delete_comment($comment_id)) {
918 $q = "UPDATE PackageComments ";
919 $q.= "SET DelUsersID = ".$uid.", ";
920 $q.= "EditedTS = UNIX_TIMESTAMP() ";
921 $q.= "WHERE ID = ".intval($comment_id);
922 $dbh->exec($q);
923 return array(true, __("Comment has been deleted."));
924 } else {
925 return array(false, __("You are not allowed to delete this comment."));
930 * Edit a package comment
932 * @return array Tuple of success/failure indicator and error message
934 function pkgbase_edit_comment($comment) {
935 $uid = uid_from_sid($_COOKIE["AURSID"]);
936 if (!$uid) {
937 return array(false, __("You must be logged in before you can edit package information."));
940 if (isset($_POST["comment_id"])) {
941 $comment_id = $_POST["comment_id"];
942 } else {
943 return array(false, __("Missing comment ID."));
946 if (trim($comment) == '') {
947 return array(false, __('Comment cannot be empty.'));
950 $dbh = DB::connect();
951 if (can_edit_comment($comment_id)) {
952 $q = "UPDATE PackageComments ";
953 $q.= "SET EditedUsersID = ".$uid.", ";
954 $q.= "Comments = ".$dbh->quote($comment).", ";
955 $q.= "EditedTS = UNIX_TIMESTAMP() ";
956 $q.= "WHERE ID = ".intval($comment_id);
957 $dbh->exec($q);
958 return array(true, __("Comment has been edited."));
959 } else {
960 return array(false, __("You are not allowed to edit this comment."));
965 * Get a list of package base keywords
967 * @param int $base_id The package base ID to retrieve the keywords for
969 * @return array An array of keywords
971 function pkgbase_get_keywords($base_id) {
972 $dbh = DB::connect();
973 $q = "SELECT Keyword FROM PackageKeywords ";
974 $q .= "WHERE PackageBaseID = " . intval($base_id) . " ";
975 $q .= "ORDER BY Keyword ASC";
976 $result = $dbh->query($q);
978 if ($result) {
979 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
980 } else {
981 return array();
986 * Update the list of keywords of a package base
988 * @param int $base_id The package base ID to update the keywords of
989 * @param array $users Array of keywords
991 * @return array Tuple of success/failure indicator and error message
993 function pkgbase_set_keywords($base_id, $keywords) {
994 $base_id = intval($base_id);
996 $maintainers = array_merge(array(pkgbase_maintainer_uid($base_id)), pkgbase_get_comaintainer_uids(array($base_id)));
997 if (!has_credential(CRED_PKGBASE_SET_KEYWORDS, $maintainers)) {
998 return array(false, __("You are not allowed to edit the keywords of this package base."));
1001 /* Remove empty and duplicate user names. */
1002 $keywords = array_unique(array_filter(array_map('trim', $keywords)));
1004 $dbh = DB::connect();
1006 $q = sprintf("DELETE FROM PackageKeywords WHERE PackageBaseID = %d", $base_id);
1007 $dbh->exec($q);
1009 $i = 0;
1010 foreach ($keywords as $keyword) {
1011 $q = sprintf("INSERT INTO PackageKeywords (PackageBaseID, Keyword) VALUES (%d, %s)", $base_id, $dbh->quote($keyword));
1012 var_dump($q);
1013 $dbh->exec($q);
1015 $i++;
1016 if ($i >= 20) {
1017 break;
1021 return array(true, __("The package base keywords have been updated."));
1025 * Get a list of package base co-maintainers
1027 * @param int $base_id The package base ID to retrieve the co-maintainers for
1029 * @return array An array of co-maintainer user names
1031 function pkgbase_get_comaintainers($base_id) {
1032 $dbh = DB::connect();
1033 $q = "SELECT UserName FROM PackageComaintainers ";
1034 $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID ";
1035 $q .= "WHERE PackageComaintainers.PackageBaseID = " . intval($base_id) . " ";
1036 $q .= "ORDER BY Priority ASC";
1037 $result = $dbh->query($q);
1039 if ($result) {
1040 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
1041 } else {
1042 return array();
1047 * Get a list of package base co-maintainer IDs
1049 * @param int $base_id The package base ID to retrieve the co-maintainers for
1051 * @return array An array of co-maintainer user UDs
1053 function pkgbase_get_comaintainer_uids($base_ids) {
1054 $dbh = DB::connect();
1055 $q = "SELECT UsersID FROM PackageComaintainers ";
1056 $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID ";
1057 $q .= "WHERE PackageComaintainers.PackageBaseID IN (" . implode(",", $base_ids) . ") ";
1058 $q .= "ORDER BY Priority ASC";
1059 $result = $dbh->query($q);
1061 if ($result) {
1062 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
1063 } else {
1064 return array();
1069 * Update the list of co-maintainers of a package base
1071 * @param int $base_id The package base ID to update the co-maintainers of
1072 * @param array $users Array of co-maintainer user names
1074 * @return array Tuple of success/failure indicator and error message
1076 function pkgbase_set_comaintainers($base_id, $users) {
1077 if (!has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) {
1078 return array(false, __("You are not allowed to manage co-maintainers of this package base."));
1081 /* Remove empty and duplicate user names. */
1082 $users = array_unique(array_filter(array_map('trim', $users)));
1084 $dbh = DB::connect();
1086 $uids_new = array();
1087 foreach($users as $user) {
1088 $q = "SELECT ID FROM Users ";
1089 $q .= "WHERE UserName = " . $dbh->quote($user);
1090 $result = $dbh->query($q);
1091 $uid = $result->fetchColumn(0);
1093 if (!$uid) {
1094 return array(false, __("Invalid user name: %s", $user));
1097 $uids_new[] = $uid;
1100 $q = sprintf("SELECT UsersID FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id);
1101 $result = $dbh->query($q);
1102 $uids_old = $result->fetchAll(PDO::FETCH_COLUMN, 0);
1104 $uids_add = array_diff($uids_new, $uids_old);
1105 $uids_rem = array_diff($uids_old, $uids_new);
1107 $i = 1;
1108 foreach ($uids_new as $uid) {
1109 if (in_array($uid, $uids_add)) {
1110 $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i);
1111 notify(array('comaintainer-add', $base_id, $uid));
1112 } else {
1113 $q = sprintf("UPDATE PackageComaintainers SET Priority = %d WHERE PackageBaseID = %d AND UsersID = %d", $i, $base_id, $uid);
1116 $dbh->exec($q);
1117 $i++;
1120 foreach ($uids_rem as $uid) {
1121 $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d AND UsersID = %d", $base_id, $uid);
1122 $dbh->exec($q);
1123 notify(array('comaintainer-remove', $base_id, $uid));
1126 return array(true, __("The package base co-maintainers have been updated."));