pkgfuncs.inc.php 46.7 KB
Newer Older
1
<?php
2
include_once("config.inc.php");
eric's avatar
eric committed
3

4
5
6
7
8
9
10
11
12
13
14
15
/**
 * Determine if the user can delete a specific package comment
 *
 * Only the comment submitter, Trusted Users, and Developers can delete
 * comments. This function is used for the backend side of comment deletion.
 *
 * @param string $comment_id The comment ID in the database
 * @param string $atype The account type of the user trying to delete a comment
 * @param string|int $uid The user ID of the individual trying to delete a comment
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
16
function can_delete_comment($comment_id=0, $atype="", $uid=0) {
17
18
19
20
	if (!$uid) {
		/* Unauthenticated users cannot delete anything. */
		return false;
	}
21
	if ($atype == "Trusted User" || $atype == "Developer") {
22
		/* TUs and developers can delete any comment. */
23
		return true;
24
	}
Lukas Fleischer's avatar
Lukas Fleischer committed
25

26
	$dbh = DB::connect();
Lukas Fleischer's avatar
Lukas Fleischer committed
27
28
29

	$q = "SELECT COUNT(*) FROM PackageComments ";
	$q.= "WHERE ID = " . intval($comment_id) . " AND UsersID = " . $uid;
canyonknight's avatar
canyonknight committed
30
	$result = $dbh->query($q);
Lukas Fleischer's avatar
Lukas Fleischer committed
31
32
33

	if (!$result) {
		return false;
34
	}
Lukas Fleischer's avatar
Lukas Fleischer committed
35
36
37

	$row = $result->fetch(PDO::FETCH_NUM);
	return ($row[0] > 0);
38
}
eric's avatar
eric committed
39

40
41
42
43
44
45
46
47
48
49
50
51
/**
 * Determine if the user can delete a specific package comment using an array
 *
 * Only the comment submitter, Trusted Users, and Developers can delete
 * comments. This function is used for the frontend side of comment deletion.
 *
 * @param array $comment All database information relating a specific comment
 * @param string $atype The account type of the user trying to delete a comment
 * @param string|int $uid The user ID of the individual trying to delete a comment
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
52
function can_delete_comment_array($comment, $atype="", $uid=0) {
53
54
55
56
	if (!$uid) {
		/* Unauthenticated users cannot delete anything. */
		return false;
	} elseif ($atype == "Trusted User" || $atype == "Developer") {
57
		/* TUs and developers can delete any comment. */
58
		return true;
59
	} else if ($comment['UsersID'] == $uid) {
60
		/* Users can delete their own comments. */
61
		return true;
62
	}
63
	return false;
64
65
}

66
67
68
69
70
71
72
73
74
75
/**
 * Determine if the visitor can submit blacklisted packages.
 *
 * Only Trusted Users and Developers can delete blacklisted packages. Packages
 * are blacklisted if they are include in the official repositories.
 *
 * @param string $atype The account type of the user
 *
 * @return bool True if the user can submit blacklisted packages, otherwise false
 */
76
function can_submit_blacklisted($atype = "") {
77
	if ($atype == "Trusted User" || $atype == "Developer") {
78
		/* Only TUs and developers can submit blacklisted packages. */
79
		return true;
80
81
	}
	else {
82
		return false;
83
84
85
	}
}

86
87
88
89
90
91
92
/**
 * Get all package categories stored in the database
 *
 * @param \PDO An already established database connection
 *
 * @return array All package categories
 */
93
function pkg_categories() {
eric's avatar
eric committed
94
	$cats = array();
95
	$dbh = DB::connect();
96
	$q = "SELECT * FROM PackageCategories WHERE ID != 1 ";
eric's avatar
eric committed
97
	$q.= "ORDER BY Category ASC";
canyonknight's avatar
canyonknight committed
98
	$result = $dbh->query($q);
eric's avatar
eric committed
99
	if ($result) {
canyonknight's avatar
canyonknight committed
100
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
eric's avatar
eric committed
101
102
103
104
105
106
			$cats[$row[0]] = $row[1];
		}
	}
	return $cats;
}

107
108
109
110
111
112
113
/**
 * Check to see if the package name already exists in the database
 *
 * @param string $name The package name to check
 *
 * @return string|void Package name if it already exists
 */
114
function pkgid_from_name($name="") {
115
	if (!$name) {return NULL;}
116
	$dbh = DB::connect();
117
	$q = "SELECT ID FROM Packages ";
canyonknight's avatar
canyonknight committed
118
119
120
121
122
123
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
	if (!$result) {
		return;
	}
	$row = $result->fetch(PDO::FETCH_NUM);
124
125
126
	return $row[0];
}

127
128
129
130
131
132
133
/**
 * Get package dependencies for a specific package
 *
 * @param int $pkgid The package to get dependencies for
 *
 * @return array All package dependencies for the package
 */
