BioTorrents.de’s version of Gazelle
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

takemoderate.php 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. <?php
  2. #declare(strict_types=1);
  3. // Are they being tricky blighters?
  4. if (!$_POST['userid'] || !is_number($_POST['userid'])) {
  5. error(404);
  6. } elseif (!check_perms('users_mod')) {
  7. error(403);
  8. }
  9. authorize();
  10. // End checking for moronity
  11. if (!apcu_exists('DBKEY')) {
  12. error('Decrypt database first');
  13. }
  14. $ENV = ENV::go();
  15. $UserID = $_POST['userid'];
  16. $DeleteKeys = false;
  17. // Variables for database input
  18. $Class = (int)$_POST['Class'];
  19. $Username = db_string($_POST['Username']);
  20. $Title = db_string($_POST['Title']);
  21. $AdminComment = db_string($_POST['AdminComment']);
  22. $Donor = isset($_POST['Donor']) ? 1 : 0;
  23. $Artist = isset($_POST['Artist']) ? 1 : 0;
  24. $SecondaryClasses = isset($_POST['secondary_classes']) ? $_POST['secondary_classes'] : [];
  25. foreach ($SecondaryClasses as $i => $Val) {
  26. if (!is_number($Val)) {
  27. unset($SecondaryClasses[$i]);
  28. }
  29. }
  30. $Visible = isset($_POST['Visible']) ? 1 : 0;
  31. $Invites = (int)$_POST['Invites'];
  32. $SupportFor = db_string($_POST['SupportFor']);
  33. $Pass = $_POST['ChangePassword'];
  34. $Warned = isset($_POST['Warned']) ? 1 : 0;
  35. if (isset($_POST['Uploaded']) && isset($_POST['Downloaded'])) {
  36. $Uploaded = ($_POST['Uploaded'] === '' ? 0 : $_POST['Uploaded']);
  37. if ($Arithmetic = strpbrk($Uploaded, '+-')) {
  38. $Uploaded += max(-$Uploaded, Format::get_bytes($Arithmetic));
  39. }
  40. $Downloaded = ($_POST['Downloaded'] === '' ? 0 : $_POST['Downloaded']);
  41. if ($Arithmetic = strpbrk($Downloaded, '+-')) {
  42. $Downloaded += max(-$Downloaded, Format::get_bytes($Arithmetic));
  43. }
  44. if (!is_number($Uploaded) || !is_number($Downloaded)) {
  45. error(0);
  46. }
  47. }
  48. $BonusPoints = isset($_POST['BonusPoints']) ? $_POST['BonusPoints'] : 0;
  49. if (!is_number($BonusPoints)) {
  50. error(0);
  51. }
  52. $FLTokens = isset($_POST['FLTokens']) ? $_POST['FLTokens'] : 0;
  53. if (!is_number($FLTokens)) {
  54. error(0);
  55. }
  56. $Badges = isset($_POST['badges']) ? $_POST['badges'] : [];
  57. $WarnLength = (int)$_POST['WarnLength'];
  58. $ExtendWarning = (int)$_POST['ExtendWarning'];
  59. $ReduceWarning = (int)$_POST['ReduceWarning'];
  60. $WarnReason = $_POST['WarnReason'];
  61. $UserReason = $_POST['UserReason'];
  62. $DisableAvatar = isset($_POST['DisableAvatar']) ? 1 : 0;
  63. $DisableInvites = isset($_POST['DisableInvites']) ? 1 : 0;
  64. $DisablePosting = isset($_POST['DisablePosting']) ? 1 : 0;
  65. $DisableForums = isset($_POST['DisableForums']) ? 1 : 0;
  66. $DisableTagging = isset($_POST['DisableTagging']) ? 1 : 0;
  67. $DisableUpload = isset($_POST['DisableUpload']) ? 1 : 0;
  68. $DisableWiki = isset($_POST['DisableWiki']) ? 1 : 0;
  69. $DisablePM = isset($_POST['DisablePM']) ? 1 : 0;
  70. $DisablePoints = isset($_POST['DisablePoints']) ? 1 : 0;
  71. $DisablePromotion = isset($_POST['DisablePromotion']) ? 1 : 0;
  72. $DisableIRC = isset($_POST['DisableIRC']) ? 1 : 0;
  73. $DisableRequests = isset($_POST['DisableRequests']) ? 1 : 0;
  74. $DisableLeech = isset($_POST['DisableLeech']) ? 0 : 1;
  75. $LockedAccount = isset($_POST['LockAccount']) ? 1 : 0;
  76. $LockType = $_POST['LockReason'];
  77. $RestrictedForums = db_string(trim($_POST['RestrictedForums']));
  78. $PermittedForums = db_string(trim($_POST['PermittedForums']));
  79. $EnableUser = (int) $_POST['UserStatus'];
  80. $ResetRatioWatch = isset($_POST['ResetRatioWatch']) ? 1 : 0;
  81. $ResetPasskey = isset($_POST['ResetPasskey']) ? 1 : 0;
  82. $ResetAuthkey = isset($_POST['ResetAuthkey']) ? 1 : 0;
  83. $SendHackedMail = isset($_POST['SendHackedMail']) ? 1 : 0;
  84. if ($SendHackedMail && !empty($_POST['HackedEmail'])) {
  85. $HackedEmail = $_POST['HackedEmail'];
  86. } else {
  87. $SendHackedMail = false;
  88. }
  89. $MergeStatsFrom = db_string($_POST['MergeStatsFrom']);
  90. $Reason = db_string($_POST['Reason']);
  91. $HeavyUpdates = [];
  92. $LightUpdates = [];
  93. // Get user info from the database
  94. $DB->query("
  95. SELECT
  96. m.Username,
  97. m.IP,
  98. m.Email,
  99. m.PermissionID,
  100. p.Level AS Class,
  101. m.Title,
  102. m.Enabled,
  103. m.Uploaded,
  104. m.Downloaded,
  105. m.Invites,
  106. m.can_leech,
  107. m.Visible,
  108. i.AdminComment,
  109. m.torrent_pass,
  110. i.Donor,
  111. i.Artist,
  112. i.Warned,
  113. i.SupportFor,
  114. i.RestrictedForums,
  115. i.PermittedForums,
  116. DisableAvatar,
  117. DisableInvites,
  118. DisablePosting,
  119. DisableForums,
  120. DisableTagging,
  121. DisableUpload,
  122. DisableWiki,
  123. DisablePM,
  124. DisablePoints,
  125. DisablePromotion,
  126. DisableIRC,
  127. DisableRequests,
  128. m.RequiredRatio,
  129. m.FLTokens,
  130. m.BonusPoints,
  131. i.RatioWatchEnds,
  132. la.Type,
  133. SHA1(i.AdminComment) AS CommentHash,
  134. GROUP_CONCAT(l.PermissionID SEPARATOR ',') AS SecondaryClasses
  135. FROM users_main AS m
  136. JOIN users_info AS i ON i.UserID = m.ID
  137. LEFT JOIN permissions AS p ON p.ID = m.PermissionID
  138. LEFT JOIN users_levels AS l ON l.UserID = m.ID
  139. LEFT JOIN locked_accounts AS la ON la.UserID = m.ID
  140. WHERE m.ID = $UserID
  141. GROUP BY m.ID");
  142. if (!$DB->has_results()) { // If user doesn't exist
  143. header("Location: log.php?search=User+$UserID");
  144. }
  145. $Cur = $DB->next_record(MYSQLI_ASSOC, false);
  146. if ($_POST['comment_hash'] != $Cur['CommentHash']) {
  147. error("Somebody else has moderated this user since you loaded it. Please go back and refresh the page.");
  148. }
  149. // NOW that we know the class of the current user, we can see if one staff member is trying to hax0r us
  150. if (!check_perms('users_mod', $Cur['Class'])) {
  151. // Son of a fucking bitch
  152. error(403);
  153. error();
  154. }
  155. if (!empty($_POST['donor_points_submit']) && !empty($_POST['donation_value']) && is_numeric($_POST['donation_value'])) {
  156. Donations::regular_donate($UserID, $_POST['donation_value'], "Add Points", $_POST['donation_reason'], $_POST['donation_currency']);
  157. } elseif (!empty($_POST['donor_values_submit'])) {
  158. Donations::update_rank($UserID, $_POST['donor_rank'], $_POST['total_donor_rank'], $_POST['reason']);
  159. }
  160. // If we're deleting the user, we can ignore all the other crap
  161. if ($_POST['UserStatus'] === 'delete' && check_perms('users_delete_users')) {
  162. Misc::write_log("User account $UserID (".$Cur['Username'].") was deleted by ".$LoggedUser['Username']);
  163. $DB->query("
  164. DELETE FROM users_main
  165. WHERE id = $UserID");
  166. $DB->query("
  167. DELETE FROM users_info
  168. WHERE UserID = $UserID");
  169. $Cache->delete_value("user_info_$UserID");
  170. Tracker::update_tracker('remove_user', array('passkey' => $Cur['torrent_pass']));
  171. header("Location: log.php?search=User+$UserID");
  172. error();
  173. }
  174. // User was not deleted. Perform other stuff.
  175. $UpdateSet = [];
  176. $EditSummary = [];
  177. $TrackerUserUpdates = array('passkey' => $Cur['torrent_pass']);
  178. $QueryID = G::$DB->get_query_id();
  179. if ($LockType == '---' || $LockedAccount == 0) {
  180. if ($Cur['Type']) {
  181. $DB->query("DELETE FROM locked_accounts WHERE UserID = '" . $UserID . "'");
  182. $EditSummary[] = 'Account unlocked';
  183. $Cache->delete_value('user_' . $Cur['torrent_pass']);
  184. }
  185. } elseif (!$Cur['Type'] || $Cur['Type'] != $LockType) {
  186. $DB->query("INSERT INTO locked_accounts (UserID, Type)
  187. VALUES ('" . $UserID . "', '" . $LockType . "')
  188. ON DUPLICATE KEY UPDATE Type = '" . $LockType . "'");
  189. $Cache->delete_value('user_' . $Cur['torrent_pass']);
  190. if ($Cur['Type'] != $LockType) {
  191. $EditSummary[] = 'Account lock reason changed to ' . $LockType;
  192. } else {
  193. $EditSummary[] = 'Account locked (' . $LockType . ')';
  194. }
  195. }
  196. $Cache->delete_value("user_info_" . $UserID);
  197. $DB->set_query_id($QueryID);
  198. if ($_POST['ResetRatioWatch'] && check_perms('users_edit_reset_keys')) {
  199. $DB->query("
  200. UPDATE users_info
  201. SET RatioWatchEnds = NULL, RatioWatchDownload = '0', RatioWatchTimes = '0'
  202. WHERE UserID = '$UserID'");
  203. $EditSummary[] = 'RatioWatch history reset';
  204. }
  205. if ($_POST['ResetSnatchList'] && check_perms('users_edit_reset_keys')) {
  206. $DB->query("
  207. DELETE FROM xbt_snatched
  208. WHERE uid = '$UserID'");
  209. $EditSummary[] = 'Snatch list cleared';
  210. $Cache->delete_value("recent_snatches_$UserID");
  211. }
  212. if ($_POST['ResetDownloadList'] && check_perms('users_edit_reset_keys')) {
  213. $DB->query("
  214. DELETE FROM users_downloads
  215. WHERE UserID = '$UserID'");
  216. $EditSummary[] = 'Download list cleared';
  217. }
  218. if (($_POST['ResetSession'] || $_POST['LogOut']) && check_perms('users_logout')) {
  219. $Cache->delete_value("user_info_$UserID");
  220. $Cache->delete_value("user_info_heavy_$UserID");
  221. $Cache->delete_value("user_stats_$UserID");
  222. $Cache->delete_value("enabled_$UserID");
  223. if ($_POST['LogOut']) {
  224. $DB->query("
  225. SELECT SessionID
  226. FROM users_sessions
  227. WHERE UserID = '$UserID'");
  228. while (list($SessionID) = $DB->next_record()) {
  229. $Cache->delete_value("session_{$UserID}_$SessionID");
  230. }
  231. $Cache->delete_value("users_sessions_$UserID");
  232. $DB->query("
  233. DELETE FROM users_sessions
  234. WHERE UserID = '$UserID'");
  235. }
  236. }
  237. // Start building SQL query and edit summary
  238. if ($Classes[$Class]['Level'] != $Cur['Class']
  239. && (
  240. ($Classes[$Class]['Level'] < $LoggedUser['Class'] && check_perms('users_promote_below', $Cur['Class']))
  241. || ($Classes[$Class]['Level'] <= $LoggedUser['Class'] && check_perms('users_promote_to', $Cur['Class'] - 1))
  242. )
  243. ) {
  244. $UpdateSet[] = "PermissionID = '$Class'";
  245. $EditSummary[] = 'class changed to '.Users::make_class_string($Class);
  246. $LightUpdates['PermissionID'] = $Class;
  247. $DeleteKeys = true;
  248. $DB->query("
  249. SELECT DISTINCT DisplayStaff
  250. FROM permissions
  251. WHERE ID = $Class
  252. OR ID = ".$ClassLevels[$Cur['Class']]['ID']);
  253. if ($DB->record_count() === 2) {
  254. if ($Classes[$Class]['Level'] < $Cur['Class']) {
  255. $SupportFor = '';
  256. }
  257. $ClearStaffIDCache = true;
  258. }
  259. $Cache->delete_value("donor_info_$UserID");
  260. }
  261. if ($Username != $Cur['Username'] && check_perms('users_edit_usernames', $Cur['Class'] - 1)) {
  262. $DB->query("
  263. SELECT ID
  264. FROM users_main
  265. WHERE Username = '$Username'");
  266. if ($DB->next_record() > 0) {
  267. list($UsedUsernameID) = $DB->next_record();
  268. error("Username already in use by <a href=\"user.php?id=$UsedUsernameID\">$Username</a>");
  269. header("Location: user.php?id=$UserID");
  270. error();
  271. } elseif ($Username == '0' || $Username == '1') {
  272. error('You cannot set a username of "0" or "1".');
  273. header("Location: user.php?id=$UserID");
  274. error();
  275. } else {
  276. $UpdateSet[] = "Username = '$Username'";
  277. $EditSummary[] = "username changed from ".$Cur['Username']." to $Username";
  278. $LightUpdates['Username'] = $Username;
  279. }
  280. }
  281. if ($Title != db_string($Cur['Title']) && check_perms('users_edit_titles')) {
  282. // Using the unescaped value for the test to avoid confusion
  283. if (strlen($_POST['Title']) > 1024) {
  284. error("Custom titles have a maximum length of 1,024 characters.");
  285. header("Location: user.php?id=$UserID");
  286. error();
  287. } else {
  288. $UpdateSet[] = "Title = '$Title'";
  289. $EditSummary[] = "title changed to [code]{$Title}[/code]";
  290. $LightUpdates['Title'] = $_POST['Title'];
  291. }
  292. }
  293. if ($Donor != $Cur['Donor'] && check_perms('users_give_donor')) {
  294. $UpdateSet[] = "Donor = '$Donor'";
  295. $EditSummary[] = 'donor status changed';
  296. $LightUpdates['Donor'] = $Donor;
  297. }
  298. // Secondary classes
  299. $OldClasses = $Cur['SecondaryClasses'] ? explode(',', $Cur['SecondaryClasses']) : [];
  300. $DroppedClasses = array_diff($OldClasses, $SecondaryClasses);
  301. $AddedClasses = array_diff($SecondaryClasses, $OldClasses);
  302. if (count($DroppedClasses) > 0) {
  303. $ClassChanges = [];
  304. foreach ($DroppedClasses as $PermID) {
  305. $ClassChanges[] = $Classes[$PermID]['Name'];
  306. }
  307. $EditSummary[] = 'Secondary classes dropped: '.implode(', ', $ClassChanges);
  308. $DB->query("
  309. DELETE FROM users_levels
  310. WHERE UserID = '$UserID'
  311. AND PermissionID IN (".implode(',', $DroppedClasses).')');
  312. if (count($SecondaryClasses) > 0) {
  313. $LightUpdates['ExtraClasses'] = array_fill_keys($SecondaryClasses, 1);
  314. } else {
  315. $LightUpdates['ExtraClasses'] = [];
  316. }
  317. $DeleteKeys = true;
  318. }
  319. if (count($AddedClasses) > 0) {
  320. $ClassChanges = [];
  321. foreach ($AddedClasses as $PermID) {
  322. $ClassChanges[] = $Classes[$PermID]['Name'];
  323. }
  324. $EditSummary[] = "Secondary classes added: ".implode(', ', $ClassChanges);
  325. $Values = [];
  326. foreach ($AddedClasses as $PermID) {
  327. $Values[] = "($UserID, $PermID)";
  328. }
  329. $DB->query("
  330. INSERT INTO users_levels (UserID, PermissionID)
  331. VALUES ".implode(', ', $Values));
  332. //$LightUpdates['ExtraClasses'] = array_fill_keys($SecondaryClasses, 1);
  333. $DeleteKeys = true;
  334. }
  335. if ($Visible != $Cur['Visible'] && check_perms('users_make_invisible')) {
  336. $UpdateSet[] = "Visible = '$Visible'";
  337. $EditSummary[] = 'visibility changed';
  338. $LightUpdates['Visible'] = $Visible;
  339. $TrackerUserUpdates['visible'] = $Visible;
  340. }
  341. if ($Uploaded != $Cur['Uploaded'] && $Uploaded != $_POST['OldUploaded'] && (check_perms('users_edit_ratio')
  342. || (check_perms('users_edit_own_ratio') && $UserID == $LoggedUser['ID']))) {
  343. $UpdateSet[] = "Uploaded = '$Uploaded'";
  344. $EditSummary[] = "uploaded changed from ".Format::get_size($Cur['Uploaded']).' to '.Format::get_size($Uploaded);
  345. $Cache->delete_value("user_stats_$UserID");
  346. }
  347. if ($Downloaded != $Cur['Downloaded'] && $Downloaded != $_POST['OldDownloaded'] && (check_perms('users_edit_ratio')
  348. || (check_perms('users_edit_own_ratio') && $UserID == $LoggedUser['ID']))) {
  349. $UpdateSet[] = "Downloaded = '$Downloaded'";
  350. $EditSummary[] = "downloaded changed from ".Format::get_size($Cur['Downloaded']).' to '.Format::get_size($Downloaded);
  351. $Cache->delete_value("user_stats_$UserID");
  352. }
  353. if ($BonusPoints != $Cur['BonusPoints'] && (check_perms('users_edit_ratio') || (check_perms('users_edit_own_ratio') && $UserID == $LoggedUser['ID']))) {
  354. $UpdateSet[] = "BonusPoints = $BonusPoints";
  355. $EditSummary[] = "Bonus Points changed from ".$Cur['BonusPoints']." to $BonusPoints";
  356. $HeavyUpdates['BonusPoints'] = $BonusPoints;
  357. }
  358. if ($FLTokens != $Cur['FLTokens'] && (check_perms('users_edit_ratio') || (check_perms('users_edit_own_ratio') && $UserID == $LoggedUser['ID']))) {
  359. $UpdateSet[] = "FLTokens = $FLTokens";
  360. $EditSummary[] = "Freeleech Tokens changed from ".$Cur['FLTokens']." to $FLTokens";
  361. $HeavyUpdates['FLTokens'] = $FLTokens;
  362. }
  363. if ($Invites != $Cur['Invites'] && check_perms('users_edit_invites')) {
  364. $UpdateSet[] = "invites = '$Invites'";
  365. $EditSummary[] = "number of invites changed to $Invites";
  366. $HeavyUpdates['Invites'] = $Invites;
  367. }
  368. if (check_perms('users_edit_badges')) {
  369. $query = "DELETE FROM users_badges WHERE UserID = $UserID";
  370. if (!empty($Badges)) {
  371. $query .= " AND BadgeID NOT IN (".implode(',', $Badges).")";
  372. }
  373. $DB->query($query);
  374. if (!empty($Badges)) {
  375. $query = "INSERT IGNORE INTO users_badges (UserID, BadgeID) VALUES ";
  376. $len = count($Badges);
  377. foreach ($Badges as $i => $BadgeID) {
  378. $query .= "($UserID, $BadgeID)";
  379. if ($i < ($len-1)) {
  380. $query .= ", ";
  381. }
  382. }
  383. $DB->query($query);
  384. }
  385. $Cache->delete_value("user_badges_".$UserID);
  386. }
  387. if ($Warned == 1 && !$Cur['Warned'] && check_perms('users_warn')) {
  388. $Weeks = 'week' . ($WarnLength === 1 ? '' : 's');
  389. Misc::send_pm($UserID, 0, 'You have received a warning', "You have been [url=".site_url()."wiki.php?action=article&amp;name=warnings]warned for $WarnLength {$Weeks}[/url] by [user]".$LoggedUser['Username']."[/user]. The reason given was:
  390. [quote]{$WarnReason}[/quote]");
  391. $UpdateSet[] = "Warned = NOW() + INTERVAL $WarnLength WEEK";
  392. $Msg = "warned for $WarnLength $Weeks";
  393. if ($WarnReason) {
  394. $Msg .= " for \"$WarnReason\"";
  395. }
  396. $EditSummary[] = db_string($Msg);
  397. $LightUpdates['Warned'] = time_plus(3600 * 24 * 7 * $WarnLength);
  398. } elseif ($Warned == 0 && $Cur['Warned'] && check_perms('users_warn')) {
  399. $UpdateSet[] = "Warned = NULL";
  400. $EditSummary[] = 'warning removed';
  401. $LightUpdates['Warned'] = null;
  402. } elseif ($Warned == 1 && $ExtendWarning != '---' && check_perms('users_warn')) {
  403. $Weeks = 'week' . ($ExtendWarning === 1 ? '' : 's');
  404. Misc::send_pm($UserID, 0, 'Your warning has been extended', "Your warning has been extended by $ExtendWarning $Weeks by [user]".$LoggedUser['Username']."[/user]. The reason given was:
  405. [quote]{$WarnReason}[/quote]");
  406. $UpdateSet[] = "Warned = Warned + INTERVAL $ExtendWarning WEEK";
  407. $DB->query("
  408. SELECT Warned + INTERVAL $ExtendWarning WEEK
  409. FROM users_info
  410. WHERE UserID = '$UserID'");
  411. list($WarnedUntil) = $DB->next_record();
  412. $Msg = "warning extended by $ExtendWarning $Weeks to $WarnedUntil";
  413. if ($WarnReason) {
  414. $Msg .= " for \"$WarnReason\"";
  415. }
  416. $EditSummary[] = db_string($Msg);
  417. $LightUpdates['Warned'] = $WarnedUntil;
  418. } elseif ($Warned == 1 && $ExtendWarning == '---' && $ReduceWarning != '---' && check_perms('users_warn')) {
  419. $Weeks = 'week' . ($ReduceWarning === 1 ? '' : 's');
  420. Misc::send_pm($UserID, 0, 'Your warning has been reduced', "Your warning has been reduced by $ReduceWarning $Weeks by [user]".$LoggedUser['Username']."[/user]. The reason given was:
  421. [quote]{$WarnReason}[/quote]");
  422. $UpdateSet[] = "Warned = Warned - INTERVAL $ReduceWarning WEEK";
  423. $DB->query("
  424. SELECT Warned - INTERVAL $ReduceWarning WEEK
  425. FROM users_info
  426. WHERE UserID = '$UserID'");
  427. list($WarnedUntil) = $DB->next_record();
  428. $Msg = "warning reduced by $ReduceWarning $Weeks to $WarnedUntil";
  429. if ($WarnReason) {
  430. $Msg .= " for \"$WarnReason\"";
  431. }
  432. $EditSummary[] = db_string($Msg);
  433. $LightUpdates['Warned'] = $WarnedUntil;
  434. }
  435. if ($SupportFor != db_string($Cur['SupportFor']) && (check_perms('admin_manage_fls') || (check_perms('users_mod') && $UserID == $LoggedUser['ID']))) {
  436. $UpdateSet[] = "SupportFor = '$SupportFor'";
  437. $EditSummary[] = "First-Line Support status changed to \"$SupportFor\"";
  438. }
  439. if ($RestrictedForums != db_string($Cur['RestrictedForums']) && check_perms('users_mod')) {
  440. $UpdateSet[] = "RestrictedForums = '$RestrictedForums'";
  441. $EditSummary[] = "restricted forum(s): $RestrictedForums";
  442. $DeleteKeys = true;
  443. }
  444. if ($PermittedForums != db_string($Cur['PermittedForums']) && check_perms('users_mod')) {
  445. $ForumSet = explode(',', $PermittedForums);
  446. $ForumList = [];
  447. foreach ($ForumSet as $ForumID) {
  448. if ($Forums[$ForumID]['MinClassCreate'] <= $LoggedUser['EffectiveClass']) {
  449. $ForumList[] = $ForumID;
  450. }
  451. }
  452. $PermittedForums = implode(',', $ForumSet);
  453. $UpdateSet[] = "PermittedForums = '$PermittedForums'";
  454. $EditSummary[] = "permitted forum(s): $PermittedForums";
  455. $DeleteKeys = true;
  456. }
  457. if ($DisableAvatar != $Cur['DisableAvatar'] && check_perms('users_disable_any')) {
  458. $UpdateSet[] = "DisableAvatar = '$DisableAvatar'";
  459. $EditSummary[] = 'avatar privileges ' . ($DisableAvatar ? 'disabled' : 'enabled');
  460. $HeavyUpdates['DisableAvatar'] = $DisableAvatar;
  461. if (!empty($UserReason)) {
  462. Misc::send_pm($UserID, 0, 'Your avatar privileges have been disabled', "Your avatar privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  463. }
  464. }
  465. if ($DisableLeech != $Cur['can_leech'] && check_perms('users_disable_any')) {
  466. $UpdateSet[] = "can_leech = '$DisableLeech'";
  467. $EditSummary[] = "leeching status changed (".translateLeechStatus($Cur['can_leech'])." -> ".translateLeechStatus($DisableLeech).")";
  468. $HeavyUpdates['DisableLeech'] = $DisableLeech;
  469. $HeavyUpdates['CanLeech'] = $DisableLeech;
  470. if (!empty($UserReason)) {
  471. Misc::send_pm($UserID, 0, 'Your leeching privileges have been disabled', "Your leeching privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  472. }
  473. $TrackerUserUpdates['can_leech'] = $DisableLeech;
  474. }
  475. if ($DisableInvites != $Cur['DisableInvites'] && check_perms('users_disable_any')) {
  476. $UpdateSet[] = "DisableInvites = '$DisableInvites'";
  477. if ($DisableInvites == 1) {
  478. //$UpdateSet[] = "Invites = '0'";
  479. if (!empty($UserReason)) {
  480. Misc::send_pm($UserID, 0, 'Your invite privileges have been disabled', "Your invite privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  481. }
  482. }
  483. $EditSummary[] = 'invites privileges ' . ($DisableInvites ? 'disabled' : 'enabled');
  484. $HeavyUpdates['DisableInvites'] = $DisableInvites;
  485. }
  486. if ($DisablePosting != $Cur['DisablePosting'] && check_perms('users_disable_posts')) {
  487. $UpdateSet[] = "DisablePosting = '$DisablePosting'";
  488. $EditSummary[] = 'posting privileges ' . ($DisablePosting ? 'disabled' : 'enabled');
  489. $HeavyUpdates['DisablePosting'] = $DisablePosting;
  490. if (!empty($UserReason)) {
  491. Misc::send_pm($UserID, 0, 'Your forum posting privileges have been disabled', "Your forum posting privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  492. }
  493. }
  494. if ($DisableForums != $Cur['DisableForums'] && check_perms('users_disable_posts')) {
  495. $UpdateSet[] = "DisableForums = '$DisableForums'";
  496. $EditSummary[] = 'forums privileges ' . ($DisableForums ? 'disabled' : 'enabled');
  497. $HeavyUpdates['DisableForums'] = $DisableForums;
  498. if (!empty($UserReason)) {
  499. Misc::send_pm($UserID, 0, 'Your forum privileges have been disabled', "Your forum privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  500. }
  501. }
  502. if ($DisableTagging != $Cur['DisableTagging'] && check_perms('users_disable_any')) {
  503. $UpdateSet[] = "DisableTagging = '$DisableTagging'";
  504. $EditSummary[] = 'tagging privileges ' . ($DisableTagging ? 'disabled' : 'enabled');
  505. $HeavyUpdates['DisableTagging'] = $DisableTagging;
  506. if (!empty($UserReason)) {
  507. Misc::send_pm($UserID, 0, 'Your tagging privileges have been disabled', "Your tagging privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  508. }
  509. }
  510. if ($DisableUpload != $Cur['DisableUpload'] && check_perms('users_disable_any')) {
  511. $UpdateSet[] = "DisableUpload = '$DisableUpload'";
  512. $EditSummary[] = 'upload privileges ' . ($DisableUpload ? 'disabled' : 'enabled');
  513. $HeavyUpdates['DisableUpload'] = $DisableUpload;
  514. if ($DisableUpload == 1) {
  515. Misc::send_pm($UserID, 0, 'Your upload privileges have been disabled', "Your upload privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  516. }
  517. }
  518. if ($DisableWiki != $Cur['DisableWiki'] && check_perms('users_disable_any')) {
  519. $UpdateSet[] = "DisableWiki = '$DisableWiki'";
  520. $EditSummary[] = 'wiki privileges ' . ($DisableWiki ? 'disabled' : 'enabled');
  521. $HeavyUpdates['DisableWiki'] = $DisableWiki;
  522. $HeavyUpdates['site_edit_wiki'] = 0;
  523. if (!empty($UserReason)) {
  524. Misc::send_pm($UserID, 0, 'Your site editing privileges have been disabled', "Your site editing privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  525. }
  526. }
  527. if ($DisablePM != $Cur['DisablePM'] && check_perms('users_disable_any')) {
  528. $UpdateSet[] = "DisablePM = '$DisablePM'";
  529. $EditSummary[] = 'PM privileges ' . ($DisablePM ? 'disabled' : 'enabled');
  530. $HeavyUpdates['DisablePM'] = $DisablePM;
  531. if (!empty($UserReason)) {
  532. Misc::send_pm($UserID, 0, 'Your PM privileges have been disabled', "Your PM privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  533. }
  534. }
  535. if ($DisablePoints != $Cur['DisablePoints'] && check_perms('users_disable_any')) {
  536. $UpdateSet[] = "DisablePoints = '$DisablePoints'";
  537. $EditSummary[] = BONUS_POINTS.' earning ' . ($DisablePoints ? 'disabled' : 'enabled');
  538. $HeavyUpdates['DisablePoints'] = $DisablePoints;
  539. if (!empty($UserReason)) {
  540. Misc::send_pm($UserID, 0, 'Your '.BONUS_POINTS.'-earning ability has been disabled', "Your ".BONUS_POINTS."-earning ability has been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  541. }
  542. }
  543. if ($DisablePromotion != $Cur['DisablePromotion'] && check_perms('users_disable_any')) {
  544. $UpdateSet[] = "DisablePromotion = '$DisablePromotion'";
  545. $EditSummary[] = 'Class purchasing ' . ($DisablePromotion ? 'disabled' : 'enabled');
  546. $HeavyUpdates['DisablePromotion'] = $DisablePromotion;
  547. if (!empty($UserReason)) {
  548. Misc::send_pm($UserID, 0, 'Your promotion purchasing ability has been disabled', "Your promotion purchasing ability has been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  549. }
  550. }
  551. if ($DisableIRC != $Cur['DisableIRC'] && check_perms('users_disable_any')) {
  552. $UpdateSet[] = "DisableIRC = '$DisableIRC'";
  553. $EditSummary[] = 'IRC privileges ' . ($DisableIRC ? 'disabled' : 'enabled');
  554. $HeavyUpdates['DisableIRC'] = $DisableIRC;
  555. if (!empty($UserReason)) {
  556. Misc::send_pm($UserID, 0, 'Your IRC privileges have been disabled', "Your IRC privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url]. This loss of privileges does not affect the ability to join and talk to staff in '.DISABLED_CHAN.'.');
  557. }
  558. }
  559. if ($DisableRequests != $Cur['DisableRequests'] && check_perms('users_disable_any')) {
  560. $UpdateSet[] = "DisableRequests = '$DisableRequests'";
  561. $EditSummary[] = 'request privileges ' . ($DisableRequests ? 'disabled' : 'enabled');
  562. $HeavyUpdates['DisableRequests'] = $DisableRequests;
  563. if (!empty($UserReason)) {
  564. Misc::send_pm($UserID, 0, 'Your request privileges have been disabled', "Your request privileges have been disabled. The reason given was: [quote]{$UserReason}[/quote] If you would like to discuss this, please join ".DISABLED_CHAN.' on our IRC network. Instructions can be found [url='.site_url().'wiki.php?action=article&amp;name=IRC+-+How+to+join]here[/url].');
  565. }
  566. }
  567. if ($EnableUser != $Cur['Enabled'] && check_perms('users_disable_users')) {
  568. $EnableStr = 'account '.translateUserStatus($Cur['Enabled']).'->'.translateUserStatus($EnableUser);
  569. if ($EnableUser == '2') {
  570. Tools::disable_users($UserID, '', 1);
  571. $TrackerUserUpdates = [];
  572. } elseif ($EnableUser == '1') {
  573. $Cache->increment('stats_user_count');
  574. $VisibleTrIP = ($Visible && Crypto::decrypt($Cur['IP']) != '127.0.0.1') ? '1' : '0';
  575. Tracker::update_tracker('add_user', array('id' => $UserID, 'passkey' => $Cur['torrent_pass'], 'visible' => $VisibleTrIP));
  576. if (($Cur['Downloaded'] == 0) || ($Cur['Uploaded'] / $Cur['Downloaded'] >= $Cur['RequiredRatio'])) {
  577. $UpdateSet[] = "i.RatioWatchEnds = NULL";
  578. $CanLeech = 1;
  579. $UpdateSet[] = "m.can_leech = '1'";
  580. $UpdateSet[] = "i.RatioWatchDownload = '0'";
  581. } else {
  582. $EnableStr .= ' (Ratio: '.Format::get_ratio_html($Cur['Uploaded'], $Cur['Downloaded'], false).', RR: '.number_format($Cur['RequiredRatio'], 2).')';
  583. if ($Cur['RatioWatchEnds']) {
  584. $UpdateSet[] = "i.RatioWatchEnds = NOW()";
  585. $UpdateSet[] = "i.RatioWatchDownload = m.Downloaded";
  586. $CanLeech = 0;
  587. }
  588. $TrackerUserUpdates['can_leech'] = 0;
  589. }
  590. $UpdateSet[] = "i.BanReason = '0'";
  591. $UpdateSet[] = "Enabled = '1'";
  592. $LightUpdates['Enabled'] = 1;
  593. }
  594. $EditSummary[] = $EnableStr;
  595. $Cache->replace_value("enabled_$UserID", $EnableUser, 0);
  596. }
  597. if ($ResetPasskey == 1 && check_perms('users_edit_reset_keys')) {
  598. $Passkey = db_string(Users::make_secret());
  599. $UpdateSet[] = "torrent_pass = '$Passkey'";
  600. $EditSummary[] = 'passkey reset';
  601. $HeavyUpdates['torrent_pass'] = $Passkey;
  602. $TrackerUserUpdates['passkey'] = $Passkey;
  603. $Cache->delete_value('user_'.$Cur['torrent_pass']);
  604. // MUST come after the case for updating can_leech
  605. Tracker::update_tracker('change_passkey', array('oldpasskey' => $Cur['torrent_pass'], 'newpasskey' => $Passkey));
  606. }
  607. if ($ResetAuthkey == 1 && check_perms('users_edit_reset_keys')) {
  608. $Authkey = db_string(Users::make_secret());
  609. $UpdateSet[] = "AuthKey = '$Authkey'";
  610. $EditSummary[] = 'authkey reset';
  611. $HeavyUpdates['AuthKey'] = $Authkey;
  612. }
  613. if ($SendHackedMail && check_perms('users_disable_any')) {
  614. $EditSummary[] = "hacked account email sent to $HackedEmail";
  615. Misc::send_email($HackedEmail, "Your $ENV->SITE_NAME account", "Your $ENV->SITE_NAME account appears to have been compromised. As a security measure, we have disabled your account. To resolve this, please visit us on Slack.");
  616. }
  617. if ($MergeStatsFrom && check_perms('users_edit_ratio')) {
  618. $DB->query("
  619. SELECT ID, Uploaded, Downloaded
  620. FROM users_main
  621. WHERE Username LIKE '$MergeStatsFrom'");
  622. if ($DB->has_results()) {
  623. list($MergeID, $MergeUploaded, $MergeDownloaded) = $DB->next_record();
  624. $DB->query("
  625. UPDATE users_main AS um
  626. JOIN users_info AS ui ON um.ID = ui.UserID
  627. SET
  628. um.Uploaded = 0,
  629. um.Downloaded = 0,
  630. ui.AdminComment = CONCAT('".sqltime().' - Stats (Uploaded: '.Format::get_size($MergeUploaded).', Downloaded: '.Format::get_size($MergeDownloaded).', Ratio: '.Format::get_ratio($MergeUploaded, $MergeDownloaded).') merged into '.site_url()."user.php?id=$UserID (".$Cur['Username'].') by '.$LoggedUser['Username']."\n\n', ui.AdminComment)
  631. WHERE ID = $MergeID");
  632. $UpdateSet[] = "Uploaded = Uploaded + '$MergeUploaded'";
  633. $UpdateSet[] = "Downloaded = Downloaded + '$MergeDownloaded'";
  634. $EditSummary[] = 'stats merged from '.site_url()."user.php?id=$MergeID ($MergeStatsFrom) (previous stats: Uploaded: ".Format::get_size($Cur['Uploaded']).', Downloaded: '.Format::get_size($Cur['Downloaded']).', Ratio: '.Format::get_ratio($Cur['Uploaded'], $Cur['Downloaded']).')';
  635. $Cache->delete_value("user_stats_$UserID");
  636. $Cache->delete_value("user_stats_$MergeID");
  637. }
  638. }
  639. if ($Pass && check_perms('users_edit_password')) {
  640. $UpdateSet[] = "PassHash = '".db_string(Users::make_sec_hash($Pass))."'";
  641. $EditSummary[] = 'password reset';
  642. $Cache->delete_value("user_info_$UserID");
  643. $Cache->delete_value("user_info_heavy_$UserID");
  644. $Cache->delete_value("user_stats_$UserID");
  645. $Cache->delete_value("enabled_$UserID");
  646. $DB->query("
  647. SELECT SessionID
  648. FROM users_sessions
  649. WHERE UserID = '$UserID'");
  650. while (list($SessionID) = $DB->next_record()) {
  651. $Cache->delete_value("session_{$UserID}_$SessionID");
  652. }
  653. $Cache->delete_value("users_sessions_$UserID");
  654. $DB->query("
  655. DELETE FROM users_sessions
  656. WHERE UserID = '$UserID'");
  657. }
  658. if (empty($UpdateSet) && empty($EditSummary)) {
  659. if (!$Reason) {
  660. if (str_replace("\r", '', $Cur['AdminComment']) != str_replace("\r", '', $AdminComment) && check_perms('users_disable_any')) {
  661. $UpdateSet[] = "AdminComment = '$AdminComment'";
  662. } else {
  663. header("Location: user.php?id=$UserID");
  664. error();
  665. }
  666. } else {
  667. $EditSummary[] = 'notes added';
  668. }
  669. }
  670. if (count($TrackerUserUpdates) > 1) {
  671. Tracker::update_tracker('update_user', $TrackerUserUpdates);
  672. }
  673. if ($DeleteKeys) {
  674. $Cache->delete_value("user_info_$UserID");
  675. $Cache->delete_value("user_info_heavy_$UserID");
  676. } else {
  677. $Cache->begin_transaction("user_info_$UserID");
  678. $Cache->update_row(false, $LightUpdates);
  679. $Cache->commit_transaction(0);
  680. $Cache->begin_transaction("user_info_heavy_$UserID");
  681. $Cache->update_row(false, $HeavyUpdates);
  682. $Cache->commit_transaction(0);
  683. }
  684. $Summary = '';
  685. // Create edit summary
  686. if ($EditSummary) {
  687. $Summary = implode(', ', $EditSummary) . ' by ' . $LoggedUser['Username'];
  688. $Summary = sqltime() . ' - ' . ucfirst($Summary);
  689. if ($Reason) {
  690. $Summary .= "\nReason: $Reason";
  691. }
  692. $Summary .= "\n\n$AdminComment";
  693. } elseif (empty($UpdateSet) && empty($EditSummary) && $Cur['AdminComment'] == $_POST['AdminComment']) {
  694. $Summary = sqltime() . ' - Comment added by ' . $LoggedUser['Username'] . ': ' . "$Reason\n\n";
  695. }
  696. if (!empty($Summary)) {
  697. $UpdateSet[] = "AdminComment = '$Summary'";
  698. } else {
  699. $UpdateSet[] = "AdminComment = '$AdminComment'";
  700. }
  701. // Update cache
  702. // Build query
  703. $SET = implode(', ', $UpdateSet);
  704. $SQL = "
  705. UPDATE users_main AS m
  706. JOIN users_info AS i ON m.ID = i.UserID
  707. SET $SET
  708. WHERE m.ID = '$UserID'";
  709. // Perform update
  710. //die($SQL);
  711. $DB->query($SQL);
  712. if (isset($ClearStaffIDCache)) {
  713. $Cache->delete_value('staff_ids');
  714. }
  715. // redirect to user page
  716. header("location: user.php?id=$UserID");
  717. function translateUserStatus($Status)
  718. {
  719. switch ($Status) {
  720. case 0:
  721. return 'Unconfirmed';
  722. case 1:
  723. return 'Enabled';
  724. case 2:
  725. return 'Disabled';
  726. default:
  727. return $Status;
  728. }
  729. }
  730. function translateLeechStatus($Status)
  731. {
  732. switch ($Status) {
  733. case 0:
  734. return 'Disabled';
  735. case 1:
  736. return 'Enabled';
  737. default:
  738. return $Status;
  739. }
  740. }