pkgfuncs.inc.php 40.8 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
16
/**
 * 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
 * @param \PDO $dbh An already established database connection
 *
 * @return bool True if the user can delete the comment, otherwise false
 */
17
function canDeleteComment($comment_id=0, $atype="", $uid=0, $dbh=NULL) {
18
19
20
21
	if ($atype == "Trusted User" || $atype == "Developer") {
		# A TU/Dev can delete any comment
		return TRUE;
	}
22
23
24
	if(!$dbh) {
		$dbh = db_connect();
	}
25
26
27
28
	$q = "SELECT COUNT(ID) AS CNT ";
	$q.= "FROM PackageComments ";
	$q.= "WHERE ID = " . intval($comment_id);
	$q.= " AND UsersID = " . $uid;
canyonknight's avatar
canyonknight committed
29
	$result = $dbh->query($q);
30
	if ($result != NULL) {
canyonknight's avatar
canyonknight committed
31
		$row = $result->fetch(PDO::FETCH_ASSOC);
32
33
34
35
36
37
		if ($row['CNT'] > 0) {
			return TRUE;
		}
	}
	return FALSE;
}
eric's avatar
eric committed
38

39
40
41
42
43
44
45
46
47
48
49
50
/**
 * 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
 */
51
52
53
54
55
56
57
58
59
60
61
function canDeleteCommentArray($comment, $atype="", $uid=0) {
	if ($atype == "Trusted User" || $atype == "Developer") {
		# A TU/Dev can delete any comment
		return TRUE;
	} else if ($comment['UsersID'] == $uid) {
		# User's own comment
		return TRUE;
	}
	return FALSE;
}

62
63
64
65
66
67
68
69
70
71
/**
 * 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
 */
72
73
74
75
76
77
78
79
80
81
function canSubmitBlacklisted($atype = "") {
	if ($atype == "Trusted User" || $atype == "Developer") {
		# Only TUs/Devs can submit blacklisted packages.
		return TRUE;
	}
	else {
		return FALSE;
	}
}

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

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

128
129
130
131
132
133
134
135
/**
 * Get package dependencies for a specific package
 *
 * @param int $pkgid The package to get dependencies for
 * @param \PDO $dbh An already established database connection
 *
 * @return array All package dependencies for the package
 */
136
function package_dependencies($pkgid, $dbh=NULL) {
137
	$deps = array();
138
139
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
140
141
142
		if(!$dbh) {
			$dbh = db_connect();
		}
Dan McGee's avatar
Dan McGee committed
143
144
145
146
		$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
147
148
149
150
151
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
152
153
154
155
156
157
			$deps[] = $row;
		}
	}
	return $deps;
}

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

185
186
187
188
189
190
191
192
/**
 * Get the number of non-deleted comments for a specific package
 *
 * @param string $pkgid The package ID to get comment count for
 * @param \PDO $dbh An already established database connection
 *
 * @return string The number of comments left for a specific package
 */
193
function package_comments_count($pkgid, $dbh=NULL) {
canyonknight's avatar
canyonknight committed
194
195
196
197
	if (!$dbh) {
		$dbh = db_connect();
	}

198
199
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
200
201
202
		if(!$dbh) {
			$dbh = db_connect();
		}
203
		$q = "SELECT COUNT(*) FROM PackageComments ";
204
		$q.= "WHERE PackageID = " . $pkgid;
205
		$q.= " AND DelUsersID IS NULL";
206
	}
canyonknight's avatar
canyonknight committed
207
	$result = $dbh->query($q);
208
209
210
211
212

	if (!$result) {
		return;
	}

canyonknight's avatar
canyonknight committed
213
214
	$row = $result->fetch(PDO::FETCH_NUM);
	return $row[0];
215
216
}

217
218
219
220
221
222
223
224
/**
 * Get all package comment information for a specific package
 *
 * @param int $pkgid The package ID to get comments for
 * @param \PDO $dbh An already established database connection
 *
 * @return array All package comment information for a specific package
 */