134
function package_dependencies($pkgid) {
135
	$deps = array();
136
137
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
138
		$dbh = DB::connect();
Dan McGee's avatar
Dan McGee committed
139
140
141
142
		$q = "SELECT pd.DepName, pd.DepCondition, p.ID FROM PackageDepends pd ";
		$q.= "LEFT JOIN Packages p ON pd.DepName = p.Name ";
		$q.= "WHERE pd.PackageID = ". $pkgid . " ";
		$q.= "ORDER BY pd.DepName";
canyonknight's avatar
canyonknight committed
143
144
145
146
147
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
148
149
150
151
152
153
			$deps[] = $row;
		}
	}
	return $deps;
}

154
155
156
157
158
159
160
/**
 * Determine packages that depend on a package
 *
 * @param string $name The package name for the dependency search
 *
 * @return array All packages that depend on the specified package name
 */
161
function package_required($name="") {
162
	$deps = array();
Dan McGee's avatar
Dan McGee committed
163
	if ($name != "") {
164
		$dbh = DB::connect();
165
		$q = "SELECT DISTINCT p.Name, PackageID FROM PackageDepends pd ";
Dan McGee's avatar
Dan McGee committed
166
		$q.= "JOIN Packages p ON pd.PackageID = p.ID ";
canyonknight's avatar
canyonknight committed
167
		$q.= "WHERE DepName = " . $dbh->quote($name) . " ";
Dan McGee's avatar
Dan McGee committed
168
		$q.= "ORDER BY p.Name";
canyonknight's avatar
canyonknight committed
169
		$result = $dbh->query($q);
170
		if (!$result) {return array();}
canyonknight's avatar
canyonknight committed
171
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
172
173
174
175
176
177
			$deps[] = $row;
		}
	}
	return $deps;
}

178
/**
179
 * Get the number of non-deleted comments for a specific package base
180
 *
181
 * @param string $pkgid The package base ID to get comment count for
182
183
184
 *
 * @return string The number of comments left for a specific package
 */
185
function package_comments_count($base_id) {
186
	$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
187

188
189
	$base_id = intval($base_id);
	if ($base_id > 0) {
190
		$dbh = DB::connect();
191
		$q = "SELECT COUNT(*) FROM PackageComments ";
192
		$q.= "WHERE PackageBaseID = " . $base_id;
193
		$q.= " AND DelUsersID IS NULL";
194
	}
canyonknight's avatar
canyonknight committed
195
	$result = $dbh->query($q);
196
197
198
199
200

	if (!$result) {
		return;
	}

canyonknight's avatar
canyonknight committed
201
202
	$row = $result->fetch(PDO::FETCH_NUM);
	return $row[0];
203
204
}

205
/**
206
 * Get all package comment information for a specific package base
207
 *
208
 * @param int $pkgid The package base ID to get comments for
209
 *
210
 * @return array All package comment information for a specific package base
211
 */
212
213
function package_comments($base_id) {
	$base_id = intval($base_id);
eric's avatar
eric committed
214
	$comments = array();
215
	if ($base_id > 0) {
216
		$dbh = DB::connect();
217
		$q = "SELECT PackageComments.ID, UserName, UsersID, Comments, CommentTS ";
218
219
		$q.= "FROM PackageComments LEFT JOIN Users ";
		$q.= "ON PackageComments.UsersID = Users.ID ";
220
		$q.= "WHERE PackageBaseID = " . $base_id . " ";
221
		$q.= "AND DelUsersID IS NULL ";
222
		$q.= "ORDER BY CommentTS DESC";
223
224
225
226
227

		if (!isset($_GET['comments'])) {
			$q.= " LIMIT 10";
		}

canyonknight's avatar
canyonknight committed
228
		$result = $dbh->query($q);
Loui Chang's avatar
Loui Chang committed
229
230
231
232
233

		if (!$result) {
			return;
		}

canyonknight's avatar
canyonknight committed
234
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
eric's avatar
eric committed
235
236
237
238
239
240
			$comments[] = $row;
		}
	}
	return $comments;
}

241
242
243
244
/**
 * Add a comment to a package page and send out appropriate notifications
 *
 * @global string $AUR_LOCATION The AUR's URL used for notification e-mails
245
 * @param string $base_id The package base ID to add the comment on
246
247
248
249
250
 * @param string $uid The user ID of the individual who left the comment
 * @param string $comment The comment left on a package page
 *
 * @return void
 */
251
function add_package_comment($base_id, $uid, $comment) {
252
253
	global $AUR_LOCATION;

254
	$dbh = DB::connect();
255

canyonknight's avatar
canyonknight committed
256
	$q = "INSERT INTO PackageComments ";
257
258
	$q.= "(PackageBaseID, UsersID, Comments, CommentTS) VALUES (";
	$q.= intval($base_id) . ", " . $uid . ", ";
canyonknight's avatar
canyonknight committed
259
260
	$q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())";
	$dbh->exec($q);
261

