Transfer notifications when merging packages
[aur.git] / web / lib / pkgbasefuncs.inc.php
blobcb756f610af423b66ae967da9c51c45a2cedca09
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
11 * @return string The number of comments left for a specific package
13 function pkgbase_comments_count($base_id, $include_deleted) {
14 $base_id = intval($base_id);
15 if (!$base_id) {
16 return null;
19 $dbh = DB::connect();
20 $q = "SELECT COUNT(*) FROM PackageComments ";
21 $q.= "WHERE PackageBaseID = " . $base_id . " ";
22 if (!$include_deleted) {
23 $q.= "AND DelUsersID IS NULL";
25 $result = $dbh->query($q);
26 if (!$result) {
27 return null;
30 return $result->fetchColumn(0);
33 /**
34 * Get all package comment information for a specific package base
36 * @param int $base_id The package base ID to get comments for
37 * @param int $limit Maximum number of comments to return (0 means unlimited)
38 * @param bool $include_deleted True if deleted comments should be included
40 * @return array All package comment information for a specific package base
42 function pkgbase_comments($base_id, $limit, $include_deleted) {
43 $base_id = intval($base_id);
44 $limit = intval($limit);
45 if (!$base_id) {
46 return null;
49 $dbh = DB::connect();
50 $q = "SELECT PackageComments.ID, A.UserName AS UserName, UsersID, Comments, ";
51 $q.= "CommentTS, EditedTS, B.UserName AS EditUserName, ";
52 $q.= "DelUsersID, C.UserName AS DelUserName FROM PackageComments ";
53 $q.= "LEFT JOIN Users A ON PackageComments.UsersID = A.ID ";
54 $q.= "LEFT JOIN Users B ON PackageComments.EditedUsersID = B.ID ";
55 $q.= "LEFT JOIN Users C ON PackageComments.DelUsersID = C.ID ";
56 $q.= "WHERE PackageBaseID = " . $base_id . " ";
57 if (!$include_deleted) {
58 $q.= "AND DelUsersID IS NULL ";
60 $q.= "ORDER BY CommentTS DESC";
61 if ($limit > 0) {
62 $q.=" LIMIT " . $limit;
64 $result = $dbh->query($q);
65 if (!$result) {
66 return null;
69 return $result->fetchAll();
72 /**
73 * Add a comment to a package page and send out appropriate notifications
75 * @param string $base_id The package base ID to add the comment on
76 * @param string $uid The user ID of the individual who left the comment
77 * @param string $comment The comment left on a package page
79 * @return void
81 function pkgbase_add_comment($base_id, $uid, $comment) {
82 $dbh = DB::connect();
84 if (trim($comment) == '') {
85 return array(false, __('Comment cannot be empty.'));
88 $q = "INSERT INTO PackageComments ";
89 $q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES (";
90 $q.= intval($base_id) . ", " . $uid . ", ";
91 $q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())";
92 $dbh->exec($q);
95 * Send e-mail notifications.
96 * TODO: Move notification logic to separate function where it belongs.
98 $q = "SELECT CommentNotify.*, Users.Email ";
99 $q.= "FROM CommentNotify, Users ";
100 $q.= "WHERE Users.ID = CommentNotify.UserID ";
101 $q.= "AND CommentNotify.UserID != " . $uid . " ";
102 $q.= "AND CommentNotify.PackageBaseID = " . intval($base_id);
103 $result = $dbh->query($q);
104 $bcc = array();
106 if ($result) {
107 notify(array('comment', $uid, $base_id), $comment);
110 return array(true, __('Comment has been added.'));
114 * Get a list of all packages a logged-in user has voted for
116 * @param string $sid The session ID of the visitor
118 * @return array All packages the visitor has voted for
120 function pkgbase_votes_from_sid($sid="") {
121 $pkgs = array();
122 if (!$sid) {return $pkgs;}
123 $dbh = DB::connect();
124 $q = "SELECT PackageBaseID ";
125 $q.= "FROM PackageVotes, Users, Sessions ";
126 $q.= "WHERE Users.ID = Sessions.UsersID ";
127 $q.= "AND Users.ID = PackageVotes.UsersID ";
128 $q.= "AND Sessions.SessionID = " . $dbh->quote($sid);
129 $result = $dbh->query($q);
130 if ($result) {
131 while ($row = $result->fetch(PDO::FETCH_NUM)) {
132 $pkgs[$row[0]] = 1;
135 return $pkgs;
139 * Get the package base details
141 * @param string $id The package base ID to get description for
143 * @return array The package base's details OR error message
145 function pkgbase_get_details($base_id) {
146 $dbh = DB::connect();
148 $q = "SELECT PackageBases.ID, PackageBases.Name, ";
149 $q.= "PackageBases.NumVotes, PackageBases.Popularity, ";
150 $q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, ";
151 $q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, ";
152 $q.= "PackageBases.MaintainerUID, PackageBases.PackagerUID, ";
153 $q.= "PackageBases.FlaggerUID, ";
154 $q.= "(SELECT COUNT(*) FROM PackageRequests ";
155 $q.= " WHERE PackageRequests.PackageBaseID = PackageBases.ID ";
156 $q.= " AND PackageRequests.Status = 0) AS RequestCount ";
157 $q.= "FROM PackageBases ";
158 $q.= "WHERE PackageBases.ID = " . intval($base_id);
159 $result = $dbh->query($q);
161 $row = array();
163 if (!$result) {
164 $row['error'] = __("Error retrieving package details.");
166 else {
167 $row = $result->fetch(PDO::FETCH_ASSOC);
168 if (empty($row)) {
169 $row['error'] = __("Package details could not be found.");
173 return $row;
177 * Display the package base details page
179 * @param string $id The package base ID to get details page for
180 * @param array $row Package base details retrieved by pkgbase_get_details()
181 * @param string $SID The session ID of the visitor
183 * @return void
185 function pkgbase_display_details($base_id, $row, $SID="") {
186 $dbh = DB::connect();
188 if (isset($row['error'])) {
189 print "<p>" . $row['error'] . "</p>\n";
191 else {
192 $pkgbase_name = pkgbase_name_from_id($base_id);
194 include('pkgbase_details.php');
196 if ($SID) {
197 include('pkg_comment_box.php');
200 $limit = isset($_GET['comments']) ? 0 : 10;
201 $include_deleted = has_credential(CRED_COMMENT_VIEW_DELETED);
202 $comments = pkgbase_comments($base_id, $limit, $include_deleted);
203 if (!empty($comments)) {
204 include('pkg_comments.php');
210 * Convert a list of package IDs into a list of corresponding package bases.
212 * @param array|int $ids Array of package IDs to convert
214 * @return array|int List of package base IDs
216 function pkgbase_from_pkgid($ids) {
217 $dbh = DB::connect();
219 if (is_array($ids)) {
220 $q = "SELECT PackageBaseID FROM Packages ";
221 $q.= "WHERE ID IN (" . implode(",", $ids) . ")";
222 $result = $dbh->query($q);
223 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
224 } else {
225 $q = "SELECT PackageBaseID FROM Packages ";
226 $q.= "WHERE ID = " . $ids;
227 $result = $dbh->query($q);
228 return $result->fetch(PDO::FETCH_COLUMN, 0);
233 * Retrieve ID of a package base by name
235 * @param string $name The package base name to retrieve the ID for
237 * @return int The ID of the package base
239 function pkgbase_from_name($name) {
240 $dbh = DB::connect();
241 $q = "SELECT ID FROM PackageBases WHERE Name = " . $dbh->quote($name);
242 $result = $dbh->query($q);
243 return $result->fetch(PDO::FETCH_COLUMN, 0);
247 * Retrieve the name of a package base given its ID
249 * @param int $base_id The ID of the package base to query
251 * @return string The name of the package base
253 function pkgbase_name_from_id($base_id) {
254 $dbh = DB::connect();
255 $q = "SELECT Name FROM PackageBases WHERE ID = " . intval($base_id);
256 $result = $dbh->query($q);
257 return $result->fetch(PDO::FETCH_COLUMN, 0);
261 * Get the names of all packages belonging to a package base
263 * @param int $base_id The ID of the package base
265 * @return array The names of all packages belonging to the package base
267 function pkgbase_get_pkgnames($base_id) {
268 $dbh = DB::connect();
269 $q = "SELECT Name FROM Packages WHERE PackageBaseID = " . intval($base_id);
270 $result = $dbh->query($q);
271 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
275 * Delete all packages belonging to a package base
277 * @param int $base_id The ID of the package base
279 * @return void
281 function pkgbase_delete_packages($base_id) {
282 $dbh = DB::connect();
283 $q = "DELETE FROM Packages WHERE PackageBaseID = " . intval($base_id);
284 $dbh->exec($q);
288 * Retrieve the maintainer of a package base given its ID
290 * @param int $base_id The ID of the package base to query
292 * @return int The user ID of the current package maintainer
294 function pkgbase_maintainer_uid($base_id) {
295 $dbh = DB::connect();
296 $q = "SELECT MaintainerUID FROM PackageBases WHERE ID = " . intval($base_id);
297 $result = $dbh->query($q);
298 return $result->fetch(PDO::FETCH_COLUMN, 0);
302 * Retrieve the maintainers of an array of package bases given by their ID
304 * @param int $base_ids The array of IDs of the package bases to query
306 * @return int The user ID of the current package maintainer
308 function pkgbase_maintainer_uids($base_ids) {
309 $dbh = DB::connect();
310 $q = "SELECT MaintainerUID FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")";
311 $result = $dbh->query($q);
312 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
316 * Flag package(s) as out-of-date
318 * @param array $base_ids Array of package base IDs to flag/unflag
319 * @param string $comment The comment to add
321 * @return array Tuple of success/failure indicator and error message
323 function pkgbase_flag($base_ids, $comment) {
324 if (!has_credential(CRED_PKGBASE_FLAG)) {
325 return array(false, __("You must be logged in before you can flag packages."));
328 $base_ids = sanitize_ids($base_ids);
329 if (empty($base_ids)) {
330 return array(false, __("You did not select any packages to flag."));
333 $uid = uid_from_sid($_COOKIE['AURSID']);
334 $dbh = DB::connect();
336 $q = "UPDATE PackageBases SET ";
337 $q.= "OutOfDateTS = UNIX_TIMESTAMP(), FlaggerUID = " . $uid . ", ";
338 $q.= "FlaggerComment = " . $dbh->quote($comment) . " ";
339 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
340 $q.= "AND OutOfDateTS IS NULL";
341 $dbh->exec($q);
343 foreach ($base_ids as $base_id) {
344 notify(array('flag', $uid, $base_id), $comment);
347 return array(true, __("The selected packages have been flagged out-of-date."));
351 * Unflag package(s) as out-of-date
353 * @param array $base_ids Array of package base IDs to flag/unflag
355 * @return array Tuple of success/failure indicator and error message
357 function pkgbase_unflag($base_ids) {
358 $uid = uid_from_sid($_COOKIE["AURSID"]);
359 if (!$uid) {
360 return array(false, __("You must be logged in before you can unflag packages."));
363 $base_ids = sanitize_ids($base_ids);
364 if (empty($base_ids)) {
365 return array(false, __("You did not select any packages to unflag."));
368 $dbh = DB::connect();
370 $q = "UPDATE PackageBases SET ";
371 $q.= "OutOfDateTS = NULL ";
372 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
374 $maintainers = array_merge(pkgbase_maintainer_uids($base_ids), pkgbase_get_comaintainer_uids($base_ids));
375 if (!has_credential(CRED_PKGBASE_UNFLAG, $maintainers)) {
376 $q.= "AND (MaintainerUID = " . $uid . " OR FlaggerUID = " . $uid. ")";
379 $result = $dbh->exec($q);
381 if ($result) {
382 return array(true, __("The selected packages have been unflagged."));
387 * Delete package bases
389 * @param array $base_ids Array of package base IDs to delete
390 * @param int $merge_base_id Package base to merge the deleted ones into
391 * @param int $via Package request to close upon deletion
392 * @param bool $grant Allow anyone to delete the package base
394 * @return array Tuple of success/failure indicator and error message
396 function pkgbase_delete ($base_ids, $merge_base_id, $via, $grant=false) {
397 if (!$grant && !has_credential(CRED_PKGBASE_DELETE)) {
398 return array(false, __("You do not have permission to delete packages."));
401 $base_ids = sanitize_ids($base_ids);
402 if (empty($base_ids)) {
403 return array(false, __("You did not select any packages to delete."));
406 $dbh = DB::connect();
408 if ($merge_base_id) {
409 $merge_base_name = pkgbase_name_from_id($merge_base_id);
412 $uid = uid_from_sid($_COOKIE['AURSID']);
413 foreach ($base_ids as $base_id) {
414 if ($merge_base_id) {
415 notify(array('delete', $uid, $base_id, $merge_base_id));
416 } else {
417 notify(array('delete', $uid, $base_id));
422 * Close package request if the deletion was initiated through the
423 * request interface. NOTE: This needs to happen *before* the actual
424 * deletion. Otherwise, the former maintainer will not be included in
425 * the Cc list of the request notification email.
427 if ($via) {
428 pkgreq_close(intval($via), 'accepted', '');
431 /* Scan through pending deletion requests and close them. */
432 if (!$action) {
433 $username = username_from_sid($_COOKIE['AURSID']);
434 foreach ($base_ids as $base_id) {
435 $pkgreq_ids = array_merge(pkgreq_by_pkgbase($base_id));
436 foreach ($pkgreq_ids as $pkgreq_id) {
437 pkgreq_close(intval($pkgreq_id), 'accepted',
438 'The user ' . $username .
439 ' deleted the package.', true);
444 if ($merge_base_id) {
445 /* Merge comments */
446 $q = "UPDATE PackageComments ";
447 $q.= "SET PackageBaseID = " . intval($merge_base_id) . " ";
448 $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")";
449 $dbh->exec($q);
451 /* Merge notifications */
452 $q = "SELECT DISTINCT UserID FROM CommentNotify cn ";
453 $q.= "WHERE PackageBaseID IN (" . implode(",", $base_ids) . ") ";
454 $q.= "AND NOT EXISTS (SELECT * FROM CommentNotify cn2 ";
455 $q.= "WHERE cn2.PackageBaseID = " . intval($merge_base_id) . " ";
456 $q.= "AND cn2.UserID = cn.UserID)";
457 $result = $dbh->query($q);
459 while ($notify_uid = $result->fetch(PDO::FETCH_COLUMN, 0)) {
460 $q = "INSERT INTO CommentNotify (UserID, PackageBaseID) ";
461 $q.= "VALUES (" . intval($notify_uid) . ", " . intval($merge_base_id) . ")";
462 $dbh->exec($q);
465 /* Merge votes */
466 foreach ($base_ids as $base_id) {
467 $q = "UPDATE PackageVotes ";
468 $q.= "SET PackageBaseID = " . intval($merge_base_id) . " ";
469 $q.= "WHERE PackageBaseID = " . $base_id . " ";
470 $q.= "AND UsersID NOT IN (";
471 $q.= "SELECT * FROM (SELECT UsersID ";
472 $q.= "FROM PackageVotes ";
473 $q.= "WHERE PackageBaseID = " . intval($merge_base_id);
474 $q.= ") temp)";
475 $dbh->exec($q);
478 $q = "UPDATE PackageBases ";
479 $q.= "SET NumVotes = (SELECT COUNT(*) FROM PackageVotes ";
480 $q.= "WHERE PackageBaseID = " . intval($merge_base_id) . ") ";
481 $q.= "WHERE ID = " . intval($merge_base_id);
482 $dbh->exec($q);
485 $q = "DELETE FROM Packages WHERE PackageBaseID IN (" . implode(",", $base_ids) . ")";
486 $dbh->exec($q);
488 $q = "DELETE FROM PackageBases WHERE ID IN (" . implode(",", $base_ids) . ")";
489 $dbh->exec($q);
491 return array(true, __("The selected packages have been deleted."));
495 * Adopt or disown packages
497 * @param array $base_ids Array of package base IDs to adopt/disown
498 * @param bool $action Adopts if true, disowns if false. Adopts by default
499 * @param int $via Package request to close upon adoption
501 * @return array Tuple of success/failure indicator and error message
503 function pkgbase_adopt ($base_ids, $action=true, $via) {
504 $dbh = DB::connect();
506 $uid = uid_from_sid($_COOKIE["AURSID"]);
507 if (!$uid) {
508 if ($action) {
509 return array(false, __("You must be logged in before you can adopt packages."));
510 } else {
511 return array(false, __("You must be logged in before you can disown packages."));
515 /* Verify package ownership. */
516 $base_ids = sanitize_ids($base_ids);
518 $q = "SELECT ID FROM PackageBases ";
519 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
521 if ($action && !has_credential(CRED_PKGBASE_ADOPT)) {
522 /* Regular users may only adopt orphan packages. */
523 $q.= "AND MaintainerUID IS NULL";
525 if (!$action && !has_credential(CRED_PKGBASE_DISOWN)) {
526 /* Regular users may only disown their own packages. */
527 $q.= "AND MaintainerUID = " . $uid;
530 $result = $dbh->query($q);
531 $base_ids = $result->fetchAll(PDO::FETCH_COLUMN, 0);
533 /* Error out if the list of remaining packages is empty. */
534 if (empty($base_ids)) {
535 if ($action) {
536 return array(false, __("You did not select any packages to adopt."));
537 } else {
538 return array(false, __("You did not select any packages to disown."));
543 * Close package request if the disownment was initiated through the
544 * request interface. NOTE: This needs to happen *before* the actual
545 * disown operation. Otherwise, the former maintainer will not be
546 * included in the Cc list of the request notification email.
548 if ($via) {
549 pkgreq_close(intval($via), 'accepted', '');
552 /* Scan through pending orphan requests and close them. */
553 if (!$action) {
554 $username = username_from_sid($_COOKIE['AURSID']);
555 foreach ($base_ids as $base_id) {
556 $pkgreq_ids = pkgreq_by_pkgbase($base_id, 'orphan');
557 foreach ($pkgreq_ids as $pkgreq_id) {
558 pkgreq_close(intval($pkgreq_id), 'accepted',
559 'The user ' . $username .
560 ' disowned the package.', true);
565 /* Adopt or disown the package. */
566 if ($action) {
567 $q = "UPDATE PackageBases ";
568 $q.= "SET MaintainerUID = $uid ";
569 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
570 $dbh->exec($q);
571 } else {
572 /* Update the co-maintainer list when disowning a package. */
573 if (has_credential(CRED_PKGBASE_DISOWN)) {
574 foreach ($base_ids as $base_id) {
575 pkgbase_set_comaintainers($base_id, array());
578 $q = "UPDATE PackageBases ";
579 $q.= "SET MaintainerUID = NULL ";
580 $q.= "WHERE ID IN (" . implode(",", $base_ids) . ") ";
581 $dbh->exec($q);
582 } else {
583 foreach ($base_ids as $base_id) {
584 $comaintainers = pkgbase_get_comaintainers($base_id);
586 if (count($comaintainers) > 0) {
587 $uid = uid_from_username($comaintainers[0]);
588 $comaintainers = array_diff($comaintainers, array($comaintainers[0]));
589 pkgbase_set_comaintainers($base_id, $comaintainers);
590 } else {
591 $uid = "NULL";
594 $q = "UPDATE PackageBases ";
595 $q.= "SET MaintainerUID = " . $uid . " ";
596 $q.= "WHERE ID = " . $base_id;
597 $dbh->exec($q);
602 if ($action) {
603 pkgbase_notify($base_ids);
604 return array(true, __("The selected packages have been adopted."));
605 } else {
606 return array(true, __("The selected packages have been disowned."));
611 * Vote and un-vote for packages
613 * @param array $base_ids Array of package base IDs to vote/un-vote
614 * @param bool $action Votes if true, un-votes if false. Votes by default
616 * @return array Tuple of success/failure indicator and error message
618 function pkgbase_vote ($base_ids, $action=true) {
619 if (!has_credential(CRED_PKGBASE_VOTE)) {
620 if ($action) {
621 return array(false, __("You must be logged in before you can vote for packages."));
622 } else {
623 return array(false, __("You must be logged in before you can un-vote for packages."));
627 $base_ids = sanitize_ids($base_ids);
628 if (empty($base_ids)) {
629 if ($action) {
630 return array(false, __("You did not select any packages to vote for."));
631 } else {
632 return array(false, __("Your votes have been removed from the selected packages."));
636 $dbh = DB::connect();
637 $my_votes = pkgbase_votes_from_sid($_COOKIE["AURSID"]);
638 $uid = uid_from_sid($_COOKIE["AURSID"]);
640 $first = 1;
641 foreach ($base_ids as $pid) {
642 if ($action) {
643 $check = !isset($my_votes[$pid]);
644 } else {
645 $check = isset($my_votes[$pid]);
648 if ($check) {
649 if ($first) {
650 $first = 0;
651 $vote_ids = $pid;
652 if ($action) {
653 $vote_clauses = "($uid, $pid, UNIX_TIMESTAMP())";
655 } else {
656 $vote_ids .= ", $pid";
657 if ($action) {
658 $vote_clauses .= ", ($uid, $pid, UNIX_TIMESTAMP())";
664 /* Only add votes for packages the user hasn't already voted for. */
665 $op = $action ? "+" : "-";
666 $q = "UPDATE PackageBases SET NumVotes = NumVotes $op 1 ";
667 $q.= "WHERE ID IN ($vote_ids)";
669 $dbh->exec($q);
671 if ($action) {
672 $q = "INSERT INTO PackageVotes (UsersID, PackageBaseID, VoteTS) VALUES ";
673 $q.= $vote_clauses;
674 } else {
675 $q = "DELETE FROM PackageVotes WHERE UsersID = $uid ";
676 $q.= "AND PackageBaseID IN ($vote_ids)";
679 $dbh->exec($q);
681 if ($action) {
682 return array(true, __("Your votes have been cast for the selected packages."));
683 } else {
684 return array(true, __("Your votes have been removed from the selected packages."));
689 * Get all usernames and IDs that voted for a specific package base
691 * @param string $pkgbase_name The package base to retrieve votes for
693 * @return array User IDs and usernames that voted for a specific package base
695 function pkgbase_votes_from_name($pkgbase_name) {
696 $dbh = DB::connect();
698 $q = "SELECT UsersID, Username, Name, VoteTS FROM PackageVotes ";
699 $q.= "LEFT JOIN Users ON UsersID = Users.ID ";
700 $q.= "LEFT JOIN PackageBases ";
701 $q.= "ON PackageVotes.PackageBaseID = PackageBases.ID ";
702 $q.= "WHERE PackageBases.Name = ". $dbh->quote($pkgbase_name) . " ";
703 $q.= "ORDER BY Username";
704 $result = $dbh->query($q);
706 if (!$result) {
707 return;
710 $votes = array();
711 while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
712 $votes[] = $row;
715 return $votes;
719 * Determine if a user has already voted for a specific package base
721 * @param string $uid The user ID to check for an existing vote
722 * @param string $base_id The package base ID to check for an existing vote
724 * @return bool True if the user has already voted, otherwise false
726 function pkgbase_user_voted($uid, $base_id) {
727 $dbh = DB::connect();
728 $q = "SELECT COUNT(*) FROM PackageVotes WHERE ";
729 $q.= "UsersID = ". $dbh->quote($uid) . " AND ";
730 $q.= "PackageBaseID = " . $dbh->quote($base_id);
731 $result = $dbh->query($q);
732 if (!$result) {
733 return null;
736 return ($result->fetch(PDO::FETCH_COLUMN, 0) > 0);
740 * Determine if a user wants notifications for a specific package base
742 * @param string $uid User ID to check in the database
743 * @param string $base_id Package base ID to check notifications for
745 * @return bool True if the user wants notifications, otherwise false
747 function pkgbase_user_notify($uid, $base_id) {
748 $dbh = DB::connect();
750 $q = "SELECT * FROM CommentNotify WHERE UserID = " . $dbh->quote($uid);
751 $q.= " AND PackageBaseID = " . $dbh->quote($base_id);
752 $result = $dbh->query($q);
754 if ($result->fetch(PDO::FETCH_NUM)) {
755 return true;
757 else {
758 return false;
763 * Toggle notification of packages
765 * @param array $base_ids Array of package base IDs to toggle
767 * @return array Tuple of success/failure indicator and error message
769 function pkgbase_notify ($base_ids, $action=true) {
770 if (!has_credential(CRED_PKGBASE_NOTIFY)) {
771 return;
774 $base_ids = sanitize_ids($base_ids);
775 if (empty($base_ids)) {
776 return array(false, __("Couldn't add to notification list."));
779 $dbh = DB::connect();
780 $uid = uid_from_sid($_COOKIE["AURSID"]);
782 $output = "";
784 $first = true;
787 * There currently shouldn't be multiple requests here, but the format
788 * in which it's sent requires this.
790 foreach ($base_ids as $bid) {
791 $q = "SELECT Name FROM PackageBases WHERE ID = $bid";
792 $result = $dbh->query($q);
793 if ($result) {
794 $row = $result->fetch(PDO::FETCH_NUM);
795 $basename = $row[0];
797 else {
798 $basename = '';
801 if ($first)
802 $first = false;
803 else
804 $output .= ", ";
807 if ($action) {
808 $q = "SELECT COUNT(*) FROM CommentNotify WHERE ";
809 $q .= "UserID = $uid AND PackageBaseID = $bid";
811 /* Notification already added. Don't add again. */
812 $result = $dbh->query($q);
813 if ($result->fetchColumn() == 0) {
814 $q = "INSERT INTO CommentNotify (PackageBaseID, UserID) VALUES ($bid, $uid)";
815 $dbh->exec($q);
818 $output .= $basename;
820 else {
821 $q = "DELETE FROM CommentNotify WHERE PackageBaseID = $bid ";
822 $q .= "AND UserID = $uid";
823 $dbh->exec($q);
825 $output .= $basename;
829 if ($action) {
830 $output = __("You have been added to the comment notification list for %s.", $output);
832 else {
833 $output = __("You have been removed from the comment notification list for %s.", $output);
836 return array(true, $output);
840 * Delete a package comment
842 * @return array Tuple of success/failure indicator and error message
844 function pkgbase_delete_comment() {
845 $uid = uid_from_sid($_COOKIE["AURSID"]);
846 if (!$uid) {
847 return array(false, __("You must be logged in before you can edit package information."));
850 if (isset($_POST["comment_id"])) {
851 $comment_id = $_POST["comment_id"];
852 } else {
853 return array(false, __("Missing comment ID."));
856 $dbh = DB::connect();
857 if (can_delete_comment($comment_id)) {
858 $q = "UPDATE PackageComments ";
859 $q.= "SET DelUsersID = ".$uid.", ";
860 $q.= "EditedTS = UNIX_TIMESTAMP() ";
861 $q.= "WHERE ID = ".intval($comment_id);
862 $dbh->exec($q);
863 return array(true, __("Comment has been deleted."));
864 } else {
865 return array(false, __("You are not allowed to delete this comment."));
870 * Edit a package comment
872 * @return array Tuple of success/failure indicator and error message
874 function pkgbase_edit_comment($comment) {
875 $uid = uid_from_sid($_COOKIE["AURSID"]);
876 if (!$uid) {
877 return array(false, __("You must be logged in before you can edit package information."));
880 if (isset($_POST["comment_id"])) {
881 $comment_id = $_POST["comment_id"];
882 } else {
883 return array(false, __("Missing comment ID."));
886 if (trim($comment) == '') {
887 return array(false, __('Comment cannot be empty.'));
890 $dbh = DB::connect();
891 if (can_edit_comment($comment_id)) {
892 $q = "UPDATE PackageComments ";
893 $q.= "SET EditedUsersID = ".$uid.", ";
894 $q.= "Comments = ".$dbh->quote($comment).", ";
895 $q.= "EditedTS = UNIX_TIMESTAMP() ";
896 $q.= "WHERE ID = ".intval($comment_id);
897 $dbh->exec($q);
898 return array(true, __("Comment has been edited."));
899 } else {
900 return array(false, __("You are not allowed to edit this comment."));
905 * Get a list of package base keywords
907 * @param int $base_id The package base ID to retrieve the keywords for
909 * @return array An array of keywords
911 function pkgbase_get_keywords($base_id) {
912 $dbh = DB::connect();
913 $q = "SELECT Keyword FROM PackageKeywords ";
914 $q .= "WHERE PackageBaseID = " . intval($base_id) . " ";
915 $q .= "ORDER BY Keyword ASC";
916 $result = $dbh->query($q);
918 if ($result) {
919 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
920 } else {
921 return array();
926 * Update the list of keywords of a package base
928 * @param int $base_id The package base ID to update the keywords of
929 * @param array $users Array of keywords
931 * @return array Tuple of success/failure indicator and error message
933 function pkgbase_set_keywords($base_id, $keywords) {
934 $base_id = intval($base_id);
936 $maintainers = array_merge(array(pkgbase_maintainer_uid($base_id)), pkgbase_get_comaintainer_uids(array($base_id)));
937 if (!has_credential(CRED_PKGBASE_SET_KEYWORDS, $maintainers)) {
938 return array(false, __("You are not allowed to edit the keywords of this package base."));
941 /* Remove empty and duplicate user names. */
942 $keywords = array_unique(array_filter(array_map('trim', $keywords)));
944 $dbh = DB::connect();
946 $q = sprintf("DELETE FROM PackageKeywords WHERE PackageBaseID = %d", $base_id);
947 $dbh->exec($q);
949 $i = 0;
950 foreach ($keywords as $keyword) {
951 $q = sprintf("INSERT INTO PackageKeywords (PackageBaseID, Keyword) VALUES (%d, %s)", $base_id, $dbh->quote($keyword));
952 var_dump($q);
953 $dbh->exec($q);
955 $i++;
956 if ($i >= 20) {
957 break;
961 return array(true, __("The package base keywords have been updated."));
965 * Get a list of package base co-maintainers
967 * @param int $base_id The package base ID to retrieve the co-maintainers for
969 * @return array An array of co-maintainer user names
971 function pkgbase_get_comaintainers($base_id) {
972 $dbh = DB::connect();
973 $q = "SELECT UserName FROM PackageComaintainers ";
974 $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID ";
975 $q .= "WHERE PackageComaintainers.PackageBaseID = " . intval($base_id) . " ";
976 $q .= "ORDER BY Priority ASC";
977 $result = $dbh->query($q);
979 if ($result) {
980 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
981 } else {
982 return array();
987 * Get a list of package base co-maintainer IDs
989 * @param int $base_id The package base ID to retrieve the co-maintainers for
991 * @return array An array of co-maintainer user UDs
993 function pkgbase_get_comaintainer_uids($base_ids) {
994 $dbh = DB::connect();
995 $q = "SELECT UsersID FROM PackageComaintainers ";
996 $q .= "INNER JOIN Users ON Users.ID = PackageComaintainers.UsersID ";
997 $q .= "WHERE PackageComaintainers.PackageBaseID IN (" . implode(",", $base_ids) . ") ";
998 $q .= "ORDER BY Priority ASC";
999 $result = $dbh->query($q);
1001 if ($result) {
1002 return $result->fetchAll(PDO::FETCH_COLUMN, 0);
1003 } else {
1004 return array();
1009 * Update the list of co-maintainers of a package base
1011 * @param int $base_id The package base ID to update the co-maintainers of
1012 * @param array $users Array of co-maintainer user names
1014 * @return array Tuple of success/failure indicator and error message
1016 function pkgbase_set_comaintainers($base_id, $users) {
1017 if (!has_credential(CRED_PKGBASE_EDIT_COMAINTAINERS, array(pkgbase_maintainer_uid($base_id)))) {
1018 return array(false, __("You are not allowed to manage co-maintainers of this package base."));
1021 /* Remove empty and duplicate user names. */
1022 $users = array_unique(array_filter(array_map('trim', $users)));
1024 $dbh = DB::connect();
1026 $uids = array();
1027 foreach($users as $user) {
1028 $q = "SELECT ID FROM Users ";
1029 $q .= "WHERE UserName = " . $dbh->quote($user);
1030 $result = $dbh->query($q);
1031 $uid = $result->fetchColumn(0);
1033 if (!$uid) {
1034 return array(false, __("Invalid user name: %s", $user));
1037 $uids[] = $uid;
1040 $q = sprintf("DELETE FROM PackageComaintainers WHERE PackageBaseID = %d", $base_id);
1041 $dbh->exec($q);
1043 $i = 1;
1044 foreach ($uids as $uid) {
1045 $q = sprintf("INSERT INTO PackageComaintainers (PackageBaseID, UsersID, Priority) VALUES (%d, %d, %d)", $base_id, $uid, $i);
1046 $dbh->exec($q);
1047 $i++;
1050 return array(true, __("The package base co-maintainers have been updated."));