225
function package_comments($pkgid, $dbh=NULL) {
eric's avatar
eric committed
226
	$comments = array();
227
228
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
229
230
231
		if(!$dbh) {
			$dbh = db_connect();
		}
232
		$q = "SELECT PackageComments.ID, UserName, UsersID, Comments, CommentTS ";
eric's avatar
eric committed
233
234
		$q.= "FROM PackageComments, Users ";
		$q.= "WHERE PackageComments.UsersID = Users.ID";
235
		$q.= " AND PackageID = " . $pkgid;
236
		$q.= " AND DelUsersID IS NULL"; # only display non-deleted comments
237
		$q.= " ORDER BY CommentTS DESC";
238
239
240
241
242

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

canyonknight's avatar
canyonknight committed
243
		$result = $dbh->query($q);
Loui Chang's avatar
Loui Chang committed
244
245
246
247
248

		if (!$result) {
			return;
		}

canyonknight's avatar
canyonknight committed
249
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
eric's avatar
eric committed
250
251
252
253
254
255
			$comments[] = $row;
		}
	}
	return $comments;
}

256
257
258
259
260
261
262
263
264
265
266
/**
 * 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
 * @param string $pkgid The package ID to add the comment on
 * @param string $uid The user ID of the individual who left the comment
 * @param string $comment The comment left on a package page
 * @param \PDO $dbh An already established database connection
 *
 * @return void
 */
267
function add_package_comment($pkgid, $uid, $comment, $dbh=NULL) {
268
269
	global $AUR_LOCATION;

270
271
272
273
	if(!$dbh) {
		$dbh = db_connect();
	}

canyonknight's avatar
canyonknight committed
274
275
276
277
278
	$q = "INSERT INTO PackageComments ";
	$q.= "(PackageID, UsersID, Comments, CommentTS) VALUES (";
	$q.= intval($pkgid) . ", " . $uid . ", ";
	$q.= $dbh->quote($comment) . ", UNIX_TIMESTAMP())";
	$dbh->exec($q);
279

280
        # TODO: Move notification logic to separate function where it belongs
281
	# Send email notifications
canyonknight's avatar
canyonknight committed
282
283
284
285
286
287
	$q = "SELECT CommentNotify.*, Users.Email ";
	$q.= "FROM CommentNotify, Users ";
	$q.= "WHERE Users.ID = CommentNotify.UserID ";
	$q.= "AND CommentNotify.UserID != " . $uid . " ";
	$q.= "AND CommentNotify.PkgID = " . intval($pkgid);
	$result = $dbh->query($q);
288
289
	$bcc = array();

canyonknight's avatar
canyonknight committed
290
291
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
292
293
294
			array_push($bcc, $row['Email']);
		}

canyonknight's avatar
canyonknight committed
295
296
297
298
299
		$q = "SELECT Packages.* ";
		$q.= "FROM Packages ";
		$q.= "WHERE Packages.ID = " . intval($pkgid);
		$result = $dbh->query($q);
		$row = $result->fetch(PDO::FETCH_ASSOC);
300
301
302
303
304

		# TODO: native language emails for users, based on their prefs
		# 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
		$body =
305
		'from ' . $AUR_LOCATION . get_pkg_uri($row['Name']) . "\n"
306
307
308
309
310
311
312
313
314
315
		. username_from_sid($_COOKIE['AURSID'], $dbh) . " wrote:\n\n"
		. $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);
		$headers = "Bcc: $bcc\nReply-to: nobody@archlinux.org\nFrom: aur-notify@archlinux.org\nX-Mailer: AUR\n";
		@mail('undisclosed-recipients: ;', "AUR Comment for " . $row['Name'], $body, $headers);
	}
}

316
317
318
319
320
321
322
323
/**
 * Get all package sources for a specific package
 *
 * @param string $pkgid The package ID to get the sources for
 * @param \PDO $dbh An already established database connection
 *
 * @return array All sources associated with a specific package
 */
324
function package_sources($pkgid, $dbh=NULL) {
325
	$sources = array();
326
327
	$pkgid = intval($pkgid);
	if ($pkgid > 0) {
328
329
330
		if(!$dbh) {
			$dbh = db_connect();
		}
331
		$q = "SELECT Source FROM PackageSources ";
332
		$q.= "WHERE PackageID = " . $pkgid;
333
		$q.= " ORDER BY Source";
canyonknight's avatar
canyonknight committed
334
335
336
337
338
		$result = $dbh->query($q);
		if (!$result) {
			return array();
		}
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
339
340
341
342
343
344
			$sources[] = $row[0];
		}
	}
	return $sources;
}

345
346
347
348
349
350
351
352
/**
 * Get a list of all packages a logged-in user has voted for
 *
 * @param string $sid The session ID of the visitor
 * @param \PDO $dbh An already established database connection
 *
 * @return array All packages the visitor has voted for
 */