262
263
264
265
	/*
	 * Send e-mail notifications.
	 * TODO: Move notification logic to separate function where it belongs.
	 */
canyonknight's avatar
canyonknight committed
266
267
268
269
	$q = "SELECT CommentNotify.*, Users.Email ";
	$q.= "FROM CommentNotify, Users ";
	$q.= "WHERE Users.ID = CommentNotify.UserID ";
	$q.= "AND CommentNotify.UserID != " . $uid . " ";
270
	$q.= "AND CommentNotify.PackageBaseID = " . intval($base_id);
canyonknight's avatar
canyonknight committed
271
	$result = $dbh->query($q);
272
273
	$bcc = array();

canyonknight's avatar
canyonknight committed
274
275
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
276
277
278
			array_push($bcc, $row['Email']);
		}

279
280
		$q = "SELECT Name FROM PackageBases WHERE ID = ";
		$q.= intval($base_id);
canyonknight's avatar
canyonknight committed
281
282
		$result = $dbh->query($q);
		$row = $result->fetch(PDO::FETCH_ASSOC);
283

284
285
286
287
288
289
		/*
		 * TODO: Add native language emails for users, based on their
		 * preferences. Simply making these strings translatable won't
		 * work, users would be getting emails in the language that the
		 * user who posted the comment was in.
		 */
290
		$body =
291
		'from ' . $AUR_LOCATION . get_pkg_uri($row['Name']) . "\n"
292
		. username_from_sid($_COOKIE['AURSID']) . " wrote:\n\n"
293
294
295
296
		. $comment
		. "\n\n---\nIf you no longer wish to receive notifications about this package, please go the the above package page and click the UnNotify button.";
		$body = wordwrap($body, 70);
		$bcc = implode(', ', $bcc);
297
298
299
		$headers = "MIME-Version: 1.0\r\n" .
			   "Content-type: text/plain; charset=UTF-8\r\n" .
			   "Bcc: $bcc\r\n" .
300
301
302
			   "Reply-to: nobody@archlinux.org\r\n" .
			   "From: aur-notify@archlinux.org\r\n" .
			   "X-Mailer: AUR";
303
304
305
306
		@mail('undisclosed-recipients: ;', "AUR Comment for " . $row['Name'], $body, $headers);
	}
}

307
308
309
310
311
312
313
/**
 * Get all package sources for a specific package
 *
 * @param string $pkgid The package ID to get the sources for
 *
 * @return array All sources associated with a specific package
 */
314
function package_sources($pkgid) {
315
	$sources = array();
316
317
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
318
		$dbh = DB::connect();
319
		$q = "SELECT Source FROM PackageSources ";
320
		$q.= "WHERE PackageID = " . $pkgid;
321
		$q.= " ORDER BY Source";
canyonknight's avatar
canyonknight committed
322
323
324
325
326
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
327
328
329
330
331
332
			$sources[] = $row[0];
		}
	}
	return $sources;
}

333
334
335
336
337
338
339
/**
 * Get a list of all packages a logged-in user has voted for
 *
 * @param string $sid The session ID of the visitor
 *
 * @return array All packages the visitor has voted for
 */
340
function pkgvotes_from_sid($sid="") {
341
342
	$pkgs = array();
	if (!$sid) {return $pkgs;}
343
	$dbh = DB::connect();
344
	$q = "SELECT PackageBaseID ";
345
346
347
	$q.= "FROM PackageVotes, Users, Sessions ";
	$q.= "WHERE Users.ID = Sessions.UsersID ";
	$q.= "AND Users.ID = PackageVotes.UsersID ";
canyonknight's avatar
canyonknight committed
348
349
	$q.= "AND Sessions.SessionID = " . $dbh->quote($sid);
	$result = $dbh->query($q);
350
	if ($result) {
canyonknight's avatar
canyonknight committed
351
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
352
353
354
355
356
357
			$pkgs[$row[0]] = 1;
		}
	}
	return $pkgs;
}

358
359
360
361
362
363
364
/**
 * Determine package names from package IDs
 *
 * @param string|array $pkgids The package IDs to get names for
 *
 * @return array|string All names if multiple package IDs, otherwise package name
 */
365
function pkgname_from_id($pkgids) {
366
367
368
	if (is_array($pkgids)) {
		$pkgids = sanitize_ids($pkgids);
		$names = array();
369
		$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
370
371
372
373
374
		$q = "SELECT Name FROM Packages WHERE ID IN (";
		$q.= implode(",", $pkgids) . ")";
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
375
376
377
378
379
380
				$names[] = $row['Name'];
			}
		}
		return $names;
	}
	elseif ($pkgids > 0) {
381
		$dbh = DB::connect();
382
		$q = "SELECT Name FROM Packages WHERE ID = " . $pkgids;
canyonknight's avatar
canyonknight committed
383
384
385
		$result = $dbh->query($q);
		if ($result) {
			$name = $result->fetch(PDO::FETCH_NUM);
386
		}
canyonknight's avatar
canyonknight committed
387
		return $name[0];
388
389
390
	}
	else {
		return NULL;
391
392
393
	}
}