353
function pkgvotes_from_sid($sid="", $dbh=NULL) {
354
355
	$pkgs = array();
	if (!$sid) {return $pkgs;}
356
357
358
	if(!$dbh) {
		$dbh = db_connect();
	}
359
360
361
362
	$q = "SELECT PackageID ";
	$q.= "FROM PackageVotes, Users, Sessions ";
	$q.= "WHERE Users.ID = Sessions.UsersID ";
	$q.= "AND Users.ID = PackageVotes.UsersID ";
canyonknight's avatar
canyonknight committed
363
364
	$q.= "AND Sessions.SessionID = " . $dbh->quote($sid);
	$result = $dbh->query($q);
365
	if ($result) {
canyonknight's avatar
canyonknight committed
366
		while ($row = $result->fetch(PDO::FETCH_NUM)) {
367
368
369
370
371
372
			$pkgs[$row[0]] = 1;
		}
	}
	return $pkgs;
}

373
374
375
376
377
378
379
380
/**
 * Determine package names from package IDs
 *
 * @param string|array $pkgids The package IDs to get names for
 * @param \PDO $dbh An already established database connection
 *
 * @return array|string All names if multiple package IDs, otherwise package name
 */
381
382
383
384
function pkgname_from_id($pkgids, $dbh=NULL) {
	if (is_array($pkgids)) {
		$pkgids = sanitize_ids($pkgids);
		$names = array();
385
386
387
		if(!$dbh) {
			$dbh = db_connect();
		}
canyonknight's avatar
canyonknight committed
388
389
390
391
392
		$q = "SELECT Name FROM Packages WHERE ID IN (";
		$q.= implode(",", $pkgids) . ")";
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
393
394
395
396
397
398
399
400
401
402
				$names[] = $row['Name'];
			}
		}
		return $names;
	}
	elseif ($pkgids > 0) {
		if(!$dbh) {
			$dbh = db_connect();
		}
		$q = "SELECT Name FROM Packages WHERE ID = " . $pkgids;
canyonknight's avatar
canyonknight committed
403
404
405
		$result = $dbh->query($q);
		if ($result) {
			$name = $result->fetch(PDO::FETCH_NUM);
406
		}
canyonknight's avatar
canyonknight committed
407
		return $name[0];
408
409
410
	}
	else {
		return NULL;
411
412
413
	}
}

414
415
416
417
418
419
420
421
/**
 * Determine if a package name is on the database blacklist
 *
 * @param string $name The package name to check
 * @param \PDO $dbh An already established database connection
 *
 * @return bool True if the name is blacklisted, otherwise false
 */
422
423
424
425
function pkgname_is_blacklisted($name, $dbh=NULL) {
	if(!$dbh) {
		$dbh = db_connect();
	}
canyonknight's avatar
canyonknight committed
426
427
428
	$q = "SELECT COUNT(*) FROM PackageBlacklist ";
	$q.= "WHERE Name = " . $dbh->quote($name);
	$result = $dbh->query($q);
429
430

	if (!$result) return false;
431
	return ($result->fetchColumn() > 0);
432
433
}

434
435
436
437
438
439
440
441
442
443
444
/**
 * 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 string $SID The session ID of the visitor
 * @param \PDO $dbh An already established database connection
 *
 * @return void
 */
445
function package_details($id=0, $SID="", $dbh=NULL) {
Dan McGee's avatar
Dan McGee committed
446
	global $AUR_LOCATION;
447
	global $USE_VIRTUAL_URLS;
Dan McGee's avatar
Dan McGee committed
448

449
450
451
452
	if(!$dbh) {
		$dbh = db_connect();
	}

453
454
455
	$q = "SELECT Packages.*,Category ";
	$q.= "FROM Packages,PackageCategories ";
	$q.= "WHERE Packages.CategoryID = PackageCategories.ID ";
Loui Chang's avatar
Loui Chang committed
456
	$q.= "AND Packages.ID = " . intval($id);
canyonknight's avatar
canyonknight committed
457
	$result = $dbh->query($q);
eric's avatar
eric committed
458

canyonknight's avatar
canyonknight committed
459
	if (!$result) {
Dario Giovannetti's avatar
Dario Giovannetti committed
460
		print "<p>" . __("Error retrieving package details.") . "</p>\n";
461
462
	}
	else {
canyonknight's avatar
canyonknight committed
463
		$row = $result->fetch(PDO::FETCH_ASSOC);
eric's avatar
eric committed
464
		if (empty($row)) {
Dario Giovannetti's avatar
Dario Giovannetti committed
465
			print "<p>" . __("Package details could not be found.") . "</p>\n";
eric's avatar
eric committed
466

467
468
469
		}
		else {
			include('pkg_details.php');
eric's avatar
eric committed
470

simo's avatar
simo committed
471
472
			# Actions Bar
			if ($SID) {
Loui Chang's avatar
Loui Chang committed
473
				include('actions_form.php');
Lukas Fleischer's avatar
Lukas Fleischer committed
474
				if (isset($_REQUEST['comment']) && check_token()) {
475
476
477
					$uid = uid_from_sid($SID, $dbh);
					add_package_comment($id, $uid, $_REQUEST['comment'], $dbh);
				}
478
				include('pkg_comment_form.php');
simo's avatar
simo committed
479
			}
480

481
			# Print Comments
482
			$comments = package_comments($id, $dbh);
eric's avatar
eric committed
483
			if (!empty($comments)) {
484
				include('pkg_comments.php');
eric's avatar
eric committed
485
			}
eric's avatar
eric committed
486
487
488
489
490
491
		}
	}
	return;
}


Simo Leone's avatar
Simo Leone committed
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
/* 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:
510
 *          values: c - package category
Simo Leone's avatar
Simo Leone committed
511
512
513
514
 *                  n - package name
 *                  v - number of votes
 *                  m - maintainer username
 *    SeB- property that search string (K) represents
Andrea Scarpino's avatar
Andrea Scarpino committed
515
516
 *          values: n  - package name
 *                  nd - package name & description
517
 *                  x  - package name (exact match)
Simo Leone's avatar
Simo Leone committed
518
519
520
521
522
523
524
525
526
527
528
529
530
531
 *                  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
532
 *                     do_Delete - Delete (requires confirm_Delete to be set)
533
534
 *                     do_Notify - Enable notification
 *                     do_UnNotify - Disable notification
Simo Leone's avatar
Simo Leone committed
535
 */
536
537
538
539
function pkg_search_page($SID="", $dbh=NULL) {
	if(!$dbh) {
		$dbh = db_connect();
	}
Loui Chang's avatar
Loui Chang committed
540
541
542
543
544

	// get commonly used variables...
	// TODO: REDUCE DB HITS.
	// grab info for user if they're logged in
	if ($SID)
545
		$myuid = uid_from_sid($SID, $dbh);
Loui Chang's avatar
Loui Chang committed
546
	// get a list of package categories
547
	$cats = pkgCategories($dbh); //meow
Loui Chang's avatar
Loui Chang committed
548
549
550
551
552
553
554
555
556
557
558
559
560
561

	// sanitize paging variables
	//
	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"]);
562
563
564
565
		if ($_GET["PP"] < 50)
			$_GET["PP"] = 50;
		else if ($_GET["PP"] > 250)
			$_GET["PP"] = 250;
Loui Chang's avatar
Loui Chang committed
566
567
	}
	else {
568
		$_GET["PP"] = 50;
Loui Chang's avatar
Loui Chang committed
569
570
571
572
573
574
575
576
	}

	// FIXME: pull out DB-related code. all of it.
	//        this one's worth a choco-chip cookie,
	//        one of those nice big soft ones

	// build the package search query
	//
577
	$q_select = "SELECT ";
Loui Chang's avatar
Loui Chang committed
578
	if ($SID) {
579
		$q_select .= "CommentNotify.UserID AS Notify,
580
			   PackageVotes.UsersID AS Voted, ";
Loui Chang's avatar
Loui Chang committed
581
	}
582
	$q_select .= "Users.Username AS Maintainer,
Loui Chang's avatar
Loui Chang committed
583
584
	PackageCategories.Category,
	Packages.Name, Packages.Version, Packages.Description, Packages.NumVotes,
585
	Packages.ID, Packages.OutOfDateTS ";
Loui Chang's avatar
Loui Chang committed
586

587
	$q_from = "FROM Packages
588
589
590
	LEFT JOIN Users ON (Packages.MaintainerUID = Users.ID)
	LEFT JOIN PackageCategories
	ON (Packages.CategoryID = PackageCategories.ID) ";