394
395
396
397
398
399
400
/**
 * Determine if a package name is on the database blacklist
 *
 * @param string $name The package name to check
 *
 * @return bool True if the name is blacklisted, otherwise false
 */
401
function pkgname_is_blacklisted($name) {
402
	$dbh = DB::connect();
canyonknight's avatar
canyonknight committed
403
404
405
	$q = "SELECT COUNT(*) FROM PackageBlacklist ";
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
406
407

	if (!$result) return false;
408
	return ($result->fetchColumn() > 0);
409
410
}

411
/**
412
 * Get the package details
413
 *
414
 * @param string $id The package ID to get description for
415
 *
416
417
 * @return array The package's details OR error message
 **/
418
function get_package_details($id=0) {
419
	$dbh = DB::connect();
420

421
422
423
424
425
426
427
428
	$q = "SELECT Packages.*, PackageBases.Name AS BaseName, ";
	$q.= "PackageBases.CategoryID, PackageBases.NumVotes, ";
	$q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, ";
	$q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, ";
	$q.= "PackageBases.MaintainerUID, PackageCategories.Category ";
	$q.= "FROM Packages, PackageBases, PackageCategories ";
	$q.= "WHERE PackageBases.ID = Packages.PackageBaseID ";
	$q.= "AND PackageBases.CategoryID = PackageCategories.ID ";
Loui Chang's avatar
Loui Chang committed
429
	$q.= "AND Packages.ID = " . intval($id);
canyonknight's avatar
canyonknight committed
430
	$result = $dbh->query($q);
eric's avatar
eric committed
431

432
433
	$row = array();

canyonknight's avatar
canyonknight committed
434
	if (!$result) {
435
		$row['error'] = __("Error retrieving package details.");
436
437
	}
	else {
canyonknight's avatar
canyonknight committed
438
		$row = $result->fetch(PDO::FETCH_ASSOC);
eric's avatar
eric committed
439
		if (empty($row)) {
440
			$row['error'] = __("Package details could not be found.");
441
		}
442
443
444
445
446
	}

	return $row;
}

447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
/**
 * Get the package base details
 *
 * @param string $id The package base ID to get description for
 *
 * @return array The package base's details OR error message
 **/
function get_pkgbase_details($base_id) {
	$dbh = DB::connect();

	$q = "SELECT PackageBases.ID, PackageBases.Name, ";
	$q.= "PackageBases.CategoryID, PackageBases.NumVotes, ";
	$q.= "PackageBases.OutOfDateTS, PackageBases.SubmittedTS, ";
	$q.= "PackageBases.ModifiedTS, PackageBases.SubmitterUID, ";
	$q.= "PackageBases.MaintainerUID, PackageCategories.Category ";
	$q.= "FROM PackageBases, PackageCategories ";
	$q.= "WHERE PackageBases.CategoryID = PackageCategories.ID ";
	$q.= "AND PackageBases.ID = " . intval($base_id);
	$result = $dbh->query($q);

	$row = array();

	if (!$result) {
		$row['error'] = __("Error retrieving package details.");
	}
	else {
		$row = $result->fetch(PDO::FETCH_ASSOC);
		if (empty($row)) {
			$row['error'] = __("Package details could not be found.");
		}
	}

	return $row;
}

482
483
484
485
486
487
488
489
490
491
492
/**
 * Display the package details page
 *
 * @global string $AUR_LOCATION The AUR's URL used for notification e-mails
 * @global bool $USE_VIRTUAL_URLS True if using URL rewriting, otherwise false
 * @param string $id The package ID to get details page for
 * @param array $row Package details retrieved by get_package_details
 * @param string $SID The session ID of the visitor
 *
 * @return void
 */
493
function display_package_details($id=0, $row, $SID="") {
494
495
496
	global $AUR_LOCATION;
	global $USE_VIRTUAL_URLS;

497
	$dbh = DB::connect();
498

499
500
501
502
	if (isset($row['error'])) {
		print "<p>" . $row['error'] . "</p>\n";
	}
	else {
503
504
505
		$base_id = pkgbase_from_pkgid($id);
		$pkgbase_name = pkgbase_name_from_id($base_id);

506
507
508
509
510
511
512
		include('pkg_details.php');

		if ($SID) {
			include('actions_form.php');
			include('pkg_comment_form.php');
		}

513
		$comments = package_comments($base_id);
514
515
		if (!empty($comments)) {
			include('pkg_comments.php');
eric's avatar
eric committed
516
517
518
519
		}
	}
}

520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
/**
 * Display the package base details page
 *
 * @global string $AUR_LOCATION The AUR's URL used for notification e-mails
 * @global bool $USE_VIRTUAL_URLS True if using URL rewriting, otherwise false
 * @param string $id The package base ID to get details page for
 * @param array $row Package base details retrieved by get_pkgbase_details
 * @param string $SID The session ID of the visitor
 *
 * @return void
 */
function display_pkgbase_details($base_id, $row, $SID="") {
	global $AUR_LOCATION;
	global $USE_VIRTUAL_URLS;

	$dbh = DB::connect();

	if (isset($row['error'])) {
		print "<p>" . $row['error'] . "</p>\n";
	}
	else {
541
542
		$pkgbase_name = pkgbase_name_from_id($base_id);

543
544
545
546
547
548
549
550
551
552
553
554
555
556
		include('pkgbase_details.php');

		if ($SID) {
			include('actions_form.php');
			include('pkg_comment_form.php');
		}

		$comments = package_comments($base_id);
		if (!empty($comments)) {
			include('pkg_comments.php');
		}
	}
}

eric's avatar
eric committed
557

Simo Leone's avatar
Simo Leone committed
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
/* pkg_search_page(SID)
 * outputs the body of search/search results page
 *
 * parameters:
 *  SID - current Session ID
 * preconditions:
 *  package search page has been accessed
 *  request variables have not been sanitized
 *
 *  request vars:
 *    O  - starting result number
 *    PP - number of search hits per page
 *    C  - package category ID number
 *    K  - package search string
 *    SO - search hit sort order:
 *          values: a - ascending
 *                  d - descending
 *    SB - sort search hits by:
576
 *          values: c - package category
Simo Leone's avatar
Simo Leone committed
577
578
579
580
 *                  n - package name
 *                  v - number of votes
 *                  m - maintainer username
 *    SeB- property that search string (K) represents
Andrea Scarpino's avatar
Andrea Scarpino committed
581
582
 *          values: n  - package name
 *                  nd - package name & description
583
 *                  x  - package name (exact match)
Simo Leone's avatar
Simo Leone committed
584
585
586
587
588
589
590
591
592
593
594
595
596
597
 *                  m  - package maintainer's username
 *                  s  - package submitter's username
 *    do_Orphans    - boolean. whether to search packages
 *                     without a maintainer
 *
 *
 *    These two are actually handled in packages.php.
 *
 *    IDs- integer array of ticked packages' IDs
 *    action - action to be taken on ticked packages
 *             values: do_Flag   - Flag out-of-date
 *                     do_UnFlag - Remove out-of-date flag
 *                     do_Adopt  - Adopt
 *                     do_Disown - Disown
598
 *                     do_Delete - Delete (requires confirm_Delete to be set)
599
600
 *                     do_Notify - Enable notification
 *                     do_UnNotify - Disable notification
Simo Leone's avatar
Simo Leone committed
601
 */
602
function pkg_search_page($SID="") {
603
	$dbh = DB::connect();
Loui Chang's avatar
Loui Chang committed
604

605
606
607
608
	/*
	 * Get commonly used variables.
	 * TODO: Reduce the number of database queries!
	 */
Loui Chang's avatar
Loui Chang committed
609
	if ($SID)
610
		$myuid = uid_from_sid($SID);
611
	$cats = pkg_categories($dbh);
Loui Chang's avatar
Loui Chang committed
612

613
	/* Sanitize paging variables. */
Loui Chang's avatar
Loui Chang committed
614
615
616
617
618
619
620
621
622
623
624
	if (isset($_GET['O'])) {
		$_GET['O'] = intval($_GET['O']);
		if ($_GET['O'] < 0)
			$_GET['O'] = 0;
	}
	else {
		$_GET['O'] = 0;
	}

	if (isset($_GET["PP"])) {
		$_GET["PP"] = intval($_GET["PP"]);
625
626
627
628
		if ($_GET["PP"] < 50)
			$_GET["PP"] = 50;
		else if ($_GET["PP"] > 250)
			$_GET["PP"] = 250;
Loui Chang's avatar
Loui Chang committed
629
630
	}
	else {
631
		$_GET["PP"] = 50;
Loui Chang's avatar
Loui Chang committed
632
633
	}

634
635
636
637
	/*
	 * FIXME: Pull out DB-related code. All of it! This one's worth a
	 * choco-chip cookie, one of those nice big soft ones.
	 */
Loui Chang's avatar
Loui Chang committed
638

639
	/* Build the package search query. */
640
	$q_select = "SELECT ";
Loui Chang's avatar
Loui Chang committed
641
	if ($SID) {
642
		$q_select .= "CommentNotify.UserID AS Notify,
643
			   PackageVotes.UsersID AS Voted, ";
Loui Chang's avatar
Loui Chang committed
644
	}
645
	$q_select .= "Users.Username AS Maintainer,
Loui Chang's avatar
Loui Chang committed
646
	PackageCategories.Category,
647
	Packages.Name, Packages.Version, Packages.Description,
648
649
	PackageBases.NumVotes, Packages.ID, Packages.PackageBaseID,
	PackageBases.OutOfDateTS ";
Loui Chang's avatar
Loui Chang committed
650

651
	$q_from = "FROM Packages
652
653
	LEFT JOIN PackageBases ON (PackageBases.ID = Packages.PackageBaseID)
	LEFT JOIN Users ON (PackageBases.MaintainerUID = Users.ID)
654
	LEFT JOIN PackageCategories
655
	ON (PackageBases.CategoryID = PackageCategories.ID) ";
Loui Chang's avatar
Loui Chang committed
656
	if ($SID) {
657
		/* This is not needed for the total row count query. */
658
		$q_from_extra = "LEFT JOIN PackageVotes
659
		ON (PackageBases.ID = PackageVotes.PackageBaseID AND PackageVotes.UsersID = $myuid)
Loui Chang's avatar
Loui Chang committed
660
		LEFT JOIN CommentNotify
661
		ON (PackageBases.ID = CommentNotify.PackageBaseID AND CommentNotify.UserID = $myuid) ";
662
663
	} else {
		$q_from_extra = "";
Loui Chang's avatar
Loui Chang committed
664
665
	}

Dan McGee's avatar
Dan McGee committed
666
	$q_where = "WHERE 1 = 1 ";
667
668
669
670
	/*
	 * TODO: Possibly do string matching on category to make request
	 * variable values more sensible.
	 */
671
	if (isset($_GET["C"]) && intval($_GET["C"])) {
672
		$q_where .= "AND Packages.CategoryID = ".intval($_GET["C"])." ";
Loui Chang's avatar
Loui Chang committed
673
674
	}

675
676
	if (isset($_GET['K'])) {
		if (isset($_GET["SeB"]) && $_GET["SeB"] == "m") {
677
			/* Search by maintainer. */
canyonknight's avatar
canyonknight committed
678
			$q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . " ";
Loui Chang's avatar
Loui Chang committed
679
		}
680
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "s") {
681
			/* Search by submitter. */
682
			$q_where .= "AND SubmitterUID = ".uid_from_username($_GET['K'])." ";
Loui Chang's avatar
Loui Chang committed
683
		}
684
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "n") {
685
			/* Search by name. */
canyonknight's avatar
canyonknight committed
686
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
687
			$q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . ") ";
Andrea Scarpino's avatar
Andrea Scarpino committed
688
		}