Loui Chang's avatar
Loui Chang committed
591
	if ($SID) {
592
593
		# this portion is not needed for the total row count query
		$q_from_extra = "LEFT JOIN PackageVotes
Loui Chang's avatar
Loui Chang committed
594
595
596
		ON (Packages.ID = PackageVotes.PackageID AND PackageVotes.UsersID = $myuid)
		LEFT JOIN CommentNotify
		ON (Packages.ID = CommentNotify.PkgID AND CommentNotify.UserID = $myuid) ";
597
598
	} else {
		$q_from_extra = "";
Loui Chang's avatar
Loui Chang committed
599
600
	}

Dan McGee's avatar
Dan McGee committed
601
	$q_where = "WHERE 1 = 1 ";
602
603
	// TODO: possibly do string matching on category
	//       to make request variable values more sensible
604
	if (isset($_GET["C"]) && intval($_GET["C"])) {
605
		$q_where .= "AND Packages.CategoryID = ".intval($_GET["C"])." ";
Loui Chang's avatar
Loui Chang committed
606
607
	}

608
	if (isset($_GET['K'])) {
Loui Chang's avatar
Loui Chang committed
609
		# Search by maintainer
610
		if (isset($_GET["SeB"]) && $_GET["SeB"] == "m") {
canyonknight's avatar
canyonknight committed
611
			$q_where .= "AND Users.Username = " . $dbh->quote($_GET['K']) . " ";
Loui Chang's avatar
Loui Chang committed
612
		}
Andrea Scarpino's avatar
Andrea Scarpino committed
613
		# Search by submitter
614
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "s") {
615
			$q_where .= "AND SubmitterUID = ".uid_from_username($_GET['K'], $dbh)." ";
Loui Chang's avatar
Loui Chang committed
616
		}
617
		# Search by name
618
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "n") {
canyonknight's avatar
canyonknight committed
619
620
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
			$q_where .= "AND (Name LIKE " . $dbh->quote($K) . ") ";
Andrea Scarpino's avatar
Andrea Scarpino committed
621
		}
622
623
		# Search by name (exact match)
		elseif (isset($_GET["SeB"]) && $_GET["SeB"] == "x") {
canyonknight's avatar
canyonknight committed
624
			$q_where .= "AND (Name = " . $dbh->quote($_GET['K']) . ") ";
625
		}
Andrea Scarpino's avatar
Andrea Scarpino committed
626
		# Search by name and description (Default)
Loui Chang's avatar
Loui Chang committed
627
		else {
canyonknight's avatar
canyonknight committed
628
629
630
			$K = "%" . addcslashes($_GET['K'], '%_') . "%";
			$q_where .= "AND (Name LIKE " . $dbh->quote($K) . " OR ";
			$q_where .= "Description LIKE " . $dbh->quote($K) . ") ";
Loui Chang's avatar
Loui Chang committed
631
632
633
		}
	}

634
	if (isset($_GET["do_Orphans"])) {
635
		$q_where .= "AND MaintainerUID IS NULL ";
Loui Chang's avatar
Loui Chang committed
636
	}
637

638
	if (isset($_GET['outdated'])) {
639
		if ($_GET['outdated'] == 'on') {
640
			$q_where .= "AND OutOfDateTS IS NOT NULL ";
641
642
		}
		elseif ($_GET['outdated'] == 'off') {
643
			$q_where .= "AND OutOfDateTS IS NULL ";
644
		}
645
646
	}

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

649
	$q_sort = "ORDER BY Name ".$order." ";
650
651
	$sort_by = isset($_GET["SB"]) ? $_GET["SB"] : '';
	switch ($sort_by) {
Loui Chang's avatar
Loui Chang committed
652
	case 'c':
653
		$q_sort = "ORDER BY CategoryID ".$order.", Name ASC ";
Loui Chang's avatar
Loui Chang committed
654
655
		break;
	case 'v':
656
		$q_sort = "ORDER BY NumVotes ".$order.", Name ASC ";
Loui Chang's avatar
Loui Chang committed
657
		break;
658
659
	case 'w':
		if ($SID) {
660
			$q_sort = "ORDER BY Voted ".$order.", Name ASC ";
661
662
663
664
		}
		break;
	case 'o':
		if ($SID) {
665
			$q_sort = "ORDER BY Notify ".$order.", Name ASC ";
666
667
		}
		break;
Loui Chang's avatar
Loui Chang committed
668
	case 'm':
669
		$q_sort = "ORDER BY Maintainer ".$order.", Name ASC ";
Loui Chang's avatar
Loui Chang committed
670
671
		break;
	case 'a':
672
		$q_sort = "ORDER BY ModifiedTS ".$order.", Name ASC ";
Loui Chang's avatar
Loui Chang committed
673
674
675
676
677
		break;
	default:
		break;
	}