689
690
691
692
693
694
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "b") {
			/* Search by package base name. */
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
			$q_where .= "AND (PackageBases.Name LIKE " . $dbh->quote($K) . ") ";
		}
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "N") {
695
			/* Search by name (exact match). */
696
			$q_where .= "AND (Packages.Name = " . $dbh->quote($_GET['K']) . ") ";
697
		}
698
699
700
701
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "B") {
			/* Search by package base name (exact match). */
			$q_where .= "AND (PackageBases.Name = " . $dbh->quote($_GET['K']) . ") ";
		}
Loui Chang's avatar
Loui Chang committed
702
		else {
703
			/* Search by name and description (default). */
canyonknight's avatar
canyonknight committed
704
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
705
			$q_where .= "AND (Packages.Name LIKE " . $dbh->quote($K) . " OR ";
canyonknight's avatar
canyonknight committed
706
			$q_where .= "Description LIKE " . $dbh->quote($K) . ") ";
Loui Chang's avatar
Loui Chang committed
707
708
709
		}
	}

710
	if (isset($_GET["do_Orphans"])) {
711
		$q_where .= "AND MaintainerUID IS NULL ";
Loui Chang's avatar
Loui Chang committed
712
	}
713

714
	if (isset($_GET['outdated'])) {
715
		if ($_GET['outdated'] == 'on') {
716
			$q_where .= "AND OutOfDateTS IS NOT NULL ";
717
718
		}
		elseif ($_GET['outdated'] == 'off') {
719
			$q_where .= "AND OutOfDateTS IS NULL ";
720
		}
721
722
	}

723
	$order = (isset($_GET["SO"]) && $_GET["SO"] == 'd') ? 'DESC' : 'ASC';
Loui Chang's avatar
Loui Chang committed
724

725
	$q_sort = "ORDER BY ";
726
727
	$sort_by = isset($_GET["SB"]) ? $_GET["SB"] : '';
	switch ($sort_by) {
Loui Chang's avatar
Loui Chang committed
728
	case 'c':
729
		$q_sort .= "CategoryID " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
730
731
		break;
	case 'v':
732
		$q_sort .= "NumVotes " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
733
		break;
734
735
	case 'w':
		if ($SID) {
736
			$q_sort .= "Voted " . $order . ", ";
737
738
739
740
		}
		break;
	case 'o':
		if ($SID) {
741
			$q_sort .= "Notify " . $order . ", ";
742
743
		}
		break;
Loui Chang's avatar
Loui Chang committed
744
	case 'm':
745
		$q_sort .= "Maintainer " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
746
747
		break;
	case 'a':
748
		$q_sort .= "ModifiedTS " . $order . ", ";
Loui Chang's avatar
Loui Chang committed
749
750
751
752
		break;
	default:
		break;
	}
753
	$q_sort .= " Packages.Name " . $order . " ";
Loui Chang's avatar
Loui Chang committed
754

755
	$q_limit = "LIMIT ".$_GET["PP"]." OFFSET ".$_GET["O"];
756

757
758
	$q = $q_select . $q_from . $q_from_extra . $q_where . $q_sort . $q_limit;
	$q_total = "SELECT COUNT(*) " . $q_from . $q_where;
Loui Chang's avatar
Loui Chang committed
759

canyonknight's avatar
canyonknight committed
760
761
	$result = $dbh->query($q);
	$result_t = $dbh->query($q_total);
762
	if ($result_t) {
canyonknight's avatar
canyonknight committed
763
764
		$row = $result_t->fetch(PDO::FETCH_NUM);
		$total = $row[0];
765
766
767
768
	}
	else {
		$total = 0;
	}
Simo Leone's avatar
Simo Leone committed
769

770
	if ($result && $total > 0) {
771
772
		if (isset($_GET["SO"]) && $_GET["SO"] == "d"){
			$SO_next = "a";
Loui Chang's avatar
Loui Chang committed
773
774
		}
		else {
775
			$SO_next = "d";
Loui Chang's avatar
Loui Chang committed
776
		}
777
	}
Simo Leone's avatar
Simo Leone committed
778

779
	/* Calculate the results to use. */
Loui Chang's avatar
Loui Chang committed
780
	$first = $_GET['O'] + 1;
Simo Leone's avatar
Simo Leone committed
781

782
	/* Calculation of pagination links. */
783
784
785
786
	$per_page = ($_GET['PP'] > 0) ? $_GET['PP'] : 50;
	$current = ceil($first / $per_page);
	$pages = ceil($total / $per_page);
	$templ_pages = array();
787

788
	if ($current > 1) {
789
790
		$templ_pages['&laquo; ' . __('First')] = 0;
		$templ_pages['&lsaquo; ' . __('Previous')] = ($current - 2) * $per_page;
791
	}
792

793
794
	if ($current - 5 > 1)
		$templ_pages["..."] = false;
795

796
797
798
	for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) {
		$templ_pages[$i] = ($i - 1) * $per_page;
	}
799

800
801
	if ($current + 5 < $pages)
		$templ_pages["... "] = false;
802

803
	if ($current < $pages) {
804
805
		$templ_pages[__('Next') . ' &rsaquo;'] = $current * $per_page;
		$templ_pages[__('Last') . ' &raquo;'] = ($pages - 1) * $per_page;
806
	}
Simo Leone's avatar
Simo Leone committed
807

808
	include('pkg_search_form.php');
809

canyonknight's avatar
canyonknight committed
810
811
812
813
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
			$searchresults[] = $row;
		}
814
815
	}

816
817
	include('pkg_search_results.php');

Loui Chang's avatar
Loui Chang committed
818
	return;
eric's avatar
eric committed
819
820
}

821
822
823
824
825
826
827
/**
 * Determine if a POST string has been sent by a visitor
 *
 * @param string $action String to check has been sent via POST
 *
 * @return bool True if the POST string was used, otherwise false
 */
Dan McGee's avatar
Dan McGee committed
828
829
830
831
832
function current_action($action) {
	return (isset($_POST['action']) && $_POST['action'] == $action) ||
		isset($_POST[$action]);
}

833
/**
834
835
836
837
838
 * Determine if sent IDs are valid integers
 *
 * @param array $ids IDs to validate
 *
 * @return array All sent IDs that are valid integers
839
840
841
842
843
844
845
846
847
848
849
850
 */
function sanitize_ids($ids) {
	$new_ids = array();
	foreach ($ids as $id) {
		$id = intval($id);
		if ($id > 0) {
			$new_ids[] = $id;
		}
	}
	return $new_ids;
}

851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
/**
 * Convert a list of package IDs into a list of corresponding package bases.
 *
 * @param array|int $ids Array of package IDs to convert
 *
 * @return array|int List of package base IDs
 */
function pkgbase_from_pkgid($ids) {
	$dbh = DB::connect();

	if (is_array($ids)) {
		$q = "SELECT PackageBaseID FROM Packages ";
		$q.= "WHERE ID IN (" . implode(",", $ids) . ")";
		$result = $dbh->query($q);
		return $result->fetchAll(PDO::FETCH_COLUMN, 0);
	} else {
		$q = "SELECT PackageBaseID FROM Packages ";
		$q.= "WHERE ID = " . $ids;
		$result = $dbh->query($q);
		return $result->fetch(PDO::FETCH_COLUMN, 0);
	}
}

874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
/**
 * Retrieve ID of a package base by name
 *
 * @param string $name The package base name to retrieve the ID for
 *
 * @return int The ID of the package base
 */