678
	$q_limit = "LIMIT ".$_GET["PP"]." OFFSET ".$_GET["O"];
679

680
681
	$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
682

canyonknight's avatar
canyonknight committed
683
684
	$result = $dbh->query($q);
	$result_t = $dbh->query($q_total);
685
	if ($result_t) {
canyonknight's avatar
canyonknight committed
686
687
		$row = $result_t->fetch(PDO::FETCH_NUM);
		$total = $row[0];
688
689
690
691
	}
	else {
		$total = 0;
	}
Simo Leone's avatar
Simo Leone committed
692

693
	if ($result && $total > 0) {
694
695
		if (isset($_GET["SO"]) && $_GET["SO"] == "d"){
			$SO_next = "a";
Loui Chang's avatar
Loui Chang committed
696
697
		}
		else {
698
			$SO_next = "d";
Loui Chang's avatar
Loui Chang committed
699
		}
700
	}
Simo Leone's avatar
Simo Leone committed
701

702
	// figure out the results to use
Loui Chang's avatar
Loui Chang committed
703
	$first = $_GET['O'] + 1;
Simo Leone's avatar
Simo Leone committed
704

705
706
707
708
709
	# calculation of pagination links
	$per_page = ($_GET['PP'] > 0) ? $_GET['PP'] : 50;
	$current = ceil($first / $per_page);
	$pages = ceil($total / $per_page);
	$templ_pages = array();
710

711
	if ($current > 1) {
712
713
		$templ_pages['&laquo; ' . __('First')] = 0;
		$templ_pages['&lsaquo; ' . __('Previous')] = ($current - 2) * $per_page;
714
	}
715

716
717
	if ($current - 5 > 1)
		$templ_pages["..."] = false;
718

719
720
721
	for ($i = max($current - 5, 1); $i <= min($pages, $current + 5); $i++) {
		$templ_pages[$i] = ($i - 1) * $per_page;
	}
722

723
724
	if ($current + 5 < $pages)
		$templ_pages["... "] = false;
725

726
	if ($current < $pages) {
727
728
		$templ_pages[__('Next') . ' &rsaquo;'] = $current * $per_page;
		$templ_pages[__('Last') . ' &raquo;'] = ($pages - 1) * $per_page;
729
	}
Simo Leone's avatar
Simo Leone committed
730

731
	include('pkg_search_form.php');
732

canyonknight's avatar
canyonknight committed
733
734
735
736
	if ($result) {
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
			$searchresults[] = $row;
		}
737
738
	}

739
740
	include('pkg_search_results.php');

Loui Chang's avatar
Loui Chang committed
741
	return;
eric's avatar
eric committed
742
743
}

744
745
746
747
748
749
750
/**
 * 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
751
752
753
754
755
function current_action($action) {
	return (isset($_POST['action']) && $_POST['action'] == $action) ||
		isset($_POST[$action]);
}

756
/**
757
758
759
760
761
 * Determine if sent IDs are valid integers
 *
 * @param array $ids IDs to validate
 *
 * @return array All sent IDs that are valid integers
762
763
764
765
766
767
768
769
770
771
772
773
 */
function sanitize_ids($ids) {
	$new_ids = array();
	foreach ($ids as $id) {
		$id = intval($id);
		if ($id > 0) {
			$new_ids[] = $id;
		}
	}
	return $new_ids;
}

774
/**
775
 * Flag package(s) as out-of-date
776
 *
777
 * @global string $AUR_LOCATION The AUR's URL used for notification e-mails
778
 * @param string $atype Account type, output of account_from_sid
779
 * @param array $ids Array of package IDs to flag/unflag
780
781
782
 *
 * @return string Translated success or error messages
 */
783
function pkg_flag($atype, $ids, $dbh=NULL) {
Dan McGee's avatar
Dan McGee committed
784
785
	global $AUR_LOCATION;

786
	if (!$atype) {
787
		return __("You must be logged in before you can flag packages.");
788
789
	}

790
	$ids = sanitize_ids($ids);
791
	if (empty($ids)) {
792
		return __("You did not select any packages to flag.");
793
794
	}

795
796
797
	if(!$dbh) {
		$dbh = db_connect();
	}
798

799
	$q = "UPDATE Packages SET";
800
	$q.= " OutOfDateTS = UNIX_TIMESTAMP()";
801
	$q.= " WHERE ID IN (" . implode(",", $ids) . ")";
802
	$q.= " AND OutOfDateTS IS NULL";
803
804
805

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

806
	if ($affected_pkgs > 0) {
807
		# Notify of flagging by email
808
809
810
		$f_name = username_from_sid($_COOKIE['AURSID'], $dbh);
		$f_email = email_from_sid($_COOKIE['AURSID'], $dbh);
		$f_uid = uid_from_sid($_COOKIE['AURSID'], $dbh);
811
812
		$q = "SELECT Packages.Name, Users.Email, Packages.ID ";
		$q.= "FROM Packages, Users ";
813
		$q.= "WHERE Packages.ID IN (" . implode(",", $ids) .") ";
814
815
		$q.= "AND Users.ID = Packages.MaintainerUID ";
		$q.= "AND Users.ID != " . $f_uid;
canyonknight's avatar
canyonknight committed
816
817
818
		$result = $dbh->query($q);
		if ($result) {
			while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
819
				# construct email
820
				$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);
821
				$body = wordwrap($body, 70);
822
823
				$headers = "Reply-to: nobody@archlinux.org\nFrom:aur-notify@archlinux.org\nX-Mailer: PHP\nX-MimeOLE: Produced By AUR\n";
				@mail($row['Email'], "AUR Out-of-date Notification for ".$row['Name'], $body, $headers);
824
825
826
827
			}
		}
	}

828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
	return __("The selected packages have been flagged out-of-date.");
}

/**
 * Unflag package(s) as out-of-date
 *
 * @param string $atype Account type, output of account_from_sid
 * @param array $ids Array of package IDs to flag/unflag
 *
 * @return string Translated success or error messages
 */
function pkg_unflag($atype, $ids, $dbh=NULL) {
	if (!$atype) {
		return __("You must be logged in before you can unflag packages.");
	}

	$ids = sanitize_ids($ids);
	if (empty($ids)) {
		return __("You did not select any packages to unflag.");
	}

	if(!$dbh) {
		$dbh = db_connect();
	}

	$q = "UPDATE Packages SET ";
	$q.= "OutOfDateTS = NULL ";
	$q.= "WHERE ID IN (" . implode(",", $ids) . ") ";

	if ($atype != "Trusted User" && $atype != "Developer") {
		$q.= "AND MaintainerUID = " . uid_from_sid($_COOKIE["AURSID"], $dbh);
	}

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

	if ($result) {
864
865
866
		return __("The selected packages have been unflagged.");
	}
}
867

868
869
870
871
/**
 * Delete packages
 *
 * @param string $atype Account type, output of account_from_sid
872
 * @param array $ids Array of package IDs to delete
873
 * @param int $mergepkgid Package to merge the deleted ones into
874
875
876
 *
 * @return string Translated error or success message
 */