function pkgbase_from_name($name) {
	$dbh = DB::connect();
	$q = "SELECT ID FROM PackageBases WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
	return $result->fetch(PDO::FETCH_COLUMN, 0);
}

/**
 * Retrieve the name of a package base given its ID
 *
 * @param int $base_id The ID of the package base to query
 *
 * @return string The name of the package base
 */
function pkgbase_name_from_id($base_id) {
	$dbh = DB::connect();
	$q = "SELECT Name FROM PackageBases WHERE ID = " . intval($base_id);
	$result = $dbh->query($q);
	return $result->fetch(PDO::FETCH_COLUMN, 0);
}

902
903
904
905
906
907
908
909
910
911
912
913
914
915
/**
 * Get the names of all packages belonging to a package base
 *
 * @param int $base_id The ID of the package base
 *
 * @return array The names of all packages belonging to the package base
 */
function pkgbase_get_pkgnames($base_id) {
	$dbh = DB::connect();
	$q = "SELECT Name FROM Packages WHERE PackageBaseID = " . intval($base_id);
	$result = $dbh->query($q);
	return $result->fetchAll(PDO::FETCH_COLUMN, 0);
}

916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
/**
 * Delete all packages belonging to a package base
 *
 * @param int $base_id The ID of the package base
 *
 * @return void
 */
function pkgbase_delete_packages($base_id) {
	$dbh = DB::connect();
	$q = "DELETE FROM Packages WHERE PackageBaseID = " . intval($base_id);
	$dbh->exec($q);
}

/**
 * Retrieve the maintainer of a package base given its ID
 *
 * @param int $base_id The ID of the package base to query
 *
 * @return int The user ID of the current package maintainer
 */
function pkgbase_maintainer_uid($base_id) {
	$dbh = DB::connect();
	$q = "SELECT MaintainerUID FROM PackageBases WHERE ID = " . intval($base_id);
	$result = $dbh->query($q);
	return $result->fetch(PDO::FETCH_COLUMN, 0);
}

943

944
/**
945
 * Flag package(s) as out-of-date
946
 *
947
 * @global string $AUR_LOCATION The AUR's URL used for notification e-mails
948
 * @param string $atype Account type, output of account_from_sid
949
 * @param array $base_ids Array of package base IDs to flag/unflag
950
 *
951
 * @return array Tuple of success/failure indicator and error message
952
 */
953
function pkg_flag($atype, $base_ids) {
Dan McGee's avatar
Dan McGee committed
954
955
	global $AUR_LOCATION;

956
	if (!$atype) {
957
		return array(false, __("You must be logged in before you can flag packages."));
958
959
	}

960
961
	$base_ids = pkgbase_from_pkgid($base_ids);
	if (empty($base_ids)) {
962
		return array(false, __("You did not select any packages to flag."));
963
964
	}

965
	$dbh = DB::connect();
966

967
	$q = "UPDATE PackageBases SET";
968
	$q.= " OutOfDateTS = UNIX_TIMESTAMP()";
969
	$q.= " WHERE ID IN (" . implode(",", $base_ids) . ")";
970
	$q.= " AND OutOfDateTS IS NULL";
971
972
973

	$affected_pkgs = $dbh->exec($q);

974
	if ($affected_pkgs > 0) {
975
		/* Notify of flagging by e-mail. */
976
977
978
		$f_name = username_from_sid($_COOKIE['AURSID']);
		$f_email = email_from_sid($_COOKIE['AURSID']);
		$f_uid = uid_from_sid($_COOKIE['AURSID']);
979
980
981
982
		$q = "SELECT PackageBases.Name, Users.Email ";
		$q.= "FROM PackageBases, Users ";
		$q.= "WHERE PackageBases.ID IN (" . implode(",", $base_ids) .") ";
		$q.= "AND Users.ID = PackageBases.MaintainerUID ";
983
		$q.= "AND Users.ID != " . $f_uid;
canyonknight's avatar
canyonknight committed
984
985
986
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
987
				$body = "Your package " . $row['Name'] . " has been flagged out of date by " . $f_name . " [1]. You may view your package at:\n" . $AUR_LOCATION . get_pkg_uri($row['Name']) . "\n\n[1] - " . $AUR_LOCATION . get_user_uri($f_name);
988
				$body = wordwrap($body, 70);
989
990
991
				$headers = "MIME-Version: 1.0\r\n" .
					   "Content-type: text/plain; charset=UTF-8\r\n" .
					   "Reply-to: nobody@archlinux.org\r\n" .
992
993
994
					   "From: aur-notify@archlinux.org\r\n" .
					   "X-Mailer: PHP\r\n" .
					   "X-MimeOLE: Produced By AUR";
995
				@mail($row['Email'], "AUR Out-of-date Notification for ".$row['Name'], $body, $headers);
996
997
998
999
			}
		}
	}

1000
	return array(true, __("The selected packages have been flagged out-of-date."));
For faster browsing, not all history is shown. View entire blame