877
function pkg_delete ($atype, $ids, $mergepkgid, $dbh=NULL) {
878
	if (!$atype) {
879
		return __("You must be logged in before you can delete packages.");
880
881
882
	}

	# If they're a TU or dev, can delete
883
884
	if ($atype != "Trusted User" && $atype != "Developer") {
		return __("You do have permission to delete packages.");
885
886
	}

887
	$ids = sanitize_ids($ids);
888
889
	if (empty($ids)) {
		return __("You did not select any packages to delete.");
890
891
	}

892
893
894
	if(!$dbh) {
		$dbh = db_connect();
	}
895

896
897
898
899
900
901
	if ($mergepkgid) {
		$mergepkgname = pkgname_from_id($mergepkgid, $dbh);
	}

	# Send email notifications
	foreach ($ids as $pkgid) {
canyonknight's avatar
canyonknight committed
902
903
904
905
906
907
		$q = "SELECT CommentNotify.*, Users.Email ";
		$q.= "FROM CommentNotify, Users ";
		$q.= "WHERE Users.ID = CommentNotify.UserID ";
		$q.= "AND CommentNotify.UserID != " . uid_from_sid($_COOKIE['AURSID']) . " ";
		$q.= "AND CommentNotify.PkgID = " . $pkgid;
		$result = $dbh->query($q);
908
909
		$bcc = array();

canyonknight's avatar
canyonknight committed
910
		while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
911
912
913
914
915
916
917
918
919
920
921
			array_push($bcc, $row['Email']);
		}
		if (!empty($bcc)) {
			$pkgname = pkgname_from_id($pkgid);

			# TODO: native language emails for users, based on their prefs
			# 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
			$body = "";
			if ($mergepkgid) {
				$body .= username_from_sid($_COOKIE['AURSID']) . " merged \"".$pkgname."\" into \"$mergepkgname\".\n\n";
922
				$body .= "You will no longer receive notifications about this package, please go to https://aur.archlinux.org" . get_pkg_uri($mergepkgname) . " and click the Notify button if you wish to recieve them again.";
923
924
925
926
927
928
929
			} else {
				$body .= username_from_sid($_COOKIE['AURSID']) . " deleted \"".$pkgname."\".\n\n";
				$body .= "You will no longer receive notifications about this package.";
			}
			$body = wordwrap($body, 70);
			$bcc = implode(', ', $bcc);
			$headers = "Bcc: $bcc\nReply-to: nobody@archlinux.org\nFrom: aur-notify@archlinux.org\nX-Mailer: AUR\n";
930
			@mail('undisclosed-recipients: ;', "AUR Package deleted: " . $pkgname, $body, $headers);
931
932
933
		}
	}

934
935
936
937
938
	if ($mergepkgid) {
		/* Merge comments */
		$q = "UPDATE PackageComments ";
		$q.= "SET PackageID = " . intval($mergepkgid) . " ";
		$q.= "WHERE PackageID IN (" . implode(",", $ids) . ")";
canyonknight's avatar
canyonknight committed
939
		$dbh->exec($q);
940
941
942
943
944
945
946
947
948
949
950

		/* Merge votes */
		foreach ($ids as $pkgid) {
			$q = "UPDATE PackageVotes ";
			$q.= "SET PackageID = " . intval($mergepkgid) . " ";
			$q.= "WHERE PackageID = " . $pkgid . " ";
			$q.= "AND UsersID NOT IN (";
			$q.= "SELECT * FROM (SELECT UsersID ";
			$q.= "FROM PackageVotes ";
			$q.= "WHERE PackageID = " . intval($mergepkgid);
			$q.= ") temp)";
canyonknight's avatar
canyonknight committed
951
			$dbh->exec($q);
952
953
954
955
956
957
		}

		$q = "UPDATE Packages ";
		$q.= "SET NumVotes = (SELECT COUNT(*) FROM PackageVotes ";
		$q.= "WHERE PackageID = " . intval($mergepkgid) . ") ";
		$q.= "WHERE ID = " . intval($mergepkgid);
canyonknight's avatar
canyonknight committed
958
		$dbh->exec($q);
959
960
	}

961
	$q = "DELETE FROM Packages WHERE ID IN (" . implode(",", $ids) . ")";
canyonknight's avatar
canyonknight committed
962
	$result = $dbh->exec($q);
963
964
965

	return __("The selected packages have been deleted.");
}
966

967
968
969
970
/**
 * Adopt or disown packages
 *
 * @param string $atype Account type, output of account_from_sid
971
 * @param array $ids Array of package IDs to adopt/disown
972
 * @param bool $action Adopts if true, disowns if false. Adopts by default
973
974
975
 *
 * @return string Translated error or success message
 */
976
function pkg_adopt ($atype, $ids, $action=true, $dbh=NULL) {
977
978
979
980
981
982
983
984
	if (!$atype) {
		if ($action) {
			return __("You must be logged in before you can adopt packages.");
		} else {
			return __("You must be logged in before you can disown packages.");
		}
	}

985
	$ids = sanitize_ids($ids);
986
987
988
989
990
991
992
993
	if (empty($ids)) {
		if ($action) {
			return __("You did not select any packages to adopt.");
		} else {
			return __("You did not select any packages to disown.");
		}
	}

994
995
996
	if(!$dbh) {
		$dbh = db_connect();
	}
997
998
999
1000

	$field = "MaintainerUID";
	$q = "UPDATE Packages ";

For faster browsing, not all history is shown. View entire blame