PageRenderTime 66ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/api.php

https://github.com/BrianPrz/worklist
PHP | 3501 lines | 3032 code | 306 blank | 163 comment | 488 complexity | 520a8870194e6de7aeb08cb5345a0bd6 MD5 | raw file
  1. <?php
  2. /**
  3. * Copyright (c) 2014, High Fidelity Inc.
  4. * All Rights Reserved.
  5. *
  6. * http://highfidelity.io
  7. */
  8. require_once ("config.php");
  9. require_once ("models/DataObject.php");
  10. require_once ("models/Review.php");
  11. require_once ("models/Users_Favorite.php");
  12. require_once ("models/Budget.php");
  13. Session::check();
  14. if (!defined("ALL_ASSETS")) define("ALL_ASSETS", "all_assets");
  15. // TODO: add API keys to these function calls
  16. // uploadProfilePicture
  17. // getSystemDrawerJobs
  18. // getTimezone
  19. if(validateAction()) {
  20. if(!empty($_REQUEST['action'])){
  21. mysql_connect (DB_SERVER, DB_USER, DB_PASSWORD);
  22. mysql_select_db (DB_NAME);
  23. switch($_REQUEST['action']){
  24. case 'updateuser':
  25. validateAPIKey();
  26. updateuser();
  27. break;
  28. case 'pushVerifyUser':
  29. validateAPIKey();
  30. pushVerifyUser();
  31. break;
  32. case 'login':
  33. validateAPIKey();
  34. loginUserIntoSession();
  35. break;
  36. case 'getTaskPosts':
  37. getTaskPosts();
  38. break;
  39. case 'uploadProfilePicture':
  40. uploadProfilePicture();
  41. break;
  42. case 'updateProjectList':
  43. validateAPIKey();
  44. updateProjectList();
  45. break;
  46. case 'getSystemDrawerJobs':
  47. getSystemDrawerJobs();
  48. break;
  49. case 'bidNotification':
  50. validateAPIKey();
  51. sendBidNotification();
  52. break;
  53. case 'processW2Masspay':
  54. validateAPIKey();
  55. processW2Masspay();
  56. break;
  57. case 'doScanAssets':
  58. validateAPIKey();
  59. doScanAssets();
  60. break;
  61. case 'version':
  62. validateAPIKey();
  63. exec('svnversion > ver');
  64. break;
  65. case 'sendContactEmail':
  66. // @TODO: why do we require an API key for this?
  67. // I don't get it. The request is sent via JS, so if we included the API key it would
  68. // then become visible to all who want to see it, leaving the form open for abuse... - lithium
  69. // validateAPIKey();
  70. sendContactEmail();
  71. break;
  72. case 'getTimezone':
  73. getTimezone();
  74. break;
  75. case 'updateLastSeen':
  76. updateLastSeen();
  77. break;
  78. case 'sendTestNotifications':
  79. validateAPIKey();
  80. sendTestNotifications();
  81. break;
  82. case 'autoPass':
  83. validateAPIKey();
  84. autoPassSuggestedJobs();
  85. break;
  86. case 'processPendingReviewsNotifications':
  87. validateAPIKey();
  88. processPendingReviewsNotifications();
  89. break;
  90. case 'pruneJournalEntries' :
  91. validateAPIKey();
  92. pruneJournalEntries();
  93. break;
  94. case 'createRepo':
  95. createRepo();
  96. break;
  97. case 'createSandbox':
  98. createSandbox();
  99. break;
  100. case 'createDatabaseNewProject':
  101. createDatabaseNewProject();
  102. break;
  103. case 'sendNewProjectEmails':
  104. sendNewProjectEmails();
  105. break;
  106. case 'modifyConfigFile':
  107. modifyConfigFile();
  108. break;
  109. case 'addPostCommitHook':
  110. addPostCommitHook();
  111. break;
  112. case 'deployStagingSite':
  113. deployStagingSite();
  114. break;
  115. case 'getFavoriteUsers':
  116. getFavoriteUsers();
  117. break;
  118. case 'getTwilioCountries':
  119. getTwilioCountries();
  120. break;
  121. case 'deployErrorNotification':
  122. validateAPIKey();
  123. deployErrorNotification();
  124. break;
  125. case 'saveSoundSettings':
  126. saveSoundSettings();
  127. break;
  128. case 'sendNotifications':
  129. validateAPIKey();
  130. sendNotifications();
  131. break;
  132. case 'checkInactiveProjects':
  133. validateAPIKey();
  134. checkInactiveProjects();
  135. break;
  136. case 'checkRemovableProjects':
  137. validateAPIKey();
  138. checkRemovableProjects();
  139. break;
  140. case 'addProject':
  141. addProject();
  142. break;
  143. case 'addWorkitem':
  144. addWorkitem();
  145. break;
  146. case 'setFavorite':
  147. setFavorite();
  148. break;
  149. case 'manageBudget':
  150. manageBudget();
  151. break;
  152. case 'getBidItem':
  153. getBidItem();
  154. break;
  155. case 'getBonusHistory':
  156. getBonusHistory();
  157. break;
  158. case 'getFeeItem':
  159. getFeeItem();
  160. break;
  161. case 'getCodeReviewStatus':
  162. getCodeReviewStatus();
  163. break;
  164. case 'getFeeSums':
  165. getFeeSums();
  166. break;
  167. case 'getJobInformation':
  168. getJobInformation();
  169. break;
  170. case 'getMultipleBidList':
  171. getMultipleBidList();
  172. break;
  173. case 'getProjects':
  174. getProjects();
  175. break;
  176. case 'getReport':
  177. getReport();
  178. break;
  179. case 'getSkills':
  180. getSkills();
  181. break;
  182. case 'getStats':
  183. $req = isset($_REQUEST['req'])? $_REQUEST['req'] : 'table';
  184. $interval = isset($_REQUEST['req'])? $_REQUEST['req'] : 30;
  185. echo json_encode(getStats($req, $interval));
  186. break;
  187. case 'getUserItem':
  188. getUserItem();
  189. break;
  190. case 'getUserItems':
  191. getUserItems();
  192. break;
  193. case 'getUserList':
  194. getUserList();
  195. break;
  196. case 'getUsersList':
  197. getUsersList();
  198. break;
  199. case 'getUserStats':
  200. getUserStats();
  201. break;
  202. case 'getWorkitem':
  203. getWorkitem();
  204. break;
  205. case 'getWorklist':
  206. getWorklist();
  207. break;
  208. case 'payBonus':
  209. payBonus();
  210. break;
  211. case 'payCheck':
  212. payCheck();
  213. break;
  214. case 'pingTask':
  215. pingTask();
  216. break;
  217. case 'refreshFilter':
  218. refreshFilter();
  219. break;
  220. case 'userReview':
  221. userReview();
  222. break;
  223. case 'workitemSandbox':
  224. workitemSandbox();
  225. break;
  226. case 'testFlight':
  227. testFlight();
  228. break;
  229. case 'updateBudget':
  230. updateBudget();
  231. break;
  232. case 'userNotes':
  233. userNotes();
  234. break;
  235. case 'visitQuery':
  236. visitQuery();
  237. break;
  238. case 'wdFee':
  239. wdFee();
  240. break;
  241. case 'budgetInfo':
  242. budgetInfo();
  243. break;
  244. case 'budgetHistory':
  245. budgetHistory();
  246. break;
  247. case 'timeline':
  248. timeline();
  249. break;
  250. case 'newUserNotification':
  251. validateAPIKey();
  252. sendNewUserNotification();
  253. break;
  254. case 'sendJobReport':
  255. validateAPIKey();
  256. sendJobReport();
  257. break;
  258. default:
  259. die("Invalid action.");
  260. }
  261. }
  262. }
  263. function validateAction() {
  264. if (validateRequest()) {
  265. return true;
  266. } else {
  267. return false;
  268. }
  269. }
  270. function validateRequest() {
  271. if( ! isset($_SERVER['HTTPS'])) {
  272. error_log("Only HTTPS connection is accepted.");
  273. die("Only HTTPS connection is accepted.");
  274. } else if ( ! isset($_REQUEST['action'])) {
  275. error_log("API not defined");
  276. die("API not defined");
  277. } else {
  278. return true;
  279. }
  280. }
  281. function validateAPIKey() {
  282. if( ! isset($_REQUEST["api_key"])) {
  283. error_log("No api key defined.");
  284. die("No api key defined.");
  285. } else if(strcmp($_REQUEST["api_key"],API_KEY) != 0 ) {
  286. error_log("Wrong api key provided.");
  287. die("Wrong api key provided.");
  288. } else {
  289. return true;
  290. }
  291. }
  292. /*
  293. * Setting session variables for the user so he is logged in
  294. */
  295. function loginUserIntoSession(){
  296. $db = new Database();
  297. $uid = (int) $_REQUEST['user_id'];
  298. $sid = $_REQUEST['session_id'];
  299. $csrf_token = md5(uniqid(rand(), TRUE));
  300. $sql = "SELECT * FROM ".WS_SESSIONS." WHERE session_id = '".mysql_real_escape_string($sid, $db->getLink())."'";
  301. $res = $db->query($sql);
  302. $session_data ="running|s:4:\"true\";";
  303. $session_data .="userid|s:".strlen($uid).":\"".$uid."\";";
  304. $session_data .="username|s:".strlen($_REQUEST['username']).":\"".$_REQUEST['username']."\";";
  305. $session_data .="nickname|s:".strlen($_REQUEST['nickname']).":\"".$_REQUEST['nickname']."\";";
  306. $session_data .="admin|s:".strlen($_REQUEST['admin']).":\"".$_REQUEST['admin']."\";";
  307. $session_data .="csrf_token|s:".strlen($csrf_token).":\"".$csrf_token."\";";
  308. if(mysql_num_rows($res) > 0){
  309. $sql = "UPDATE ".WS_SESSIONS." SET ".
  310. "session_data = '".mysql_real_escape_string($session_data,$db->getLink())."' ".
  311. "WHERE session_id = '".mysql_real_escape_string($sid, $db->getLink())."';";
  312. $db->query($sql);
  313. } else {
  314. $expires = time() + SESSION_EXPIRE;
  315. $db->insert(WS_SESSIONS,
  316. array("session_id" => $sid,
  317. "session_expires" => $expires,
  318. "session_data" => $session_data),
  319. array("%s","%d","%s")
  320. );
  321. }
  322. }
  323. function uploadProfilePicture() {
  324. // check if we have a file
  325. if (empty($_FILES)) {
  326. respond(array(
  327. 'success' => false,
  328. 'message' => 'No file uploaded!'
  329. ));
  330. }
  331. if (empty($_REQUEST['userid'])) {
  332. respond(array(
  333. 'success' => false,
  334. 'message' => 'No user ID set!'
  335. ));
  336. }
  337. $ext = end(explode(".", $_FILES['profile']['name']));
  338. $tempFile = $_FILES['profile']['tmp_name'];
  339. $imgName = strtolower($_REQUEST['userid'] . '.' . $ext);
  340. $path = APP_IMAGE_PATH . $imgName;
  341. try {
  342. File::s3Upload($tempFile, $path);
  343. $query = "
  344. UPDATE `" . USERS . "`
  345. SET `picture` = '" . mysql_real_escape_string($imgName) . "' ,
  346. `s3bucket` = '" . S3_BUCKET ."'
  347. WHERE `id` = " . (int) $_REQUEST['userid'] . "
  348. LIMIT 1";
  349. if (! mysql_query($query)) {
  350. error_log("s3upload mysql: ".mysql_error());
  351. respond(array(
  352. 'success' => false,
  353. 'message' => SL_DB_FAILURE
  354. ));
  355. }
  356. respond(array(
  357. 'success' => true,
  358. 'picture' => $imgName
  359. ));
  360. } catch (Exception $e) {
  361. $success = false;
  362. $error = 'There was a problem uploading your file';
  363. error_log(__FILE__.": Error uploading images to S3:\n$e");
  364. return $this->setOutput(array(
  365. 'success' => false,
  366. 'message' => 'An error occured while uploading the file, please try again!'
  367. ));
  368. }
  369. }
  370. function updateuser(){
  371. $sql = "UPDATE ".USERS." ".
  372. "SET ";
  373. $id = (int)$_REQUEST["user_id"];
  374. foreach($_REQUEST["user_data"] as $key => $value){
  375. $sql .= $key." = '".mysql_real_escape_string($value)."', ";
  376. }
  377. $sql = substr($sql,0,(strlen($sql) - 1));
  378. $sql .= " ".
  379. "WHERE id = ".$id;
  380. mysql_query($sql);
  381. }
  382. function pushVerifyUser(){
  383. $user_id = intval($_REQUEST['id']);
  384. $sql = "UPDATE " . USERS . " SET `confirm` = '1', is_active = '1' WHERE `id` = $user_id";
  385. mysql_unbuffered_query($sql);
  386. respond(array('success' => false, 'message' => 'User has been confirmed!'));
  387. }
  388. function updateProjectList(){
  389. $repo = basename($_REQUEST['repo']);
  390. $project = new Project();
  391. $project->loadByRepo($repo);
  392. $commit_date = date('Y-m-d H:i:s');
  393. $project->setLastCommit($commit_date);
  394. $project->save();
  395. }
  396. function getSystemDrawerJobs(){
  397. $sql = " SELECT "
  398. . " SUM(CASE WHEN w.status = 'Bidding' THEN 1 ELSE 0 END) AS bidding, "
  399. . " SUM(CASE WHEN w.status = 'Review' THEN 1 ELSE 0 END) AS review "
  400. . " FROM " . WORKLIST . " AS w "
  401. . " WHERE w.status = 'Bidding' OR (w.status = 'Review' "
  402. . " AND w.code_review_completed = 0 "
  403. . " AND w.code_review_started = 0);";
  404. $result = mysql_query($sql);
  405. if ($result && ($row = mysql_fetch_assoc($result))) {
  406. $bidding_count = $row['bidding'];
  407. $review_count = $row['review'];
  408. $need_review = array();
  409. if ($review_count) {
  410. $sql = " SELECT w.id, w.summary "
  411. . " FROM " . WORKLIST . " AS w "
  412. . " WHERE w.status = 'Review' "
  413. . " AND w.code_review_completed = 0 "
  414. . " AND w.code_review_started = 0"
  415. . " LIMIT 7;";
  416. $result = mysql_query($sql);
  417. while ($row = mysql_fetch_assoc($result)) {
  418. $need_review[] = array(
  419. 'id' => $row['id'],
  420. 'summary' => $row['summary']
  421. );
  422. }
  423. }
  424. respond(array(
  425. 'success' => true,
  426. 'bidding' => $bidding_count,
  427. 'review' => $review_count,
  428. 'need_review' => $need_review
  429. ));
  430. } else {
  431. respond(array('success' => false, 'message' => "Couldn't retrieve jobs"));
  432. }
  433. }
  434. function sendBidNotification() {
  435. require_once('./classes/Notification.class.php');
  436. $notify = new Notification();
  437. $notify->emailExpiredBids();
  438. }
  439. function processW2Masspay() {
  440. if (!defined('COMMAND_API_KEY')
  441. or !array_key_exists('COMMAND_API_KEY',$_POST)
  442. or $_POST['COMMAND_API_KEY'] != COMMAND_API_KEY)
  443. { die('Action Not configured'); }
  444. $con = mysql_connect(DB_SERVER,DB_USER,DB_PASSWORD);
  445. if (!$con) {
  446. die('Could not connect: ' . mysql_error());
  447. }
  448. mysql_select_db(DB_NAME, $con);
  449. $sql = " UPDATE " . FEES . " AS f, " . WORKLIST . " AS w, " . USERS . " AS u "
  450. . " SET f.paid = 1, f.paid_date = NOW() "
  451. . " WHERE f.paid = 0 AND f.worklist_id = w.id AND w.status = 'Done' "
  452. . " AND f.withdrawn = 0 "
  453. . " AND f.user_id = u.id "
  454. . " AND u.has_W2 = 1 "
  455. . " AND w.status_changed < CAST(DATE_FORMAT(NOW(),'%Y-%m-01') as DATE) "
  456. . " AND f.date < CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE); ";
  457. // Marks all Fees from the past month as paid (for DONEd jobs)
  458. if (!$result = mysql_query($sql)) { error_log("mysql error: ".mysql_error()); die("mysql_error: ".mysql_error()); }
  459. $total = mysql_affected_rows();
  460. if( $total) {
  461. echo "{$total} fees were processed.";
  462. } else {
  463. echo "No fees were found!";
  464. }
  465. $sql = " UPDATE " . FEES . " AS f, " . USERS . " AS u "
  466. . " SET f.paid = 1, f.paid_date = NOW() "
  467. . " WHERE f.paid = 0 "
  468. . " AND f.bonus = 1 "
  469. . " AND f.withdrawn = 0 "
  470. . " AND f.user_id = u.id "
  471. . " AND u.has_W2 = 1 "
  472. . " AND f.date < CAST(DATE_FORMAT(NOW() ,'%Y-%m-01') as DATE); ";
  473. // Marks all Fees from the past month as paid (for DONEd jobs)
  474. if (!$result = mysql_query($sql)) { error_log("mysql error: ".mysql_error()); die("mysql_error: ".mysql_error()); }
  475. $total = mysql_affected_rows();
  476. if( $total) {
  477. echo "{$total} bonuses were processed.";
  478. } else {
  479. echo "No bonuses were found!";
  480. }
  481. mysql_close($con);
  482. }
  483. function doScanAssets() {
  484. $scanner = new ScanAssets();
  485. $scanner->scanAll();
  486. }
  487. function respond($val){
  488. exit(json_encode($val));
  489. }
  490. function sendContactEmail(){
  491. $name = isset($_REQUEST['name']) ? $_REQUEST['name'] : '';
  492. $email = isset($_REQUEST['email']) ? $_REQUEST['email'] : '';
  493. $phone = isset($_REQUEST['phone']) ? $_REQUEST['phone'] : '';
  494. $proj_name = isset($_REQUEST['project']) ? $_REQUEST['project'] : '';
  495. $proj_desc = isset($_REQUEST['proj_desc']) ? $_REQUEST['proj_desc'] : '';
  496. $website = isset($_REQUEST['website']) ? $_REQUEST['website'] : '';
  497. if (empty($phone) || empty($email) || empty($phone) || empty($proj_name) || empty($proj_desc)) {
  498. exit(json_encode(array('error' => 'All Fields are required!')));
  499. }
  500. require_once('./classes/Notification.class.php');
  501. $notify = new Notification();
  502. if ($notify->emailContactForm($name, $email, $phone, $proj_name, $proj_desc, $website)) {
  503. exit(json_encode(array('success' => true)));
  504. } else {
  505. exit(json_encode(array('error' => 'There was an error sending your message, please try again later.')));
  506. }
  507. }// end sendContactEmail
  508. function autoPassSuggestedJobs() {
  509. $con = mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD);
  510. if (!$con) {
  511. die('Could not connect: ' . mysql_error());
  512. }
  513. mysql_select_db(DB_NAME, $con);
  514. $sql = "SELECT id FROM `" . WORKLIST ."` WHERE status IN ( 'Suggested' , 'SuggestedWithBid', 'Bidding') AND DATEDIFF(now() , status_changed) > 30";
  515. $result = mysql_query($sql);
  516. $delay = 0;
  517. if(mysql_num_rows($result) > 1) {
  518. $delay = 5;
  519. }
  520. while ($row = mysql_fetch_assoc($result)) {
  521. $status = 'Pass';
  522. $workitem = new WorkItem($row['id']);
  523. $prev_status = $workitem->getStatus();
  524. // change status of the workitem to PASS.
  525. $workitem->setStatus($status);
  526. if ($workitem->save()) {
  527. $recipients = array('creator');
  528. $emails = array();
  529. $data = array('prev_status' => $prev_status);
  530. if ($prev_status == 'Bidding') {
  531. $recipients[] = 'usersWithBids';
  532. $emails = preg_split('/[\s]+/', ADMINS_EMAILS);
  533. }
  534. //notify
  535. Notification::workitemNotify(
  536. array(
  537. 'type' => 'auto-pass',
  538. 'workitem' => $workitem,
  539. 'recipients' => $recipients,
  540. 'emails' => $emails
  541. ),
  542. $data
  543. );
  544. //sendJournalnotification
  545. $journal_message = "\\\\#" . $workitem->getId() . " updated by @Otto. Status set to " . $status;
  546. sendJournalNotification(stripslashes($journal_message));
  547. } else {
  548. error_log("Otto failed to update the status of workitem #" . $workitem->getId() . " to " . $status);
  549. }
  550. sleep($delay);
  551. }
  552. mysql_free_result($result);
  553. mysql_close($con);
  554. }
  555. function getTimezone() {
  556. if (isset($_REQUEST['username'])) {
  557. $username = $_REQUEST['username'];
  558. } else {
  559. respond(array('succeeded' => false, 'message' => 'Error: Could not determine the user'));
  560. }
  561. $user = new User();
  562. if ($user->findUserByUsername($username)) {
  563. respond(array('succeeded' => true, 'message' => $user->getTimezone()));
  564. } else {
  565. respond(array('succeeded' => false, 'message' => 'Error: Could not determine the user'));
  566. }
  567. }
  568. function updateLastSeen() {
  569. if (isset($_REQUEST['username'])) {
  570. $username = $_REQUEST['username'];
  571. } else {
  572. respond(array('succeeded' => false, 'message' => 'Error: Could not determine the user'));
  573. }
  574. $qry = "UPDATE ". USERS ." SET last_seen = NOW() WHERE username='". $username ."'";
  575. if ($res = mysql_query($qry)) {
  576. respond(array('succeeded' => true, 'message' => 'Last seen time updated!'));
  577. } else {
  578. respond(array('succeeded' => false, 'message' => mysql_error()));
  579. }
  580. }
  581. function processPendingReviewsNotifications() {
  582. // Check if it is time to process notifications
  583. if (!isset($_REQUEST['force']) && !canProcessNotifications()) {
  584. return;
  585. }
  586. // process pending journal notifications
  587. $pendingReviews = Review::getReviewsWithPendingJournalNotifications();
  588. if($pendingReviews !== false && count($pendingReviews) > 0) {
  589. echo "<br/>Processing " . count($pendingReviews) . " reviews.";
  590. foreach ($pendingReviews as $review) {
  591. $tReview = new Review();
  592. $tReview->loadById($review['reviewer_id'], $review['reviewee_id']);
  593. if ($tReview->journal_notified == 0) {
  594. sendReviewNotification($tReview->reviewee_id, 'update',
  595. $tReview->getReviews($tReview->reviewee_id, $tReview->reviewer_id, ' AND r.reviewer_id=' . $tReview->reviewer_id));
  596. } else {
  597. sendReviewNotification($tReview->reviewee_id, 'new',
  598. $tReview->getReviews($tReview->reviewee_id, $tReview->reviewer_id, ' AND r.reviewer_id=' . $tReview->reviewer_id));
  599. }
  600. $tReview->journal_notified = 1;
  601. $tReview->save('reviewer_id', 'reviewee_id');
  602. usleep(4000000);
  603. }
  604. } else {
  605. echo "<br />Processed. No pending Reviews.";
  606. }
  607. resetCronFile();
  608. }
  609. function canProcessNotifications() {
  610. $file = REVIEW_NOTIFICATIONS_CRON_FILE;
  611. // If no temp file is set (first time?) run it
  612. if (!file_exists($file)) {
  613. return true;
  614. } else {
  615. $hour = (int) file_get_contents($file);
  616. $serverHour = (int) date('H');
  617. if ($serverHour == $hour) {
  618. return true;
  619. } else {
  620. echo "<br/>It is not time yet.";
  621. echo "<br/>Next hour: " . $hour;
  622. echo "<br/>Current hour:" . $serverHour;
  623. return false;
  624. }
  625. }
  626. }
  627. function resetCronFile() {
  628. $hourLag = mt_rand(5, 12);
  629. $serverHour = (int) date('H');
  630. $newHour = $hourLag + $serverHour;
  631. if ($newHour > 23) {
  632. $newHour -= 24;
  633. }
  634. echo "<br/>Cron File Reseted.";
  635. echo "<br/>Next hour: " . $newHour;
  636. unlink(REVIEW_NOTIFICATIONS_CRON_FILE);
  637. file_put_contents(REVIEW_NOTIFICATIONS_CRON_FILE, $newHour);
  638. chmod (REVIEW_NOTIFICATIONS_CRON_FILE, 0755);
  639. }
  640. // Prune Journal entries by deleting all entries except the latest 100
  641. function pruneJournalEntries() {
  642. $sql = " SELECT MAX(id) AS maxId FROM " . ENTRIES;
  643. $result = mysql_query($sql);
  644. if ($result) {
  645. $row = mysql_fetch_assoc($result);
  646. } else {
  647. die( 'Failed to get all entries');
  648. }
  649. $total = (int) $row['maxId'] - 100;
  650. $sql = " DELETE FROM " . ENTRIES . " WHERE id <= {$total};";
  651. echo $sql;
  652. $result = mysql_unbuffered_query($sql);
  653. echo "<br/> # of deleted entries: " . mysql_affected_rows();
  654. }
  655. function createDatabaseNewProject() {
  656. $sandBoxUtil = new SandBoxUtil();
  657. if (array_key_exists('project', $_REQUEST)) {
  658. try {
  659. if ($sandBoxUtil->createDatabaseNewProject($_REQUEST['project'], $_REQUEST['username'])) {
  660. echo json_encode(array('success'=>true, 'message'=>'Database created succesfully'));
  661. } else {
  662. echo json_encode(array('success'=>false, 'message'=>'Database creation failed'));
  663. }
  664. } catch (Exception $e) {
  665. echo json_encode(array('success'=>false, 'message'=>$e->getMessage()));
  666. }
  667. } else {
  668. echo json_encode(array('success'=>false, 'message'=>'Missing Parameters'));
  669. }
  670. }
  671. function createRepo() {
  672. $sandBoxUtil = new SandBoxUtil();
  673. if (array_key_exists('project', $_REQUEST)) {
  674. try {
  675. if ($sandBoxUtil->createRepo($_REQUEST['project'])) {
  676. echo json_encode(array('success'=>true, 'message'=>'Repository created succesfully'));
  677. } else {
  678. echo json_encode(array('success'=>false, 'message'=>'Repository not created'));
  679. }
  680. } catch (Exception $e) {
  681. echo json_encode(array('success'=>false, 'message'=>$e->getMessage()));
  682. }
  683. } else {
  684. echo json_encode(array('success'=>false, 'message'=>'Missing parameters'));
  685. }
  686. }
  687. function createSandbox() {
  688. $sandBoxUtil = new SandBoxUtil();
  689. if (array_key_exists('username', $_REQUEST) && array_key_exists('nickname', $_REQUEST)
  690. && array_key_exists('unixusername', $_REQUEST) && array_key_exists('projectname', $_REQUEST)) {
  691. try {
  692. if ($sandBoxUtil->createSandbox($_REQUEST['username'],
  693. $_REQUEST['nickname'],
  694. $_REQUEST['unixusername'],
  695. $_REQUEST['projectname'],
  696. null,
  697. $_REQUEST['newuser'])) {
  698. $user = new User();
  699. $user->findUserByNickname($_REQUEST['nickname']);
  700. $user->setHas_sandbox(1);
  701. $user->setUnixusername($_REQUEST['unixusername']);
  702. $user->setProjects_checkedout($_REQUEST['projectname']);
  703. $user->save();
  704. echo json_encode(array('success'=>true, 'message'=>'Sandbox created'));
  705. } else {
  706. echo json_encode(array('success'=>false, 'message'=>'Sandbox creation and project checkout failed'));
  707. }
  708. } catch (Exception $e) {
  709. echo json_encode(array('success'=>false, 'message'=>$e->getMessage()));
  710. }
  711. } else {
  712. echo json_encode(array('success'=>false, 'message'=>'Missing parameters'));
  713. }
  714. }
  715. function sendNewProjectEmails() {
  716. if (array_key_exists('username', $_REQUEST) && array_key_exists('nickname', $_REQUEST)
  717. && array_key_exists('unixusername', $_REQUEST) && array_key_exists('projectname', $_REQUEST)) {
  718. $data = array();
  719. $data['project_name'] = $_REQUEST['projectname'];
  720. $data['nickname'] = $_REQUEST['unixusername'];
  721. $data['database_user'] = $_REQUEST['dbuser'];
  722. $data['repo_type'] = $_REQUEST['repo_type'];
  723. $data['github_repo_url'] = $_REQUEST['github_repo_url'];
  724. $user = new User();
  725. sendTemplateEmail(SUPPORT_EMAIL, 'ops-project-created', $data);
  726. if (!sendTemplateEmail($_REQUEST['username'], $_REQUEST['template'], $data)) {
  727. echo json_encode(array('success'=>false, 'message'=>'Emails not sent'));
  728. } else {
  729. echo json_encode(array('success'=>true, 'message'=>'Emails sent out'));
  730. }
  731. } else {
  732. echo json_encode(array('success'=>false, 'message'=>'Missing parameters'));
  733. }
  734. }
  735. function modifyConfigFile() {
  736. $sandBoxUtil = new SandBoxUtil();
  737. if (array_key_exists('username', $_REQUEST) && array_key_exists('nickname', $_REQUEST)
  738. && array_key_exists('unixusername', $_REQUEST) && array_key_exists('projectname', $_REQUEST)) {
  739. if ($sandBoxUtil->modifyConfigFile($_REQUEST['unixusername'],
  740. $_REQUEST['projectname'],
  741. $_REQUEST['dbuser'])) {
  742. echo json_encode(array('success'=>true, 'message'=>'Sandbox created'));
  743. } else {
  744. echo json_encode(array('success'=>false, 'message'=>'Sandbox creation and project checkout failed'));
  745. }
  746. } else {
  747. echo json_encode(array('success'=>false, 'message'=>'Missing parameters'));
  748. }
  749. }
  750. function addPostCommitHook() {
  751. $sandBoxUtil = new SandBoxUtil();
  752. if (array_key_exists('repo', $_REQUEST)) {
  753. try {
  754. if ($sandBoxUtil->addPostCommitHook($_REQUEST['repo'])) {
  755. echo json_encode(array('success'=>true, 'message'=>'Post commit hook added'));
  756. } else {
  757. echo json_encode(array('success'=>false, 'message'=>'Failed adding post commit hook'));
  758. }
  759. } catch (Exception $e) {
  760. echo json_encode(array('success'=>false, 'message'=>$e->getMessage()));
  761. }
  762. } else {
  763. echo json_encode(array('success'=>false, 'message'=>'Missing parameters'));
  764. }
  765. }
  766. function deployStagingSite() {
  767. $sandBoxUtil = new SandBoxUtil();
  768. if (array_key_exists('repo', $_REQUEST)) {
  769. try {
  770. if ($sandBoxUtil->deployStagingSite($_REQUEST['repo'])) {
  771. echo json_encode(array('success'=>true, 'message'=>'Post commit hook added'));
  772. } else {
  773. echo json_encode(array('success'=>false, 'message'=>'Failed adding post commit hook'));
  774. }
  775. } catch (Exception $e) {
  776. echo json_encode(array('success'=>false, 'message'=>$e->getMessage()));
  777. }
  778. } else {
  779. echo json_encode(array('success'=>false, 'message'=>'Missing parameters'));
  780. }
  781. }
  782. function getFavoriteUsers() {
  783. if (!$userid = (isset($_SESSION['userid']) ? $_SESSION['userid'] : 0)) {
  784. echo json_encode(array('favorite_users' => array()));
  785. return;
  786. }
  787. $users_favorite = new Users_Favorite();
  788. $data = array('favorite_users' => $users_favorite->getFavoriteUsers($userid));
  789. echo json_encode($data);
  790. }
  791. /**
  792. * Returns a list of all the countries supported by Twilio
  793. */
  794. function getTwilioCountries() {
  795. $sql = 'SELECT `country_code`, `country_phone_prefix` FROM `' . COUNTRIES . '` WHERE `country_twilio_enabled` = 1';
  796. $result = mysql_query($sql);
  797. if(!is_resource($result)) {
  798. echo json_encode(array(
  799. 'success' => false,
  800. 'message' => 'Could not retrieve the list of twilio supported countries'
  801. ));
  802. return;
  803. }
  804. $list = array();
  805. while ($row = mysql_fetch_assoc($result)) {
  806. $list[$row['country_code']] = $row['country_phone_prefix'];
  807. }
  808. echo json_encode(array(
  809. 'success' => true,
  810. 'list' => $list
  811. ));
  812. return;
  813. }
  814. function deployErrorNotification() {
  815. $work_item_id = isset($_REQUEST['workitem']) ? $_REQUEST['workitem'] : 0;
  816. $error_msg = isset($_REQUEST['error']) ? base64_decode($_REQUEST['error']) : '';
  817. $commit_rev = isset($_REQUEST['rev']) ? $_REQUEST['rev'] : '';
  818. require_once('classes/Notification.class.php');
  819. $notify = new Notification();
  820. $notify->deployErrorNotification($work_item_id, $error_msg, $commit_rev);
  821. exit(json_encode(array('success' => true)));
  822. }
  823. function saveSoundSettings() {
  824. if (!$userid = (isset($_SESSION['userid']) ? $_SESSION['userid'] : 0)) {
  825. echo json_encode(array('success'=>false, 'message'=>'Not logged-in user'));
  826. return;
  827. }
  828. try {
  829. $settings = 0;
  830. $settings_arr = preg_split('/:/', $_REQUEST['settings'], 5);
  831. if ((int) $settings_arr[0]) {
  832. $settings = $settings | JOURNAL_CHAT_SOUND;
  833. }
  834. if ((int) $settings_arr[1]) {
  835. $settings = $settings | JOURNAL_SYSTEM_SOUND;
  836. }
  837. if ((int) $settings_arr[2]) {
  838. $settings = $settings | JOURNAL_BOT_SOUND;
  839. }
  840. if ((int) $settings_arr[3]) {
  841. $settings = $settings | JOURNAL_PING_SOUND;
  842. }
  843. if ((int) $settings_arr[4]) {
  844. $settings = $settings | JOURNAL_EMERGENCY_ALERT;
  845. }
  846. $user = new User();
  847. $user->findUserById($userid);
  848. $user->setSound_settings($settings);
  849. $user->save();
  850. echo json_encode(array('success'=>true, 'message'=>'Settings saved'));
  851. } catch(Exception $e) {
  852. echo json_encode(array('success'=>false, 'message'=>'Settings saving failed'));
  853. }
  854. }
  855. function sendNotifications() {
  856. if (! array_key_exists('command', $_REQUEST)) {
  857. echo json_encode(array('success' => false, 'message' => 'Missing parameters'));
  858. exit;
  859. }
  860. $command = $_REQUEST['command'];
  861. switch ($command) {
  862. case 'statusNotify':
  863. if (! array_key_exists('workitem', $_REQUEST)) {
  864. echo json_encode(array('success' => false, 'message' => 'Missing parameters'));
  865. exit;
  866. }
  867. $workitem_id = (int) $_REQUEST['workitem'];
  868. $workitem = new WorkItem;
  869. $workitem->loadById($workitem_id);
  870. Notification::statusNotify($workitem);
  871. error_log('api.php: statusNotify completed');
  872. break;
  873. }
  874. echo json_encode(array('success' => true, 'message' => 'Notifications sent'));
  875. }
  876. function checkInactiveProjects() {
  877. $report_message = '';
  878. $db = new Database();
  879. $sql_inactive_projects = "
  880. SELECT w.project_id, p.name, p.contact_info, u.nickname, MAX(status_changed) AS last_change
  881. FROM " . WORKLIST . " AS w
  882. INNER JOIN " . PROJECTS . " AS p ON w.project_id=p.project_id
  883. LEFT JOIN " . USERS . " AS u ON u.id=p.owner_id
  884. WHERE p.active = 1 OR 1
  885. GROUP BY w.project_id HAVING last_change < DATE_SUB(NOW(), INTERVAL 90 DAY)
  886. ORDER BY p.name ASC";
  887. // Delete accounts which exists for at least 45 days and never have been used.
  888. $result = $db->query($sql_inactive_projects);
  889. while ($row = mysql_fetch_assoc($result)) {
  890. $project = new Project($row['project_id']);
  891. // send email
  892. $data = array(
  893. 'owner' => $row['nickname'],
  894. 'projectUrl' => Project::getProjectUrl($row['project_id']),
  895. 'projectName' => $row['name']
  896. );
  897. if (! sendTemplateEmail($row['contact_info'], 'project-inactive', $data)) {
  898. $report_message .= ' <p> Ok ---';
  899. } else {
  900. $report_message .= ' <p> Fail -';
  901. }
  902. $report_message .= ' Project (' . $row['project_id'] . ')- <a href="' . Project::getProjectUrl($row['project_id']) . '">' . $row['name'] . '</a> -- Last changed status: ' . $row['last_change'] . '</p>';
  903. $project->setActive(0);
  904. $project->save();
  905. }
  906. // Send report to ops if any project was set as inactive
  907. if ($report_message != '') {
  908. $headers['From'] = DEFAULT_SENDER;
  909. $subject = "Inactive Projects Report";
  910. $body = $report_message;
  911. if (!send_email(OPS_EMAIL, $subject, $body, null, $headers )) {
  912. error_log ('checkActiveProjects cron: Failed to send email report');
  913. }
  914. }
  915. }
  916. function checkRemovableProjects() {
  917. $report_message = '';
  918. $db = new Database();
  919. $sql_projects = "
  920. SELECT p.project_id, p.name, u.nickname, p.creation_date
  921. FROM " . PROJECTS . " AS p
  922. LEFT JOIN " . USERS . " AS u ON u.id=p.owner_id
  923. WHERE p.project_id NOT IN (SELECT DISTINCT w1.project_id
  924. FROM " . WORKLIST . " AS w1)
  925. AND p.creation_date < DATE_SUB(NOW(), INTERVAL 180 DAY)";
  926. $result = $db->query($sql_projects);
  927. while ($row = mysql_fetch_assoc($result)) {
  928. // send email
  929. $data = array(
  930. 'owner' => $row['nickname'],
  931. 'projectUrl' => Project::getProjectUrl($row['project_id']),
  932. 'projectName' => $row['name'],
  933. 'creation_date' => date('Y-m-d', strtotime($row['creation_date']))
  934. );
  935. if (sendTemplateEmail($row['contact_info'], 'project-removed', $data)) {
  936. $report_message .= ' <p> Ok email---';
  937. } else {
  938. $report_message .= ' <p> Failed email -';
  939. }
  940. $report_message .= ' Project (' . $row['project_id'] . ')- <a href="' . Project::getProjectUrl($row['project_id']) . '">' . $row['name'] . '</a> -- Created: ' . $row['creation_date'] . '</p>';
  941. // Remove projects dependencies
  942. // Remove project users
  943. $report_message .= '<p> Users removed for project id ' . $row['project_id'] . ':</p>';
  944. $sql_get_project_users = "SELECT * FROM " . PROJECT_USERS . " WHERE project_id = " . $row['project_id'];
  945. $result_temp = $db->query($sql_get_project_users);
  946. while ($row_temp = mysql_fetch_assoc($result_temp)) {
  947. $report_message .= dump_row_values($row_temp);
  948. }
  949. $sql_remove_project_users = "DELETE FROM " . PROJECT_USERS . " WHERE project_id = " . $row['project_id'];
  950. $db->query($sql_remove_project_users);
  951. // Remove project runners
  952. $report_message .= '<p> Designers removed for project id ' . $row['project_id'] . ':</p>';
  953. $sql_get_project_runners = "SELECT * FROM " . PROJECT_RUNNERS . " WHERE project_id = " . $row['project_id'];
  954. $result_temp = $db->query($sql_get_project_runners);
  955. while ($row_temp = mysql_fetch_assoc($result_temp)) {
  956. $report_message .= dump_row_values($row_temp);
  957. }
  958. $sql_remove_project_runners = "DELETE FROM " . PROJECT_RUNNERS . " WHERE project_id = " . $row['project_id'];
  959. $db->query($sql_remove_project_runners);
  960. // Remove project roles
  961. $report_message .= '<p> Roles removed for project id ' . $row['project_id'] . ':</p>';
  962. $sql_get_project_roles = "SELECT * FROM " . ROLES . " WHERE project_id = " . $row['project_id'];
  963. $result_temp = $db->query($sql_get_project_roles);
  964. while ($row_temp = mysql_fetch_assoc($result_temp)) {
  965. $report_message .= dump_row_values($row_temp);
  966. }
  967. $sql_remove_project_roles = "DELETE FROM " . ROLES . " WHERE project_id = " . $row['project_id'];
  968. $db->query($sql_remove_project_roles);
  969. $url = TOWER_API_URL;
  970. $fields = array(
  971. 'action' => 'staging_cleanup',
  972. 'name' => $row['name']
  973. );
  974. $result = CURLHandler::Post($url, $fields);
  975. // Remove project
  976. $report_message .= '<p> Project id ' . $row['project_id'] . ' removed </p>';
  977. $sql_get_project = "SELECT * FROM " . PROJECTS . " WHERE project_id = " . $row['project_id'];
  978. $result_temp = $db->query($sql_get_project);
  979. while ($row_temp = mysql_fetch_assoc($result_temp)) {
  980. $report_message .= dump_row_values($row_temp);
  981. }
  982. $sql_remove_project = "DELETE FROM " . PROJECTS . " WHERE project_id = " . $row['project_id'];
  983. $db->query($sql_remove_project);
  984. }
  985. // Send report to ops if any project was set as inactive
  986. if ($report_message != '') {
  987. $headers['From'] = DEFAULT_SENDER;
  988. $subject = "Removed Projects Report";
  989. $body = $report_message;
  990. if (!send_email(OPS_EMAIL, $subject, $body, null, $headers )) {
  991. error_log ('checkActiveProjects cron: Failed to send email report');
  992. }
  993. }
  994. }
  995. function dump_row_values($row) {
  996. $dump = '<p>';
  997. foreach ($row as $key=> $val ) {
  998. $dump .= '"' . $key . '" => ' . $val . ':';
  999. }
  1000. $dump .= '</p>';
  1001. return $dump;
  1002. }
  1003. function addProject() {
  1004. $journal_message = '';
  1005. $nick = '';
  1006. $userId = getSessionUserId();
  1007. if ($userId) {
  1008. initUserById($userId);
  1009. $user = new User();
  1010. $user->findUserById( $userId );
  1011. $nick = $user->getNickname();
  1012. $project = new Project();
  1013. $cr_3_favorites = $_REQUEST["cr_3_favorites"];
  1014. $args = array(
  1015. 'name',
  1016. 'description',
  1017. 'logo',
  1018. 'website',
  1019. 'checkGitHub',
  1020. 'github_repo_url',
  1021. 'defaultGithubApp',
  1022. 'githubClientId',
  1023. 'githubClientSecret'
  1024. );
  1025. foreach ($args as $arg) {
  1026. $$arg = !empty($_POST[$arg]) ? $_POST[$arg] : '';
  1027. }
  1028. if (!ctype_alnum($name)) {
  1029. die(json_encode(array('error' => "The name of the project can only contain letters (A-Z) and numbers (0-9). Please review and try again.")));
  1030. }
  1031. $repository = $name;
  1032. if ($project->getIdFromName($name)) {
  1033. die(json_encode(array('error' => "Project with the same name already exists!")));
  1034. }
  1035. $project->setName($name);
  1036. $project->setDescription($description);
  1037. $project->setWebsite($website);
  1038. $project->setContactInfo($user->getUsername());
  1039. $project->setOwnerId($userId);
  1040. $project->setActive(true);
  1041. $project->setLogo($logo);
  1042. if ($checkGitHub == 'true') {
  1043. $project->setRepo_type('git');
  1044. $project->setRepository($github_repo_url);
  1045. if ($defaultGithubApp == 'false') {
  1046. $project->setGithubId($githubClientId);
  1047. $project->setGithubSecret($githubClientSecret);
  1048. }
  1049. } else {
  1050. $project->setRepo_type('svn');
  1051. $project->setRepository($name);
  1052. }
  1053. $project->save();
  1054. $journal_message = '@' . $nick . ' added project *' . $name . '*';
  1055. if (!empty($journal_message)) {
  1056. //sending journal notification
  1057. sendJournalNotification($journal_message);
  1058. }
  1059. echo json_encode(array( 'return' => "Done!"));
  1060. } else {
  1061. echo json_encode(array( 'error' => "You must be logged in to add a new project!"));
  1062. }
  1063. }
  1064. function setFavorite() {
  1065. if ( !isset($_REQUEST['favorite_user_id']) ||
  1066. !isset($_REQUEST['newVal']) ) {
  1067. echo json_encode(array( 'error' => "Invalid parameters!"));
  1068. }
  1069. $userId = getSessionUserId();
  1070. if ($userId > 0) {
  1071. initUserById($userId);
  1072. $user = new User();
  1073. $user->findUserById( $userId );
  1074. $favorite_user_id = (int) $_REQUEST['favorite_user_id'];
  1075. $newVal = (int) $_REQUEST['newVal'];
  1076. $users_favorites = new Users_Favorite();
  1077. $res = $users_favorites->setMyFavoriteForUser($userId, $favorite_user_id, $newVal);
  1078. if ($res == "") {
  1079. // send chat if user has been marked a favorite
  1080. $favorite_user = new User();
  1081. $favorite_user->findUserById($favorite_user_id);
  1082. if ($newVal == 1) {
  1083. $resetUrl = SECURE_SERVER_URL . 'jobs#userid=' . $favorite_user_id ;
  1084. $resetUrl = '<a href="' . $resetUrl . '" title="Your profile">' . $resetUrl . '</a>';
  1085. $data = array();
  1086. $data['link'] = $resetUrl;
  1087. $nick = $favorite_user->getNickname();
  1088. if (! sendTemplateEmail($favorite_user->getUsername(), 'trusted', $data)) {
  1089. error_log("setFavorite: send_email failed on favorite notification");
  1090. }
  1091. // get favourite count
  1092. $count = $users_favorites->getUserFavoriteCount($favorite_user_id);
  1093. if ($count > 0) {
  1094. if ($count == 1) {
  1095. $message = "**{$count}** person";
  1096. } else {
  1097. $message = "**{$count}** people";
  1098. }
  1099. $journal_message = '@' . $nick . ' is now trusted by ' . $message . '!';
  1100. //sending journal notification
  1101. sendJournalNotification(stripslashes($journal_message));
  1102. }
  1103. }
  1104. echo json_encode(array( 'return' => "Trusted saved."));
  1105. } else {
  1106. echo json_encode(array( 'error' => $res));
  1107. }
  1108. } else {
  1109. echo json_encode(array( 'error' => "You must be logged in!"));
  1110. }
  1111. }
  1112. function manageBudget() {
  1113. // Check that this info is requested by a runner
  1114. if (!isset($_SESSION['is_runner']) || $_SESSION['is_runner'] != 1) {
  1115. echo "Error: Unauthorized";
  1116. die;
  1117. }
  1118. // Check a section request is given
  1119. if (!isset($_REQUEST['section'])) {
  1120. echo "No section requested.";
  1121. die;
  1122. }
  1123. $budget_id = 0;
  1124. if (isset($_REQUEST['budget_id'])) {
  1125. $budget_id = (int) $_REQUEST['budget_id'];
  1126. }
  1127. // Check if we've received sorting request
  1128. $sortby = "";
  1129. $desc = "";
  1130. $sort = false;
  1131. if (isset($_REQUEST['sortby']) && isset($_REQUEST['desc'])) {
  1132. switch ($_REQUEST['sortby']) {
  1133. case 'be-id':
  1134. case 'bet-id':
  1135. $sortby = 'id';
  1136. break;
  1137. case 'be-budget':
  1138. $sortby = 'budget_id';
  1139. break;
  1140. case 'bet-budget':
  1141. $sortby = 'budget_title';
  1142. break;
  1143. case 'be-summary':
  1144. $sortby = 'summary';
  1145. break;
  1146. case 'bet-notes':
  1147. $sortby = 'notes';
  1148. break;
  1149. case 'be-who':
  1150. case 'bet-who':
  1151. $sortby = 'who';
  1152. break;
  1153. case 'be-amount':
  1154. case 'bet-amount':
  1155. $sortby = 'amount';
  1156. break;
  1157. case 'be-status':
  1158. $sortby = 'status';
  1159. break;
  1160. case 'be-created':
  1161. case 'bet-created':
  1162. $sortby = 'created';
  1163. break;
  1164. case 'be-paid':
  1165. $sortby = 'paid';
  1166. break;
  1167. }
  1168. $desc = $_REQUEST['desc'];
  1169. $sort = true;
  1170. }
  1171. $section = $_REQUEST['section'];
  1172. if (!isset($_REQUEST['method'])) {
  1173. switch ($section) {
  1174. case 0:
  1175. if ($sort) {
  1176. echo BudgetTools::getAllocated($budget_id, $sortby, $desc);
  1177. } else {
  1178. echo BudgetTools::getAllocated($budget_id);
  1179. }
  1180. break;
  1181. case 1:
  1182. if ($sort) {
  1183. echo BudgetTools::getSubmitted($budget_id, $sortby, $desc);
  1184. } else {
  1185. echo BudgetTools::getSubmitted($budget_id);
  1186. }
  1187. break;
  1188. case 2:
  1189. if ($sort) {
  1190. echo BudgetTools::getPaid($budget_id, $sortby, $desc);
  1191. } else {
  1192. echo BudgetTools::getPaid($budget_id);
  1193. }
  1194. break;
  1195. case 3:
  1196. if ($sort) {
  1197. echo BudgetTools::getTransferred($budget_id, $sortby, $desc);
  1198. } else {
  1199. echo BudgetTools::getTransferred($budget_id);
  1200. }
  1201. break;
  1202. }
  1203. } else {
  1204. if ($_REQUEST['method'] == 'export') {
  1205. // Export to CSV
  1206. switch ($section) {
  1207. case 0:
  1208. $data = json_decode(BudgetTools::getAllocated());
  1209. BudgetTools::exportCSV($data);
  1210. break;
  1211. case 1:
  1212. $data = json_decode(BudgetTools::getSubmitted());
  1213. BudgetTools::exportCSV($data);
  1214. break;
  1215. case 2:
  1216. $data = json_decode(BudgetTools::getPaid());
  1217. BudgetTools::exportCSV($data);
  1218. break;
  1219. case 3:
  1220. $data = json_decode(BudgetTools::getTransferred($budget_id));
  1221. BudgetTools::exportCSV_Transferred($data);
  1222. break;
  1223. }
  1224. }
  1225. }
  1226. }
  1227. function getBidItem() {
  1228. $blankbid = array(
  1229. 'id' => 0,
  1230. 'bidder_id' => 0,
  1231. 'worklist_id' => 0,
  1232. 'email' => '*name hidden*',
  1233. 'bid_amount' => '0',
  1234. 'done_in' => '',
  1235. 'notes' => '',
  1236. );
  1237. $blankjson = json_encode($blankbid);
  1238. $item = isset($_REQUEST['item']) ? (int)$_REQUEST['item'] : 0;
  1239. if ($item == 0) {
  1240. echo $blankjson;
  1241. return;
  1242. }
  1243. $userId = getSessionUserId();
  1244. $user = new User();
  1245. if ($userId > 0) {
  1246. $user = $user->findUserById($userId);
  1247. } else {
  1248. $user->setId(0);
  1249. }
  1250. // Guest or hacking
  1251. if ($user->getId() == 0) {
  1252. echo $blankjson;
  1253. return;
  1254. }
  1255. $bid = new Bid($item);
  1256. if ($bid->id) {
  1257. $workItem = new WorkItem();
  1258. $workItem->conditionalLoadByBidId($item);
  1259. // Runner, item creator, or bidder can see item.
  1260. if ($user->isRunner() || ($user->getId() == $workItem->getCreatorId()) || ($user->getId() == $bid->bidder_id)) {
  1261. $bid->setAnyAccepted($workItem->hasAcceptedBids());
  1262. $row = $bid->toArray();
  1263. $row['notes'] = html_entity_decode($row['notes'], ENT_QUOTES);
  1264. $json = json_encode($row);
  1265. echo $json;
  1266. } else {
  1267. echo $blankjson;
  1268. }
  1269. }
  1270. }
  1271. function getBonusHistory() {
  1272. checkLogin();
  1273. if (empty($_SESSION['is_runner'])) {
  1274. die(json_encode(array()));
  1275. }
  1276. $limit = 7;
  1277. $page = (int) $_REQUEST['page'];
  1278. $rid = (int) $_REQUEST['rid'];
  1279. $uid = (int) $_REQUEST['uid'];
  1280. $where = 'AND `'.FEES.'`.`payer_id` = ' . $uid;
  1281. // Add option for order results
  1282. $orderby = "ORDER BY `".FEES."`.`date` DESC";
  1283. $qcnt = "SELECT count(*)";
  1284. $qsel = "SELECT DATE_FORMAT(`date`, '%m-%d-%Y') as date,
  1285. `amount`,
  1286. `nickname`,
  1287. `desc`";
  1288. $qbody = " FROM `".FEES."`
  1289. LEFT JOIN `".USERS."` ON `".USERS."`.`id` = `".FEES."`.`user_id`
  1290. WHERE `bonus` = 1 AND `amount` != 0 $where ";
  1291. $qorder = "$orderby LIMIT " . ($page - 1) * $limit . ",$limit";
  1292. $rtCount = mysql_query("$qcnt $qbody");
  1293. if ($rtCount) {
  1294. $row = mysql_fetch_row($rtCount);
  1295. $items = intval($row[0]);
  1296. } else {
  1297. $items = 0;
  1298. die(json_encode(array()));
  1299. }
  1300. $cPages = ceil($items/$limit);
  1301. $report = array(array($items, $page, $cPages));
  1302. // Construct json for history
  1303. $rtQuery = mysql_query("$qsel $qbody $qorder");
  1304. for ($i = 1; $rtQuery && $row = mysql_fetch_assoc($rtQuery); $i++) {
  1305. $report[$i] = array($row['date'],
  1306. $row['amount'],
  1307. $row['nickname'],
  1308. $row['desc']);
  1309. }
  1310. $json = json_encode($report);
  1311. echo $json;
  1312. }
  1313. function getCodeReviewStatus() {
  1314. $id = (int) $_REQUEST['workitemid'];
  1315. $query = "
  1316. SELECT id, code_reviewer_id, code_review_started, code_review_completed
  1317. FROM " . WORKLIST . "
  1318. WHERE id = '" . $id . "'";
  1319. $result = mysql_query($query);
  1320. $data = array();
  1321. while ($result && $row=mysql_fetch_assoc($result)) {
  1322. $data[] = $row;
  1323. }
  1324. echo json_encode($data);
  1325. }
  1326. function getFeeItem() {
  1327. $item = isset($_REQUEST["item"]) ? intval($_REQUEST["item"]) : 0;
  1328. if (empty($item))
  1329. return;
  1330. $query = "SELECT id, paid, notes FROM ".FEES." WHERE ".FEES.".id='{$item}'";
  1331. $rt = mysql_query($query);
  1332. $row = mysql_fetch_assoc($rt);
  1333. $json = json_encode(array($row['id'], $row['paid'], $row['notes']));
  1334. echo $json;
  1335. }
  1336. function getFeeSums() {
  1337. $sum = Fee::getSums(isset($_GET["type"]) ? $_GET["type"] : '');
  1338. echo json_encode($sum);
  1339. }
  1340. function getJobInformation() {
  1341. $page=isset($_REQUEST["page"]) ? intval($_REQUEST["page"]) : 1; //Get the page number to show, set default to 1
  1342. $workitem = new WorkItem();
  1343. $userId = getSessionUserId();
  1344. if( $userId > 0 ) {
  1345. initUserById($userId);
  1346. $user = new User();
  1347. $user->findUserById( $userId );
  1348. }
  1349. if ($user->getId() > 0 ) {
  1350. $args = array( 'itemid');
  1351. foreach ($args as $arg) {
  1352. if(!empty($_POST[$arg])) {
  1353. $$arg=$_POST[$arg];
  1354. } else {
  1355. $$arg='';
  1356. }
  1357. }
  1358. if (!empty($itemid)) {
  1359. try {
  1360. $workitem->loadById($itemid);
  1361. $summary= "#". $workitem->getId()." - ". $workitem->getSummary();
  1362. } catch(Exception $e) {
  1363. //Item id doesnt exist
  1364. $summary="";
  1365. }
  1366. } else {
  1367. $summary='';
  1368. }
  1369. $returnString=$summary;
  1370. } else {
  1371. echo json_encode(array('error' => "Invalid parameters !"));
  1372. return;
  1373. }
  1374. echo json_encode(array('returnString' => $returnString));
  1375. }
  1376. function getMultipleBidList() {
  1377. $job_id = isset($_REQUEST['job_id']) ? (int) $_REQUEST['job_id'] : 0;
  1378. if ($job_id == 0) {
  1379. echo $job_id;
  1380. return;
  1381. }
  1382. $workItem = new WorkItem();
  1383. $bids = $workItem->getBids($job_id);
  1384. $ret = array();
  1385. foreach($bids as $bid) {
  1386. $bid['expired'] = $bid['expires'] <= BID_EXPIRE_WARNING;
  1387. $bid['expires_text'] = relativeTime($bid['expires'] , false, false, false, false);
  1388. $ret[] = $bid;
  1389. }
  1390. echo json_encode(array('bids' => $ret));
  1391. return;
  1392. }
  1393. function getProjects() {
  1394. // Create project object
  1395. $projectHandler = new Project();
  1396. // page 1 is "all active projects"
  1397. $page = isset($_REQUEST['page']) ? (int) $_REQUEST['page'] : 1;
  1398. // for subsequent pages, which will be inactive projects, return 10 at a time
  1399. if ($page > 1) {
  1400. // Define values for sorting a display
  1401. $limit = 10;
  1402. // Get listing of all inactive projects
  1403. $projectListing = $projectHandler->getProjects(false, array(), true);
  1404. // Create content for each page
  1405. // Select projects that match the letter chosen and construct the array for
  1406. // the selected page
  1407. $pageFinish = $page * $limit;
  1408. $pageStart = $pageFinish - ($limit - 1);
  1409. // leaving 'letter' filter in place for the time being although the UI is not supporting it
  1410. $letter = isset($_REQUEST["letter"]) ? trim($_REQUEST["letter"]) : "all";
  1411. if($letter == "all") {
  1412. $letter = ".*";
  1413. } else if ($letter == "_") { //numbers
  1414. $letter = "[^A-Za-z]";
  1415. }
  1416. // Count total number of active projects
  1417. $activeProjectsCount = count($projectListing);
  1418. if ($projectListing != null) {
  1419. foreach ($projectListing as $key => $value) {
  1420. if (preg_match("/^$letter/i", $value["name"])) {
  1421. $selectedProjects[] = $value;
  1422. }
  1423. }
  1424. // Count number of projects to display
  1425. $projectsToDisplay = count($selectedProjects);
  1426. // Determine total number of pages
  1427. $displayPages = ceil($projectsToDisplay / $limit);
  1428. // Construct json for pagination
  1429. // $projectsOnPage = array(array($projectsToDisplay, $page, $displayPages));
  1430. $projectsOnPage = array();
  1431. // Select projects for current page
  1432. $i = $pageStart - 1;
  1433. while ($i < $pageFinish) {
  1434. if (isset($selectedProjects[$i])) {
  1435. $projectsOnPage[] = $selectedProjects[$i];
  1436. }
  1437. $i++;
  1438. }
  1439. }
  1440. } else {
  1441. // Get listing of active projects
  1442. $projectsOnPage = $projectHandler->getProjects(true);
  1443. usort($projectsOnPage, function($a, $b) {
  1444. if ( $b["bCount"] < $a["bCount"] ) return -1;
  1445. if ( $b["bCount"] > $a["bCount"] ) return 1;
  1446. if ( $b["cCount"] < $a["cCount"] ) return -1;
  1447. if ( $b["cCount"] > $a["cCount"] ) return 1;
  1448. if ( $b["feesCount"] > $a["feesCount"] ) return -1;
  1449. if ( $b["feesCount"] < $a["feesCount"] ) return 1;
  1450. return 0;
  1451. });
  1452. }
  1453. // Prepare data for printing in projects
  1454. $json = json_encode($projectsOnPage);
  1455. echo $json;
  1456. }
  1457. function getReport() {
  1458. $limit = 30;
  1459. $_REQUEST['name'] = '.reports';
  1460. $filter = new Agency_Worklist_Filter($_REQUEST);
  1461. $from_date = mysql_real_escape_string($filter->getStart());
  1462. $to_date = mysql_real_escape_string($filter->getEnd());
  1463. $paidStatus = $filter->getPaidstatus();
  1464. $page = $filter->getPage();
  1465. $w2_only = (int) $_REQUEST['w2_only'];
  1466. $dateRangeFilter = '';
  1467. if (isset($from_date) || isset($to_date)) {
  1468. $mysqlFromDate = GetTimeStamp($from_date);
  1469. $mysqlToDate = GetTimeStamp($to_date);
  1470. $dateRangeFilter = " AND DATE(`date`) BETWEEN '".$mysqlFromDate."' AND '".$mysqlToDate."'" ;
  1471. }
  1472. $w2Filter = '';
  1473. if ($w2_only) {
  1474. $w2Filter = " AND " . USERS . ".`has_w2` = 1";
  1475. }
  1476. $paidStatusFilter = '';
  1477. if (isset($paidStatus) && ($paidStatus) !="ALL") {
  1478. $paidStatus= mysql_real_escape_string($paidStatus);
  1479. $paidStatusFilter = " AND `".FEES."`.`paid` = ".$paidStatus."";
  1480. }
  1481. $sfilter = $filter->getStatus();
  1482. $pfilter = $filter->getProjectId();
  1483. $fundFilter = $filter->getFund_id();
  1484. $ufilter = $filter->getUser();
  1485. $rfilter = $filter->getRunner();
  1486. $order = $filter->getOrder();
  1487. $dir = $filter->getDir();
  1488. $type = $filter->getType();
  1489. $queryType = isset( $_REQUEST['qType'] ) ? $_REQUEST['qType'] :'detail';
  1490. $where = '';
  1491. if ($ufilter) {
  1492. $where = " AND `".FEES."`.`user_id` = $ufilter ";
  1493. }
  1494. if ($rfilter) {
  1495. $where = " AND `".FEES."`.`user_id` = $rfilter AND `" . WORKLIST . "`.runner_id = $rfilter ";
  1496. }
  1497. if ($sfilter){
  1498. if($sfilter != 'ALL') {
  1499. $where .= " AND `" . WORKLIST . "`.status = '$sfilter' ";
  1500. }
  1501. }
  1502. if ($pfilter) {
  1503. // ignore the fund filter?
  1504. if($pfilter != 'ALL') {
  1505. $where .= " AND `" . WORKLIST . "`.project_id = '$pfilter' ";
  1506. } elseif ($fundFilter) {
  1507. $where .= " AND `".PROJECTS."`.`fund_id` = " . $fundFilter;
  1508. }
  1509. } elseif (isset($fundFilter) && $fundFilter != -1) {
  1510. if ($fundFilter == 0) {
  1511. $where .= " AND `".PROJECTS."`.`fund_id` = " . $fundFilter . " || `".PROJECTS."`.`fund_id` IS NULL";
  1512. } else {
  1513. $where .= " AND `".PROJECTS."`.`fund_id` = " . $fundFilter;
  1514. }
  1515. }
  1516. if ($type == 'Fee') {
  1517. $where .= " AND `".FEES."`.expense = 0 AND `".FEES."`.rewarder = 0 AND `".FEES. "`.bonus = 0";
  1518. } else if ($type == 'Expense') {
  1519. $where .= " AND `".FEES."`.expense = 1 AND `".FEES."`.rewarder = 0 AND `".FEES. "`.bonus = 0";
  1520. } else if ($type == 'Bonus') {
  1521. $where .= " AND (rewarder = 1 OR bonus = 1)";
  1522. } else if ($type == 'ALL') {
  1523. $where .= " AND `".FEES."`.expense = 0 AND `".FEES."`.rewarder = 0";
  1524. }
  1525. // Add option for order results
  1526. $orderby = "ORDER BY ";
  1527. switch ($order) {
  1528. case 'date':
  1529. $orderby .= "`".FEES."`.`date`";
  1530. break;
  1531. case 'name':
  1532. case 'payee':
  1533. $orderby .= "`".USERS."`.`nickname`";
  1534. break;
  1535. case 'desc':
  1536. $orderby .= "`".FEES."`.`desc`";
  1537. break;
  1538. case 'summary':
  1539. $orderby .= "`".WORKLIST."`.`summary`";
  1540. break;
  1541. case 'paid_date':
  1542. $orderby .= "`".FEES."`.`paid_date`";
  1543. break;
  1544. case 'id':
  1545. $orderby .= "`".FEES."`.`worklist_id`";
  1546. break;
  1547. case 'fee':
  1548. $orderby .= "`".FEES."`.`amount`";
  1549. break;
  1550. case 'jobs':
  1551. $orderby .= "`jobs`";
  1552. break;
  1553. case 'avg_job':
  1554. $orderby .= "`average`";
  1555. break;
  1556. case 'total_fees':
  1557. $orderby .= "`total`";
  1558. break;
  1559. }
  1560. if ($dateRangeFilter) {
  1561. $where .= $dateRangeFilter;
  1562. }
  1563. if (! empty($w2Filter)) {
  1564. $where .= $w2Filter;
  1565. }
  1566. if ($paidStatusFilter) {
  1567. $where .= $paidStatusFilter;
  1568. }
  1569. if($queryType == "detail") {
  1570. $qcnt = "SELECT count(*)";
  1571. $qsel = "SELECT `".FEES."`.id AS fee_id, DATE_FORMAT(`paid_date`, '%m-%d-%Y') AS paid_date,`worklist_id`,`".WORKLIST."`.`summary` AS `summary`,`desc`,`status`,`".USERS."`.`nickname` AS `payee`,`".FEES."`.`amount`, `".USERS."`.`paypal` AS `paypal`, `expense` AS `expense`,`rewarder` AS `rewarder`,`bonus` AS `bonus`, `" . USERS . "`.`has_W2` AS `has_W2`";
  1572. $qsum = "SELECT SUM(`amount`) as page_sum FROM (SELECT `amount` ";
  1573. $qbody = " FROM `".FEES."`
  1574. LEFT JOIN `".WORKLIST."` ON `".WORKLIST."`.`id` = `".FEES."`.`worklist_id`
  1575. LEFT JOIN `".USERS."` ON `".USERS."`.`id` = `".FEES."`.`user_id`
  1576. LEFT JOIN ".PROJECTS." ON `".WORKLIST."`.`project_id` = `".PROJECTS."`.`project_id`
  1577. WHERE `amount` != 0 AND `".FEES."`.`withdrawn` = 0 $where ";
  1578. $qorder = "$orderby $dir, `status` ASC, `worklist_id` ASC LIMIT " . ($page - 1) * $limit . ",$limit";
  1579. $rtCount = mysql_query("$qcnt $qbody");
  1580. if ($rtCount) {
  1581. $row = mysql_fetch_row($rtCount);
  1582. $items = intval($row[0]);
  1583. } else {
  1584. $items = 0;
  1585. die(json_encode(array()));
  1586. }
  1587. $cPages = ceil($items/$limit);
  1588. $qPageSumClose = "$orderby $dir, `status` ASC, `worklist_id` ASC LIMIT " . ($page - 1) * $limit . ", $limit ) fee_sum ";
  1589. $sumResult = mysql_query("$qsum $qbody $qPageSumClose");
  1590. if ($sumResult) {
  1591. $get_row = mysql_fetch_row($sumResult);
  1592. $pageSum = $get_row[0];
  1593. } else {
  1594. $pageSum = 0;
  1595. }
  1596. $qGrandSumClose = "ORDER BY `".USERS."`.`nickname` ASC, `status` ASC, `worklist_id` ASC ) fee_sum ";
  1597. $grandSumResult = mysql_query("$qsum $qbody $qGrandSumClose");
  1598. if ($grandSumResult) {
  1599. $get_row = mysql_fetch_row($grandSumResult);
  1600. $grandSum = $get_row[0];
  1601. } else {
  1602. $grandSum = 0;
  1603. }
  1604. $report = array(array($items, $page, $cPages, $pageSum, $grandSum));
  1605. // Construct json for history
  1606. $rtQuery = mysql_query("$qsel $qbody $qorder");
  1607. for ($i = 1; $rtQuery && $row = mysql_fetch_assoc($rtQuery); $i++) {
  1608. $report[$i] = array($row['worklist_id'], $row['fee_id'], $row['summary'], $row['desc'], $row['payee'], $row['amount'], $row['paid_date'], $row['paypal'],$row['expense'],$row['rewarder'],$row['bonus'],$row['has_W2']);
  1609. }
  1610. $concatR = '';
  1611. if ($row['rewarder'] ==1) {
  1612. $concatR = "R";
  1613. }
  1614. $json = json_encode($report);
  1615. echo $json;
  1616. } else if ($queryType == "chart" ) {
  1617. $fees = array();
  1618. $uniquePeople = array();
  1619. $feeCount = array();
  1620. if(isset($from_date)) {
  1621. $fromDate = ReportTools::getMySQLDate($from_date);
  1622. }
  1623. if(isset($to_date)) {
  1624. $toDate = ReportTools::getMySQLDate($to_date);
  1625. }
  1626. $fromDateTime = mktime(0,0,0,substr($fromDate,5,2), substr($fromDate,8,2), substr($fromDate,0,4));
  1627. $toDateTime = mktime(0,0,0,substr($toDate,5,2), substr($toDate,8,2), substr($toDate,0,4));
  1628. $daysInRange = round( abs($toDateTime-$fromDateTime) / 86400, 0 );
  1629. $rollupColumn = ReportTools::getRollupColumn('`date`', $daysInRange);
  1630. $dateRangeType = $rollupColumn['rollupRangeType'];
  1631. $qbody = " FROM `".FEES."`
  1632. LEFT JOIN `".WORKLIST."` ON `worklist`.`id` = `".FEES."`.`worklist_id`
  1633. LEFT JOIN `".USERS."` ON `".USERS."`.`id` = `".FEES."`.`user_id`
  1634. LEFT JOIN ".PROJECTS." ON `".WORKLIST."`.`project_id` = `".PROJECTS."`.`project_id`
  1635. WHERE `amount` != 0 AND `".FEES."`.`withdrawn` = 0 $where ";
  1636. $qgroup = " GROUP BY fee_date";
  1637. $qcols = "SELECT " . $rollupColumn['rollupQuery'] . " as fee_date, count(1) as fee_count,sum(amount) as total_fees, count(distinct user_id) as unique_people ";
  1638. $res = mysql_query("$qcols $qbody $qgroup");
  1639. if($res && mysql_num_rows($res) > 0) {
  1640. while ($row = mysql_fetch_array($res, MYSQL_ASSOC)) {
  1641. if ($row['fee_count'] >=1 ) {
  1642. $feeCount[$row['fee_date']] = $row['fee_count'];
  1643. $fees[$row['fee_date']] = $row['total_fees'];
  1644. $uniquePeople[$row['fee_date']] = $row['unique_people'];
  1645. }
  1646. }
  1647. }
  1648. $json_data = array('fees' => ReportTools::fillAndRollupSeries($fromDate, $toDate, $fees, false, $dateRangeType),
  1649. 'uniquePeople' => ReportTools::fillAndRollupSeries($fromDate, $toDate, $uniquePeople, false, $dateRangeType),
  1650. 'feeCount' => ReportTools::fillAndRollupSeries($fromDate, $toDate, $feeCount, false, $dateRangeType),
  1651. 'labels' => ReportTools::fillAndRollupSeries($fromDate, $toDate, null, true, $dateRangeType),
  1652. 'fromDate' => $fromDate, 'toDate' => $toDate);
  1653. $json = json_encode($json_data);
  1654. echo $json;
  1655. } else if($queryType == "payee") {
  1656. $payee_report = array();
  1657. $page = $filter->getPage();
  1658. $count_query = " SELECT count(1) FROM ";
  1659. $query = " SELECT `nickname` AS payee_name, count(1) AS jobs, sum(`amount`) / count(1) AS average, sum(`amount`) AS total FROM `".FEES."`
  1660. LEFT JOIN `".USERS."` ON `".FEES."`.`user_id` = `".USERS."`.`id`
  1661. LEFT JOIN `".WORKLIST."` ON `worklist`.`id` = `".FEES."`.`worklist_id`
  1662. LEFT JOIN ".PROJECTS." ON `".WORKLIST."`.`project_id` = `".PROJECTS."`.`project_id`
  1663. WHERE `".FEES."`.`paid` = 1 ".$where." GROUP BY `user_id` ";
  1664. $result_count = mysql_query($count_query."(".$query.") AS payee_name");
  1665. if ($result_count) {
  1666. $count_row = mysql_fetch_row($result_count);
  1667. $items = intval($count_row[0]);
  1668. } else {
  1669. $items = 0;
  1670. die(json_encode(array()));
  1671. }
  1672. $countPages = ceil($items/$limit);
  1673. $payee_report[] = array($items, $page, $countPages);
  1674. if(!empty($_REQUEST['defaultSort']) && $_REQUEST['defaultSort'] == 'total_fees') {
  1675. $query .= " ORDER BY total DESC";
  1676. } else {
  1677. $query .= $orderby." ".$dir;
  1678. }
  1679. $query .= " LIMIT " . ($page - 1) * $limit . ",$limit";
  1680. $result = mysql_query($query);
  1681. if($result && mysql_num_rows($result) > 0) {
  1682. while ($row = mysql_fetch_array($result, MYSQL_ASSOC)) {
  1683. $payee_name = $row['payee_name'];
  1684. $jobs = $row['jobs'];
  1685. $total = number_format($row['total'], 2, '.', '');
  1686. $average = number_format($row['average'], 2, '.', '');
  1687. $payee_report[] = array($payee_name, $jobs, $average, $total);
  1688. }
  1689. }
  1690. echo json_encode($payee_report);
  1691. }
  1692. }
  1693. function getSkills() {
  1694. $query = "SELECT `skill` FROM ".SKILLS." ORDER BY skill";
  1695. $result = mysql_query($query);
  1696. $data = array();
  1697. while ($result && $row=mysql_fetch_assoc($result)) {
  1698. $data[] = $row['skill'];
  1699. }
  1700. echo json_encode($data);
  1701. }
  1702. function getUserItem() {
  1703. $req = isset($_REQUEST['req'])? $_REQUEST['req'] : 'item';
  1704. if( $req == 'id' ) {
  1705. // Convert Nickname to User ID
  1706. $author = $_REQUEST['nickname'];
  1707. $rt = mysql_query("SELECT id FROM ".USERS." WHERE nickname='$author'");
  1708. $row = mysql_fetch_assoc($rt);
  1709. $json_array = array();
  1710. foreach( $row as $item ) {
  1711. $json_array[] = $item;
  1712. }
  1713. echo json_encode( $json_array );
  1714. } else if ( $req == 'item' ) {
  1715. $item = isset($_REQUEST["item"]) ? intval($_REQUEST["item"]) : 0;
  1716. if ( empty($item) ) {
  1717. return;
  1718. }
  1719. $query = "SELECT id, nickname,username,about,contactway,payway,skills,timezone,DATE_FORMAT(added, '%m/%d/%Y'),is_runner,is_payer
  1720. FROM ".USERS." WHERE id= $item";
  1721. $rt = mysql_query($query);
  1722. $row = mysql_fetch_assoc($rt);
  1723. $json_row = array();
  1724. foreach($row as $item){
  1725. $json_row[] = $item;
  1726. }
  1727. //changing timezone to human-readable
  1728. if( $json_row[7] ) {
  1729. $json_row[7] = $timezoneTable[$json_row[7]];
  1730. }
  1731. $json = json_encode($json_row);
  1732. echo $json;
  1733. }
  1734. }
  1735. function getUserItems() {
  1736. $userId = isset($_REQUEST["id"]) ? intval($_REQUEST["id"]) : 0;
  1737. if (empty($userId))
  1738. return;
  1739. $query = "SELECT `" . WORKLIST . "`.`id`, `summary`, `bid_amount`, `bid_done`,"
  1740. . " TIMESTAMPDIFF(SECOND, NOW(), `" . BIDS . "`.`bid_done`) AS `future_delta` FROM `" . WORKLIST . "`"
  1741. . " LEFT JOIN `" . BIDS . "` ON `bidder_id` = `mechanic_id`"
  1742. . " AND `" . BIDS . "`.`accepted`= 1 AND `" . BIDS . "`.`withdrawn`= 0 AND `worklist_id` = `" . WORKLIST . "`.`id`"
  1743. . " WHERE `mechanic_id` = $userId AND status = 'Working'";
  1744. $rt = mysql_query($query);
  1745. $items = array();
  1746. while($row = mysql_fetch_assoc($rt)){
  1747. $row['relative'] = relativeTime($row['future_delta']);
  1748. $items[] = $row;
  1749. }
  1750. $json = json_encode($items);
  1751. echo $json;
  1752. }
  1753. function getUserList() {
  1754. $limit = 30;
  1755. $page = isset($_REQUEST["page"])?intval($_REQUEST["page"]) : 1;
  1756. $letter = isset($_REQUEST["letter"]) ? mysql_real_escape_string(trim($_REQUEST["letter"])) : "";
  1757. $order = !empty($_REQUEST["order"]) ? mysql_real_escape_string(trim($_REQUEST["order"])) : "earnings30";
  1758. $order_dir = isset($_REQUEST["order_dir"]) ? mysql_real_escape_string(trim($_REQUEST["order_dir"])) : "DESC";
  1759. $active = isset( $_REQUEST['active'] ) && $_REQUEST['active'] == 'TRUE' ? 'TRUE' : 'FALSE';
  1760. $myfavorite = isset( $_REQUEST['myfavorite'] ) && $_REQUEST['myfavorite'] == 'TRUE' ? 'TRUE' : 'FALSE';
  1761. $sfilter = $_REQUEST['sfilter'];
  1762. if($letter == "all"){
  1763. $letter = ".*";
  1764. }
  1765. if($letter == "0-9"){ //numbers
  1766. $letter = "[^A-Za-z]";
  1767. }
  1768. $userid = $_SESSION['userid'];
  1769. $myfavorite_cond = '';
  1770. if ($userid > 0 && $myfavorite == 'TRUE') {
  1771. $myfavorite_cond = 'AND (SELECT COUNT(*) FROM `' . USERS_FAVORITES . "` uf WHERE uf.`user_id`=$userid AND uf.`favorite_user_id`=`" . USERS . "`.`id` AND uf.`enabled` = 1) > 0";
  1772. }
  1773. if( $active == 'FALSE' ) {
  1774. $rt = mysql_query("SELECT COUNT(*) FROM `".USERS."` WHERE `nickname` REGEXP '^$letter' AND `is_active` = 1 $myfavorite_cond");
  1775. $row = mysql_fetch_row($rt);
  1776. $users = intval($row[0]);
  1777. } else if( $active == 'TRUE' ) {
  1778. $rt = mysql_query("
  1779. SELECT COUNT(*) FROM `".USERS."`
  1780. LEFT JOIN (SELECT `user_id`,MAX(`paid_date`) AS `date` FROM `".FEES."` WHERE `paid_date` IS NOT NULL AND `paid` = 1 AND `withdrawn` != 1 GROUP BY `user_id`) AS `dates` ON `".USERS."`.id = `dates`.user_id
  1781. WHERE `date` > DATE_SUB(NOW(), INTERVAL $sfilter DAY) AND `is_active` = 1 AND `nickname` REGEXP '^$letter' $myfavorite_cond");
  1782. $row = mysql_fetch_row($rt);
  1783. $users = intval($row[0]);
  1784. }
  1785. //SELECT `id`, `nickname`,DATE_FORMAT(`added`, '%m/%d/%Y') AS `joined`, `budget`,
  1786. $cPages = ceil($users/$limit);
  1787. if( $active == 'FALSE' ) {
  1788. $query = "
  1789. SELECT `id`, `nickname`,`added` AS `joined`, `budget`,
  1790. IFNULL(`creators`.`count`,0) + IFNULL(`mechanics`.`count`,0) AS `jobs_count`,
  1791. IFNULL(`earnings`.`sum`,0) AS `earnings`,
  1792. IFNULL(`earnings30`.`sum`,0) AS `earnings30`,
  1793. IFNULL(`rewarder`.`sum`,0)AS `rewarder`
  1794. FROM `".USERS."`
  1795. LEFT JOIN (SELECT `mechanic_id`, COUNT(`mechanic_id`) AS `count` FROM `" . WORKLIST . "` WHERE (`status` IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')) GROUP BY `mechanic_id`) AS `mechanics` ON `".USERS."`.`id` = `mechanics`.`mechanic_id`
  1796. LEFT JOIN (SELECT `creator_id`, COUNT(`creator_id`) AS `count` FROM `" . WORKLIST . "` WHERE (`status` IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')) AND `creator_id` != `mechanic_id` GROUP BY `creator_id`) AS `creators` ON `".USERS."`.`id` = `creators`.`creator_id`
  1797. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE $sfilter AND `paid` = 1 AND `withdrawn`=0 AND (`rewarder`=1 OR `bonus`=1) GROUP BY `user_id`) AS `rewarder` ON `".USERS."`.`id` = `rewarder`.`user_id`
  1798. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE $sfilter AND `withdrawn`=0 AND `expense`=0 AND `paid` = 1 AND `paid_date` IS NOT NULL GROUP BY `user_id`) AS `earnings` ON `".USERS."`.`id` = `earnings`.`user_id`
  1799. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE `withdrawn`=0 AND `paid` = 1 AND `paid_date` IS NOT NULL AND `paid_date` > DATE_SUB(NOW(), INTERVAL 30 DAY) AND `expense`=0 GROUP BY `user_id`) AS `earnings30` ON `".USERS."`.`id` = `earnings30`.`user_id`
  1800. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE ($sfilter AND `withdrawn`=0 AND `paid` = 1) AND `expense`=1 GROUP BY `user_id`) AS `expenses_billed` ON `".USERS."`.`id` = `expenses_billed`.`user_id`
  1801. WHERE `nickname` REGEXP '^$letter' AND `is_active` = 1 $myfavorite_cond ORDER BY `$order` $order_dir LIMIT " . ($page-1)*$limit . ",$limit";
  1802. } else if( $active == 'TRUE' ) {
  1803. $query = "
  1804. SELECT `id`, `nickname`,`added` AS `joined`, `budget`,
  1805. IFNULL(`creators`.`count`,0) + IFNULL(`mechanics`.`count`,0) AS `jobs_count`,
  1806. IFNULL(`earnings`.`sum`,0) AS `earnings`,
  1807. IFNULL(`earnings30`.`sum`,0) AS `earnings30`,
  1808. IFNULL(`rewarder`.`sum`,0)AS `rewarder`
  1809. FROM `".USERS."`
  1810. LEFT JOIN (SELECT `user_id`,MAX(`date`) AS `date` FROM `".FEES."` WHERE `paid` = 1 AND `amount` != 0 AND `withdrawn` = 0 AND `expense` = 0 GROUP BY `user_id`) AS `dates` ON `".USERS."`.id = `dates`.user_id
  1811. LEFT JOIN (SELECT `mechanic_id`, COUNT(`mechanic_id`) AS `count` FROM `" . WORKLIST . "` WHERE (`status` IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')) GROUP BY `mechanic_id`) AS `mechanics` ON `".USERS."`.`id` = `mechanics`.`mechanic_id`
  1812. LEFT JOIN (SELECT `creator_id`, COUNT(`creator_id`) AS `count` FROM `" . WORKLIST . "` WHERE (`status` IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')) AND `creator_id` != `mechanic_id` GROUP BY `creator_id`) AS `creators` ON `".USERS."`.`id` = `creators`.`creator_id`
  1813. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE $sfilter AND `paid` = 1 AND `withdrawn`=0 AND (`rewarder`=1 OR `bonus`= 1) GROUP BY `user_id`) AS `rewarder` ON `".USERS."`.`id` = `rewarder`.`user_id`
  1814. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE $sfilter AND `withdrawn`=0 AND `expense`=0 AND `paid` = 1 AND `paid_date` IS NOT NULL GROUP BY `user_id`) AS `earnings` ON `".USERS."`.`id` = `earnings`.`user_id`
  1815. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE `withdrawn`=0 AND `paid` = 1 AND `paid_date` IS NOT NULL AND `paid_date` > DATE_SUB(NOW(), INTERVAL 30 DAY) AND `expense`=0 GROUP BY `user_id`) AS `earnings30` ON `".USERS."`.`id` = `earnings30`.`user_id`
  1816. LEFT JOIN (SELECT `user_id`, SUM(amount) AS `sum` FROM `".FEES."` WHERE ($sfilter AND `withdrawn`=0 AND `paid` = 1) AND `expense`=1 GROUP BY `user_id`) AS `expenses_billed` ON `".USERS."`.`id` = `expenses_billed`.`user_id`
  1817. WHERE `date` > DATE_SUB(NOW(), INTERVAL $sfilter DAY) AND `nickname` REGEXP '^$letter' AND `is_active` = 1 $myfavorite_cond ORDER BY `$order` $order_dir LIMIT " . ($page-1)*$limit . ",$limit";
  1818. }
  1819. $rt = mysql_query($query);
  1820. // Construct json for pagination
  1821. $userlist = array(array($users, $page, $cPages));
  1822. while($row = mysql_fetch_assoc($rt)){
  1823. $userStats = new UserStats($row['id']);
  1824. $user = new User();
  1825. $user->findUserById($row['id']);
  1826. if ($row['budget'] < 1){
  1827. $row['budget'] = 'NONE';
  1828. } else {
  1829. $row['budget'] = '$'.number_format($user->getRemainingFunds(), 0);
  1830. }
  1831. $row['earnings'] = $userStats->getTotalEarnings();
  1832. $diffseconds = strtotime($row['joined']);
  1833. $row['joined'] = formatableRelativeTime($diffseconds,2);
  1834. $userlist[] = $row;
  1835. }
  1836. $json = json_encode($userlist);
  1837. echo $json;
  1838. }
  1839. function getUsersList() {
  1840. $query = "SELECT id, nickname FROM " . USERS . " WHERE 1=1";
  1841. if (isset($_REQUEST['getNicknameOnly'])) {
  1842. $query = "SELECT nickname FROM " . USERS . " WHERE 1=1";
  1843. }
  1844. if (isset($_REQUEST['startsWith']) && !empty($_REQUEST['startsWith'])) {
  1845. $startsWith = $_REQUEST['startsWith'];
  1846. $query .= " AND nickname like '".mysql_real_escape_string($startsWith)."%'";
  1847. }
  1848. $query .= " order by nickname limit 0,10";
  1849. $result = mysql_query($query);
  1850. $data = array();
  1851. while ($result && $row=mysql_fetch_assoc($result)) {
  1852. if ($_REQUEST['getNicknameOnly']) {
  1853. $data[] = $row['nickname'];
  1854. } else {
  1855. $data[] = $row;
  1856. }
  1857. }
  1858. echo json_encode($data);
  1859. }
  1860. function getUserStats() {
  1861. if (isset($_REQUEST['id'])) {
  1862. $userId = (int)$_REQUEST['id'];
  1863. } else {
  1864. die("No id provided");
  1865. }
  1866. $userStats = new UserStats($userId);
  1867. $userStats->setItemsPerPage(9);
  1868. $page = isset($_REQUEST['page']) ? $_REQUEST['page'] : 1;
  1869. switch($_REQUEST['statstype']){
  1870. case 'love':
  1871. echo json_encode($userStats->getTotalLove($page));
  1872. break;
  1873. case 'doneJobs':
  1874. echo json_encode($userStats->getUserItems('Done', $page));
  1875. break;
  1876. case 'activeJobs':
  1877. echo json_encode($userStats->getActiveUserItems(9, $page));
  1878. break;
  1879. case 'reviewJobs':
  1880. echo json_encode($userStats->getUserItems('Review', $page));
  1881. break;
  1882. case 'workingJobs':
  1883. echo json_encode($userStats->getUserItems('Working', $page));
  1884. break;
  1885. case 'completedJobsWithStats':
  1886. echo json_encode($userStats->getCompletedJobsWithStats());
  1887. break;
  1888. case 'completedJobs':
  1889. echo json_encode($userStats->getUserItems('Completed', $page));
  1890. break;
  1891. case 'latest_earnings':
  1892. echo json_encode($userStats->getLatestEarningsJobs(30, $page));
  1893. break;
  1894. case 'following':
  1895. echo json_encode($userStats->getFollowingJobs($page));
  1896. break;
  1897. case 'runnerTotalJobs':
  1898. echo json_encode($userStats->getTotalRunnerItems($page));
  1899. break;
  1900. case 'runnerActiveJobs':
  1901. echo json_encode($userStats->getActiveRunnerItems($page));
  1902. break;
  1903. case 'project_history':
  1904. $projectId = $_REQUEST['project_id'];
  1905. echo json_encode($userStats->getUserItemsForASpecificProject('Done', $projectId));
  1906. break;
  1907. case 'counts':
  1908. setlocale(LC_MONETARY,'en_US');
  1909. $_totalEarnings = $userStats->getTotalEarnings();
  1910. $_bonusPayments = $userStats->getBonusPaymentsTotal();
  1911. $ajaxTotalEarnings = preg_replace('/\.[0-9]{2,}$/','',money_format('%n',round($_totalEarnings)));
  1912. $ajaxLatestEarnings = preg_replace('/\.[0-9]{2,}$/','',money_format('%n',$userStats->getLatestEarnings(30)));
  1913. $bonus = preg_replace('/\.[0-9]{2,}$/','',money_format('%n',round($_bonusPayments)));
  1914. $_bonusPercent = round((($_bonusPayments + 0.00000001) / ($_totalEarnings + 0.000001)) * 100,2);
  1915. echo json_encode(array(
  1916. 'total_jobs' => $userStats->getTotalJobsCount(),
  1917. 'active_jobs' => $userStats->getActiveJobsCount(),
  1918. 'total_earnings' => $ajaxTotalEarnings,
  1919. 'latest_earnings' => $ajaxLatestEarnings,
  1920. 'bonus_total' => $bonus,
  1921. 'bonus_percent' => $_bonusPercent.'%'
  1922. ));
  1923. break;
  1924. }
  1925. }
  1926. function getWorkitem() {
  1927. $userId = isset($_SESSION['userid'])? $_SESSION['userid'] : 0;
  1928. $item = isset($_REQUEST["item"]) ? intval($_REQUEST["item"]) : 0;
  1929. if (empty($item))
  1930. return;
  1931. $query = "SELECT
  1932. w.id,
  1933. w.summary,
  1934. c.nickname creator,
  1935. w.status job_status,
  1936. w.notes,
  1937. p.name project,
  1938. r.nickname runner,
  1939. m.nickname mechanic
  1940. FROM ".WORKLIST." w
  1941. LEFT JOIN " . USERS . " c ON w.creator_id = c.id
  1942. LEFT JOIN " . USERS . " r ON w.runner_id = r.id
  1943. LEFT JOIN " . USERS . " m ON w.mechanic_id = m.id
  1944. LEFT JOIN ".PROJECTS." p ON w.project_id = p.project_id
  1945. WHERE w.id = '$item'
  1946. AND (w.status <> 'Draft' OR (w.status = 'Draft' AND w.creator_id = '$userId'))";
  1947. $rt = mysql_query($query);
  1948. if ($rt) {
  1949. $row = mysql_fetch_assoc($rt);
  1950. $row['notes'] = truncateText($row['notes']);
  1951. $query1 = ' SELECT c.comment, u.nickname '
  1952. . ' FROM ' . COMMENTS . ' AS c '
  1953. . ' INNER JOIN ' . USERS . ' AS u ON c.user_id = u.id '
  1954. . ' WHERE c.worklist_id = ' . $row['id']
  1955. . ' ORDER BY c.id DESC '
  1956. . ' LIMIT 1';
  1957. $rtc = mysql_query($query1);
  1958. if ($rt) {
  1959. $rowc = mysql_fetch_assoc($rtc);
  1960. $row['comment'] = truncateText($rowc['comment']);
  1961. $row['commentAuthor'] = $rowc['nickname'];
  1962. } else {
  1963. $row['comment'] = 'No comments yet.';
  1964. }
  1965. $json = json_encode($row);
  1966. } else {
  1967. $json = json_encode(array('error' => "No data available"));
  1968. }
  1969. echo $json;
  1970. }
  1971. function getWorklist() {
  1972. // Test for a string containing 0 characters of anything other than 0-9 and #
  1973. // After a quick trim ofcourse! :)
  1974. // I know regex is usually the bad first stop, but there would be no back tracking in this
  1975. // particular regular expression
  1976. if (preg_match("/^\#?\d+$/", $query = trim($_REQUEST['query']))) {
  1977. // if we reach here, include workitem package, autoloaded (hans)
  1978. $workitem = new WorkItem();
  1979. if ($workitem->idExists($id = ltrim($query, '#'))) {
  1980. $obj = array('redirect',$id);
  1981. die(JSON_encode($obj));
  1982. }
  1983. // if we're not dead continue on!
  1984. }
  1985. $limit = 30;
  1986. $_REQUEST['name'] = '.worklist';
  1987. $filter = new Agency_Worklist_Filter($_REQUEST);
  1988. $is_runner = !empty( $_SESSION['is_runner'] ) ? 1 : 0;
  1989. $userId = isset($_SESSION['userid'])? $_SESSION['userid'] : 0;
  1990. $currentUser = new User($userId);
  1991. $sfilter = explode('/', $filter->getStatus());
  1992. $ufilter = $filter->getUser();
  1993. $pfilter = !empty($_POST['project_id']) ? $_POST['project_id'] : $filter->getProjectId();
  1994. $cfilter = !empty($_POST['inComment']) ? $_POST['inComment'] : $filter->getInComment();
  1995. $ofilter = $filter->getSort();
  1996. $subofilter = $filter->getSubSort();
  1997. $dfilter = $filter->getDir();
  1998. $page = $filter->getPage();
  1999. $where = '';
  2000. $mobile_filter = isset($_POST['mobile']) ? ($_POST['mobile'] == 'true') : false;
  2001. // Status filter
  2002. if ($sfilter) {
  2003. $where = "WHERE (";
  2004. foreach ($sfilter as $val) {
  2005. $val = mysql_real_escape_string($val);
  2006. if (($val == 'ALL' || $val == '') && !$is_runner) {
  2007. /**
  2008. * if current user is not a runner and is filtering by ALL
  2009. * status it wont fetch workitems in DRAFT status
  2010. */
  2011. $where .= "1 AND status != 'Draft' ";
  2012. if (! empty($ufilter) && $ufilter != 'ALL') {
  2013. $where .= " AND (IF(status = 'Bidding', IF(`fees`.user_id = $ufilter, 0, 1), 1)) OR ";
  2014. } else {
  2015. $where .= " OR ";
  2016. }
  2017. }
  2018. if (($val == 'ALL' || $val == '') && $is_runner == 1 ){
  2019. /**
  2020. * if current user is a runner and is filtering by ALL status
  2021. * it wont fetch workitems in DRAFT status created by any other
  2022. * user
  2023. */
  2024. $where .= "1 AND status != 'Draft' OR (status = 'Draft' AND creator_id = $userId) OR ";
  2025. }
  2026. if ($val == 'Draft'){
  2027. /**
  2028. * if filtering by DRAFT status will only fetch workitems in
  2029. * DRAFT status created by current user
  2030. */
  2031. $where .= "(status = 'Draft' AND creator_id = $userId) OR ";
  2032. } else {
  2033. if ($val == 'Bidding') {
  2034. /**
  2035. * runner can see all
  2036. */
  2037. if ($is_runner || $mobile_filter) {
  2038. $where .= "(status = '$val') OR ";
  2039. } else if ($ufilter != 'ALL') {
  2040. /**
  2041. * if bidding, and user filter is not set to all users,
  2042. * we need to check that logged in user is the bidder
  2043. * otherwise we reveal other user's tasks they are
  2044. * bidding on
  2045. */
  2046. $where .= "(status = 'Bidding' AND ((`" . WORKLIST . "`.`id` in (SELECT `worklist_id` ";
  2047. $where .= "FROM `" . BIDS . "` where `bidder_id` = '$userId' AND status = 'Bidding')) OR runner_id = $userId)) OR ";
  2048. } else {
  2049. $where .= "status = '$val' OR ";
  2050. }
  2051. } else if ($val == 'Code Review') {
  2052. $where .= "status = 'Review' OR ";
  2053. } else if ($val == 'Needs-Review') {
  2054. $where .= "(status = 'Review' AND code_review_started = 0) OR ";
  2055. } else if ($val != 'ALL') {
  2056. /**
  2057. * if filtering by any status different than ALL and (DRAFT, BIDDING) it
  2058. * won't do any magic
  2059. */
  2060. $where .= "status = '$val' OR ";
  2061. } else {
  2062. $where .= "status = '$val' OR ";
  2063. }
  2064. }
  2065. }
  2066. $where .= "0)";
  2067. }
  2068. // User filter
  2069. if (!empty($ufilter) && $ufilter != 'ALL') {
  2070. if (empty($where)) {
  2071. $where = "WHERE (";
  2072. } else {
  2073. $where .= " AND (";
  2074. }
  2075. $severalStatus = "";
  2076. foreach ($sfilter as $val) {
  2077. if ($val == 'ALL') {
  2078. $status_cond = "";
  2079. } else {
  2080. $status_cond = "status='$val' AND";
  2081. }
  2082. if ($val == 'Bidding' && $mobile_filter) {
  2083. $where .= $severalStatus . "( $status_cond 1)";
  2084. } else if ($is_runner && $val == 'Bidding' || $val == 'SuggestedWithBid' && $ufilter == $userId) {
  2085. /**
  2086. * If current user is a runner and filtering for himself and
  2087. * (BIDDING or SwB) status then fetch all workitems where he
  2088. * is mechanic, runner, creator or has bids.
  2089. */
  2090. $where .= $severalStatus .
  2091. "( $status_cond (`mechanic_id` = '$ufilter' OR `runner_id` = '$ufilter' OR `creator_id` = '$ufilter'
  2092. OR `" . WORKLIST . "`.`id` in (SELECT `worklist_id` FROM `" . BIDS . "` where `bidder_id` = '$ufilter')
  2093. ))";
  2094. } else if ((!$is_runner && $val == 'Bidding' || $val == 'SuggestedWithBid' && $ufilter == $userId)) {
  2095. /**
  2096. * If current user is a runner and filtering for certain user and
  2097. * (BIDDING or SwB) status then fetch all workitems where selected
  2098. * user is runner, creator or has bids.
  2099. */
  2100. $where .= $severalStatus . "( $status_cond ( `runner_id` = '$ufilter' OR `creator_id` = '$ufilter'
  2101. OR `" . WORKLIST . "`.`id` in (SELECT `worklist_id` FROM `" . BIDS . "` where `bidder_id` = '$ufilter')
  2102. ))";
  2103. } else if (($val == 'Bidding' || $val == 'SuggestedWithBid') && $ufilter != $userId) {
  2104. /**
  2105. * If current user is not a runner and is filtering for certain user
  2106. * and (BIDDING or SwB) status then fetch all workitems where selected
  2107. * user is mechanic, runner or creator.
  2108. */
  2109. $where .= $severalStatus . "( $status_cond ( mechanic_id='$ufilter' OR `runner_id` = '$ufilter' OR creator_id='$ufilter'))";
  2110. } else if ($val == 'Working' || $val =='Review' || $val =='Functional' || $val =='Completed') {
  2111. /**
  2112. * If current user is filtering for any user (himself or not) and
  2113. * (WORKING or REVIEW or FUNCTIONAL or COMPLETED) status then fetch
  2114. * all workitems where selected user is mechanic, creator or runner.
  2115. */
  2116. $where .= $severalStatus . "( $status_cond ( mechanic_id='$ufilter' OR `creator_id`='$ufilter' OR `runner_id` = '$ufilter'))";
  2117. } else {
  2118. /**
  2119. * If current user is filtering for any user (himself or not) and
  2120. * didn't match above cases (filtering ALL or any other status
  2121. * different than BIDDING, SwB, WORKING, REVIEW, FUNCTIONAL and
  2122. * COMPLETED) then fetch all workitems where selected user is
  2123. * creator, runner, mechanic, has fees or has bids
  2124. */
  2125. $where .= $severalStatus .
  2126. "( $status_cond (`creator_id` = '$ufilter' OR `runner_id` = '$ufilter' OR `mechanic_id` = '$ufilter'
  2127. OR (`" . FEES . "`.user_id = '$ufilter' AND status != 'Bidding')
  2128. OR `" . WORKLIST . "`.`id` in (SELECT `worklist_id` FROM `" . BIDS . "` where `bidder_id` = '$ufilter' AND status != 'Bidding')
  2129. ))";
  2130. }
  2131. $severalStatus = " OR ";
  2132. }
  2133. $where .= ')';
  2134. }
  2135. // Project filter
  2136. if (!empty($pfilter) && $pfilter != 'All') {
  2137. if (empty($where)) {
  2138. $where = "WHERE ";
  2139. } else {
  2140. $where .= " AND ";
  2141. }
  2142. $where .= " `".WORKLIST."`.`project_id` = '{$pfilter}' ";
  2143. }
  2144. $query = $filter->getQuery();
  2145. $commentsjoin ="";
  2146. if($query!='' && $query!='Search...') {
  2147. $searchById = false;
  2148. if(is_numeric(trim($query))) {
  2149. $rt = mysql_query("select count(*) from ".WORKLIST." LEFT JOIN `".FEES."` ON `".WORKLIST."`.`id` = `".FEES."`.`worklist_id` $where AND `".WORKLIST."`.`id` = " .$query);
  2150. $row = mysql_fetch_row($rt);
  2151. $rowCount = intval($row[0]);
  2152. if($rowCount >0)
  2153. {
  2154. $searchById = true;
  2155. $where .= " AND `". WORKLIST ."`.`id` = " . $query;
  2156. }
  2157. }
  2158. if(!$searchById) {
  2159. // #11500
  2160. // INPUT: 'one OR two three' ;
  2161. // RESULT: 'one two,three' ;
  2162. // split the query into an array using space as delimiter
  2163. // remove empty elements
  2164. // convert spaces into commas
  2165. // change ',OR,' into space
  2166. $query = preg_replace('/,OR,/', ' ', implode(',', array_filter(explode(' ', $query)))) ;
  2167. $array=explode(",",rawurldecode($query));
  2168. $commentPart = "";
  2169. foreach ($array as $item) {
  2170. $item = mysql_escape_string($item);
  2171. if ($cfilter == 1) {
  2172. $commentPart = " OR MATCH (`com`.`comment`) AGAINST ('$item')";
  2173. }
  2174. $where .= " AND ( MATCH (summary, `" . WORKLIST . "`.`notes`) AGAINST ('$item')OR MATCH (`" . FEES .
  2175. "`.notes) AGAINST ('$item') OR MATCH (`ru`.`nickname`) AGAINST ('$item') OR MATCH (`cu`.`nickname`) AGAINST ('$item') OR MATCH (`mu`.`nickname`) AGAINST ('$item') " .
  2176. $commentPart . ") ";
  2177. }
  2178. if ($cfilter == 1) {
  2179. $commentsjoin = "LEFT OUTER JOIN `" . COMMENTS . "` AS `com` ON `" . WORKLIST . "`.`id` = `com`.`worklist_id`";
  2180. }
  2181. }
  2182. }
  2183. // only internal users are allowed to view internal jobs
  2184. if (! $currentUser->isInternal()) {
  2185. $where .= " AND `".WORKLIST."`.is_internal = 0";
  2186. }
  2187. $qcnt = "SELECT count(DISTINCT `".WORKLIST."`.`id`)";
  2188. //mega-query with total fees and latest bid for the worklist item
  2189. $qsel = "
  2190. SELECT `".WORKLIST."`.`id`, `summary`,
  2191. (CASE
  2192. WHEN status = 'Review' AND code_review_started = 0 THEN 'Needs Review'
  2193. WHEN status = 'Review' AND code_review_started = 1 AND code_review_completed = 0 THEN 'In Review'
  2194. WHEN status = 'Review' AND code_review_completed = 1 THEN 'Reviewed'
  2195. WHEN status != 'Review' THEN status
  2196. END) `status`,";
  2197. if ($ofilter == 'status') {
  2198. $ofilter = 'status_order';
  2199. $qsel .= "(CASE
  2200. WHEN status = 'Suggested' THEN 1
  2201. WHEN status = 'SuggestedWithBid' THEN 2
  2202. WHEN status = 'Bidding' THEN 3
  2203. WHEN status = 'Working' THEN 4
  2204. WHEN status = 'Functional' THEN 5
  2205. WHEN status = 'SvnHold' THEN 6
  2206. WHEN status = 'Review' THEN 7
  2207. WHEN status = 'Completed' THEN 8
  2208. WHEN status = 'Done' THEN 9
  2209. WHEN status = 'Pass' THEN 10
  2210. END) `status_order`,";
  2211. }
  2212. $qsel .= "
  2213. `bug_job_id` AS `bug_job_id`,
  2214. `cu`.`nickname` AS `creator_nickname`,
  2215. `ru`.`nickname` AS `runner_nickname`,
  2216. `mu`.`nickname` AS `mechanic_nickname`,
  2217. `proj`.`name` AS `project_name`,
  2218. `worklist`.`project_id` AS `project_id`,
  2219. TIMESTAMPDIFF(SECOND, `created`, NOW()) as `delta`,
  2220. SUM(`" . FEES . "`.amount) AS `total_fees`,
  2221. (SELECT `bid_amount`
  2222. FROM `" . BIDS . "`
  2223. WHERE `withdrawn` = 0
  2224. AND (`bid_expires` > NOW()
  2225. OR `bid_expires` = '0000-00-00 00:00:00')
  2226. AND `worklist_id` = `worklist`.`id`
  2227. ORDER BY bid_created DESC LIMIT 1) `bid_amount`,
  2228. `creator_id`, `runner_id`, `mechanic_id`,
  2229. (SELECT COUNT(`".BIDS."`.`id`) FROM `".BIDS."`
  2230. WHERE `".BIDS."`.`worklist_id` = `".WORKLIST."`.`id` AND (`".BIDS."`.`withdrawn` = 0) AND (NOW() < `".BIDS."`.`bid_expires` OR `bid_expires`='0000-00-00 00:00:00') LIMIT 1) as bid_count,
  2231. TIMESTAMPDIFF(SECOND,NOW(), (SELECT `".BIDS."`.`bid_done` FROM `".BIDS."`
  2232. WHERE `".BIDS."`.`worklist_id` = `".WORKLIST."`.`id` AND `".BIDS."`.`accepted` = 1 LIMIT 1)) as bid_done,
  2233. (SELECT COUNT(`".COMMENTS."`.`id`) FROM `".COMMENTS."`
  2234. WHERE `".COMMENTS."`.`worklist_id` = `".WORKLIST."`.`id`) AS `comments`";
  2235. // Highlight jobs I bid on in a different color
  2236. // 14-JUN-2010 <Tom>
  2237. if ((isset($_SESSION['userid']))) {
  2238. $qsel .= ", (SELECT `".BIDS."`.`id` FROM `".BIDS."` WHERE `".BIDS."`.`worklist_id` = `".WORKLIST."`.`id` AND `".BIDS."`.`bidder_id` = ".$_SESSION['userid']." AND `withdrawn` = 0 AND (`".WORKLIST."`.`status`='Bidding' OR `".WORKLIST."`.`status`='SuggestedWithBid') ORDER BY `".BIDS."`.`id` DESC LIMIT 1) AS `current_bid`";
  2239. $qsel .= ", (SELECT `".BIDS."`.`bid_expires` FROM `".BIDS."` WHERE `".BIDS."`.`id` = `current_bid`) AS `current_expire`";
  2240. $qsel .= ", (SELECT COUNT(`".BIDS."`.`id`) FROM `".BIDS."` WHERE `".BIDS."`.`worklist_id` = `".WORKLIST."`.`id` AND (`".WORKLIST."`.`status`='Bidding' OR `".WORKLIST."`.`status`='SuggestedWithBid') AND `".BIDS."`.`bidder_id` = ".$_SESSION['userid']." AND `withdrawn` = 0 AND (`bid_expires` > NOW() OR `bid_expires`='0000-00-00 00:00:00')) AS `bid_on`";
  2241. }
  2242. $qbody = "FROM `".WORKLIST."`
  2243. LEFT JOIN `".USERS."` AS cu ON `".WORKLIST."`.`creator_id` = `cu`.`id`
  2244. LEFT JOIN `".USERS."` AS ru ON `".WORKLIST."`.`runner_id` = `ru`.`id`
  2245. LEFT JOIN `" . USERS . "` AS mu ON `" . WORKLIST . "`.`mechanic_id` = `mu`.`id`
  2246. LEFT JOIN `" . FEES . "` ON `" . WORKLIST . "`.`id` = `" . FEES . "`.`worklist_id` AND `" . FEES . "`.`withdrawn` = 0
  2247. INNER JOIN `".PROJECTS."` AS `proj` ON `".WORKLIST."`.`project_id` = `proj`.`project_id` AND `proj`.`internal` = 1
  2248. AND `proj`.`active` = 1
  2249. $commentsjoin
  2250. $where
  2251. ";
  2252. if ($ofilter == "delta") {
  2253. $idsort = $dfilter == 'DESC' ? 'ASC' : 'DESC';
  2254. $qorder = "GROUP BY `".WORKLIST."`.`id` ORDER BY `".WORKLIST."`.`id` {$idsort} LIMIT "
  2255. . ($page-1)*$limit . ",{$limit}";
  2256. } else {
  2257. $qorder = "GROUP BY `".WORKLIST."`.`id` ORDER BY {$ofilter} {$dfilter},{$subofilter} {$dfilter} LIMIT "
  2258. . ($page-1)*$limit . ",{$limit}";
  2259. }
  2260. $rtCount = mysql_query("$qcnt $qbody");
  2261. if ($rtCount) {
  2262. $row = mysql_fetch_row($rtCount);
  2263. $items = intval($row[0]);
  2264. } else {
  2265. $items = 0;
  2266. }
  2267. $cPages = ceil($items/$limit);
  2268. $worklist = array(array($items, $page, $cPages));
  2269. // Construct json for history
  2270. $qry="$qsel $qbody $qorder";
  2271. //Don't export mysql errors to the browser by default
  2272. $rtQuery = mysql_query($qry) or error_log('getworklist mysql error: '. mysql_error());
  2273. while ($rtQuery && $row=mysql_fetch_assoc($rtQuery)) {
  2274. $worklist[] = array(
  2275. 0 => $row['id'],
  2276. 1 => $row['summary'],
  2277. 2 => $row['status'],
  2278. 3 => $row['creator_nickname'],
  2279. 4 => $row['runner_nickname'],
  2280. 5 => $row['mechanic_nickname'],
  2281. 6 => $row['delta'],
  2282. 7 => $row['total_fees'],
  2283. 8 => ($is_runner == 1) ? $row['bid_amount'] : 0,
  2284. 9 => $row['creator_id'],
  2285. 10 => $row['bid_count'],
  2286. 11 => ($row['status'] == 'Done') ? date("m/d/Y",time()+$row['bid_done']):$row['bid_done'],
  2287. 12 => $row['comments'],
  2288. 13 => $row['runner_id'],
  2289. 14 => $row['mechanic_id'],
  2290. 15 => (!empty($row['bid_on']) ? $row['bid_on'] : 0),
  2291. 16 => $row['project_id'],
  2292. 17 => $row['project_name'],
  2293. 18 => $row['bug_job_id'],
  2294. 19 => (!empty($row['current_expire']) && strtotime($row['current_expire'])<time() && trim($row['current_expire'])!='0000-00-00 00:00:00') ? 'expired' : 0,
  2295. 20 => (!empty($row['current_bid']) ? $row['current_bid'] : 0),
  2296. );
  2297. }
  2298. $json = json_encode($worklist);
  2299. echo $json;
  2300. }
  2301. function payBonus() {
  2302. $error = false;
  2303. $message = '';
  2304. // user must be logged in
  2305. if (! isset($_SESSION['userid'])) {
  2306. $error = true;
  2307. $message = 'error: unauthorized';
  2308. } else {
  2309. $userId = getSessionUserId();
  2310. $is_runner = isset($_SESSION['is_runner']) ? $_SESSION['is_runner'] : 0;
  2311. $is_payer = isset($_SESSION['is_payer']) ? $_SESSION['is_payer'] : 0;
  2312. if( $userId > 0 && ( $is_runner || $is_payer ) ) {
  2313. $giver = new User();
  2314. $giver->findUserById($userId);
  2315. $budget = $giver->getBudget();
  2316. // validate required fields
  2317. if (empty($_REQUEST['budget-source-combo-bonus']) || empty($_REQUEST['receiver_id']) || empty($_REQUEST['amount'])) {
  2318. $error = true;
  2319. $message = 'error: args';
  2320. }
  2321. $budget_source_combo = (int) $_REQUEST['budget-source-combo-bonus'];
  2322. $budgetSource = new Budget();
  2323. if (!$budgetSource->loadById($budget_source_combo) ) {
  2324. $error = true;
  2325. $message = 'Invalid budget!';
  2326. }
  2327. $amount = floatval($_REQUEST['amount']);
  2328. $stringAmount = number_format($amount, 2);
  2329. $receiver_id = intval($_REQUEST['receiver_id']);
  2330. $reason = $_REQUEST['reason'];
  2331. } else {
  2332. $error = true;
  2333. $message = 'error: session';
  2334. }
  2335. }
  2336. if (! $error) {
  2337. $remainingFunds = $budgetSource->getRemainingFunds();
  2338. if ($amount <= $budget && $amount <= $remainingFunds) {
  2339. if (payBonusToUser($receiver_id, $amount, $reason, $budget_source_combo)) {
  2340. // deduct amount from balance
  2341. $giver->updateBudget(- $amount, $budget_source_combo);
  2342. $receiver = getUserById($receiver_id);
  2343. $receiver_email = $receiver->username;
  2344. sendTemplateEmail( $receiver_email, 'bonus_received', array('amount' => $stringAmount, 'reason' => $reason));
  2345. if (sendJournalNotification('@' . $receiver->nickname . ' received a bonus of $' . $stringAmount) == 'ok') {
  2346. } else {
  2347. // journal notification failed
  2348. }
  2349. $error = false;
  2350. $message = 'Paid ' . $receiver->nickname . ' a bonus of $' . $stringAmount;
  2351. } else {
  2352. $error = true;
  2353. $message = 'DB error';
  2354. }
  2355. } else {
  2356. $error = true;
  2357. $message = 'You do not have enough budget available to pay this bonus.';
  2358. }
  2359. }
  2360. $json = json_encode(array('success' => !$error, 'message' => $message));
  2361. echo $json;
  2362. }
  2363. function payCheck() {
  2364. $is_payer = !empty($_SESSION['is_payer']) ? true : false;
  2365. // Check if we have a payer
  2366. if (!$is_payer) {
  2367. exit('{"success": false, "message": "Nothing to see here. Move along!" }');
  2368. }
  2369. // Get clean data
  2370. if (isset($_REQUEST['paid_check']) && ($_REQUEST['paid_check'] == '1')) {
  2371. $paid_check = 1;
  2372. } else {
  2373. $paid_check = 0;
  2374. }
  2375. $paid_notes = $_REQUEST['paid_notes'];
  2376. if (isset($paid_notes) && !empty($paid_notes)) {
  2377. $paid_notes = mysql_real_escape_string($_REQUEST['paid_notes']);
  2378. } else {
  2379. die('{"success": false, "message": "You must write a note!" }');
  2380. }
  2381. if (isset($_REQUEST['itemid']) && !empty($_REQUEST['itemid'])) {
  2382. $fee_id = mysql_real_escape_string($_REQUEST['itemid']);
  2383. } else {
  2384. die('{"success": false, "message": "No fee set!" }');
  2385. }
  2386. // What user is paying
  2387. $user = $_SESSION['userid'];
  2388. // get the fund_id from the project that the fee/workitem belongs to
  2389. $fund_query = "
  2390. SELECT p.fund_id AS fund_id
  2391. FROM " . FEES . " f
  2392. LEFT JOIN " . WORKLIST . " w ON f.worklist_id = w.id
  2393. LEFT JOIN " . PROJECTS . " p ON w.project_id = p.project_id
  2394. WHERE f.id = {$fee_id}";
  2395. if ($fund_result = mysql_query($fund_query)) {
  2396. $fund_row = mysql_fetch_array($fund_result);
  2397. $fund_id = $fund_row['fund_id'];
  2398. } else {
  2399. $fund_id = 0;
  2400. }
  2401. // Exit of this script
  2402. if (Fee::markPaidById($fee_id, $user, $paid_notes, $paid_check, false, $fund_id)) {
  2403. /* Only send the email when marking as paid. */
  2404. if ($paid_check) {
  2405. $fees_query = 'SELECT `amount`,`user_id`,`worklist_id`,`desc` FROM '.FEES.' WHERE `id` = '.$fee_id;
  2406. $result1 = mysql_query($fees_query);
  2407. $fee_pay= mysql_fetch_array($result1);
  2408. $total_fee_pay = $fee_pay['amount'];
  2409. $summary = getWorkItemSummary($fee_pay['worklist_id']);
  2410. $mail = 'SELECT `username` FROM '.USERS.' WHERE `id` = '.$fee_pay['user_id'].'';
  2411. $userData = mysql_fetch_array(mysql_query($mail));
  2412. $subject = "Worklist.net paid you " . $total_fee_pay ." for ". $summary;
  2413. $body = "Your Fee was marked paid.<br/>";
  2414. $body .= "Job <a href='./" . $fee_pay['worklist_id'] . "' />#" . $fee_pay['worklist_id'] .
  2415. "</a>: <a href='./" . $fee_pay['worklist_id'] . "' />" . SERVER_URL . $fee_pay['worklist_id'] . "</a><br/>";
  2416. $body .= "Fee Description : ".nl2br($fee_pay['desc'])."<br/>";
  2417. $body .= "Paid Notes : ".nl2br($_REQUEST['paid_notes'])."<br/><br/>";
  2418. $body .= "Contact the job Designer with any questions<br/><br/>Worklist.net<br/>";
  2419. if(!send_email($userData['username'], $subject, $body)) { error_log("paycheck: send_email failed"); }
  2420. }
  2421. die('{"success": true, "message": "Payment has been saved!" }');
  2422. } else {
  2423. die('{"success": false, "message": "Hmm, that was unexpected... Payment Failed!" }');
  2424. }
  2425. }
  2426. function pingTask() {
  2427. checkLogin();
  2428. // Get sender Nickname
  2429. $id = getSessionUserId();
  2430. $user = getUserById($id);
  2431. $nickname = $user->nickname;
  2432. $email = $user->username;
  2433. $msg = $_REQUEST['msg'];
  2434. $send_cc = isset($_REQUEST['cc']) ? (int) $_REQUEST['cc'] : false;
  2435. // ping about concrete task
  2436. if (isset($_REQUEST['id'])) {
  2437. $item_id = intval($_REQUEST['id']);
  2438. $who = $_REQUEST['who'];
  2439. // Get item
  2440. $item = getWorklistById( $item_id );
  2441. if( $who == 'mechanic' ) {
  2442. // Get mechanic Nickname & email
  2443. $receiver_id = $item['mechanic_id'];
  2444. $receiver = getUserById( $receiver_id );
  2445. $receiver_nick = $receiver->nickname;
  2446. $receiver_email = $receiver->username;
  2447. } else if( $who == 'runner' ) {
  2448. // Get runner Nickname & email
  2449. $receiver_id = $item['runner_id'];
  2450. $receiver = getUserById( $receiver_id );
  2451. $receiver_nick = $receiver->nickname;
  2452. $receiver_email = $receiver->username;
  2453. } else if($who == 'creator' ) {
  2454. // Get runner Nickname & email
  2455. $receiver_id = $item['creator_id'];
  2456. $receiver = getUserById( $receiver_id );
  2457. $receiver_nick = $receiver->nickname;
  2458. $receiver_email = $receiver->username;
  2459. } else if ($who == 'bidder') {
  2460. // Get bidder Nickname & email
  2461. if (isset($_REQUEST['bid_id'])) {
  2462. $bid_id = (int) $_REQUEST['bid_id'];
  2463. } else {
  2464. echo json_encode(array("error" => "missing parameter bid_id"));
  2465. die();
  2466. }
  2467. $bid = new Bid();
  2468. $bid->findBidById($bid_id);
  2469. $bid_info = $bid->toArray();
  2470. $receiver_id = $bid_info['bidder_id'];
  2471. $receiver = getUserById( $receiver_id );
  2472. $receiver_nick = $receiver->nickname;
  2473. $receiver_email = $receiver->username;
  2474. }
  2475. // Send mail
  2476. if ($who != 'bidder') {
  2477. $mail_subject = $nickname." sent you a message on Worklist for item #".$item_id;
  2478. $mail_msg .= "<p><a href='" . WORKLIST_URL .'user/' . $id . "'>" . $nickname . "</a>";
  2479. $mail_msg .= " sent you a message about item ";
  2480. $mail_msg .= "<a href='" . WORKLIST_URL . $item_id . "'>#" . $item_id . "</a>";
  2481. $mail_msg .= "</p><p>----------<br/>".$msg."<br/>----------</p><p>You can reply via email to: ".$email."</p>";
  2482. $headers = array('X-tag' => 'ping, task', 'From' => NOREPLY_SENDER, 'Reply-To' => '"' . $nickname . '" <' . $email . '>');
  2483. if ($send_cc) {
  2484. $headers['Cc'] = '"' . $nickname . '" <' . $email . '>';
  2485. }
  2486. if (!send_email($receiver_email, $mail_subject, $mail_msg, '', $headers)) {
  2487. error_log('pingtask.php:id: send_email failed');
  2488. }
  2489. } else if ($who == 'bidder') {
  2490. $project = new Project();
  2491. $project->loadById($item['project_id']);
  2492. $project_name = $project->getName();
  2493. $mail_subject = "#" . $item_id . " - " . $item['summary'];
  2494. $mail_msg = "<p>The Designer for #" . $item_id . " sent a reply to your bid.</p>";
  2495. $mail_msg .= "<p>Message from " . $nickname . ":<br/>" . $msg . "</p>";
  2496. $mail_msg .= "<p>Your bid info:</p>";
  2497. $mail_msg .= "<p>Amount: " . $bid_info['bid_amount'] . "<br />Done in: " . $bid_info['bid_done_in'] . "<br />Expires: " . $bid_info['bid_expires'] . "</p>";
  2498. $mail_msg .= "<p>Notes: " . $bid_info['notes'] . "</p>";
  2499. $mail_msg .= "<p>You can view the job here. <a href='./" . $item_id . "?action=view'>#" . $item_id . "</a></p>";
  2500. $mail_msg .= "<p><a href=\"www.worklist.net\">www.worklist.net</a></p>";
  2501. $headers = array('From' => '"'. $project_name.'-bid reply" <'. SMS_SENDER . '>', '
  2502. X-tag' => 'ping, task',
  2503. 'From' => NOREPLY_SENDER,
  2504. 'Reply-To' => '"' . $nickname . '" <' . $email . '>');
  2505. if ($send_cc) {
  2506. $headers['Cc'] = '"' . $nickname . '" <' . $email . '>';
  2507. }
  2508. if (!send_email($receiver_email, $mail_subject, $mail_msg, '', $headers)) {
  2509. error_log('pingtask.php:id: send_email failed');
  2510. }
  2511. }
  2512. } else {
  2513. // just send general ping to user
  2514. $receiver = getUserById(intval($_REQUEST['userid']));
  2515. $receiver_nick = $receiver->nickname;
  2516. $receiver_email = $receiver->username;
  2517. $mail_subject = $nickname." sent you a message on Worklist";
  2518. $mail_msg = "<p><a href='" . WORKLIST_URL .'user/' . $id . "'>" . $nickname . "</a>";
  2519. $mail_msg .=" sent you a message: ";
  2520. $mail_msg .= "</p><p>----------<br/>". nl2br($msg)."<br />----------</p><p>You can reply via email to ".$email."</p>";
  2521. $headers = array('X-tag' => 'ping', 'From' => NOREPLY_SENDER, 'Reply-To' => '"' . $nickname . '" <' . $email . '>');
  2522. if ($send_cc) {
  2523. $headers['Cc'] = '"' . $nickname . '" <' . $email . '>';
  2524. }
  2525. if (!send_email($receiver_email, $mail_subject, $mail_msg, '', $headers)) {
  2526. error_log("pingtask.php:!id: send_email failed");
  2527. }
  2528. }
  2529. echo json_encode(array());
  2530. }
  2531. function refreshFilter() {
  2532. checkLogin();
  2533. // If no action is passed exit
  2534. if (!isset($_REQUEST['name']) || !isset($_REQUEST['active'])) {
  2535. return;
  2536. }
  2537. $name = $_REQUEST['name'];
  2538. $active = intval($_REQUEST['active']);
  2539. $type = $_REQUEST['filter'];
  2540. $filter = new Agency_Worklist_Filter();
  2541. $filter->setName($name)
  2542. ->initFilter();
  2543. $json = array();
  2544. switch ($type) {
  2545. case 'projects':
  2546. $projects = Project::getProjects($active);
  2547. $json[] = array(
  2548. 'value' => 0,
  2549. 'text' => 'All projects',
  2550. 'selected' => false
  2551. );
  2552. foreach ($projects as $project) {
  2553. $json[] = array(
  2554. 'value' => $project['project_id'],
  2555. 'text' => $project['name'],
  2556. 'selected' => false
  2557. );
  2558. }
  2559. break;
  2560. case 'users':
  2561. $users = User::getUserList(getSessionUserId(), $active);
  2562. $json[] = array(
  2563. 'value' => 0,
  2564. 'text' => 'All users',
  2565. 'selected' => (($filter->getUser() == 0) ? true : false)
  2566. );
  2567. foreach ($users as $user) {
  2568. $json[] = array(
  2569. 'value' => $user->getId(),
  2570. 'text' => $user->getNickname(),
  2571. 'selected' => (($filter->getUser() == $user->getId()) ? true : false)
  2572. );
  2573. }
  2574. break;
  2575. }
  2576. echo(json_encode($json));
  2577. }
  2578. function userReview() {
  2579. $userReview = new UserReview();
  2580. $userReview->validateRequest(array('method'));
  2581. $method = $_REQUEST['method'];
  2582. $userReview->$method();
  2583. }
  2584. function workitemSandbox() {
  2585. $workitemSandbox = new WorkitemSandbox();
  2586. $workitemSandbox->validateRequest(array('method'));
  2587. $method = $_REQUEST['method'];
  2588. $workitemSandbox->$method();
  2589. }
  2590. function testFlight() {
  2591. if (! $_REQUEST['project_id']) {
  2592. echo json_encode(array(
  2593. "error" => "There is no project ID."
  2594. ));
  2595. return;
  2596. }
  2597. $userId = getSessionUserId();
  2598. $project = new Project();
  2599. $project->loadById( mysql_real_escape_string($_REQUEST['project_id']) );
  2600. $testFlightTeamToken = $project->getTestFlightTeamToken();
  2601. if ($project->getTestFlightEnabled()) {
  2602. if ($testFlightTeamToken == "") {
  2603. echo json_encode(array(
  2604. "error" => "TestFlight Team Token is empty."
  2605. ));
  2606. } else if ($project->isOwner($userId)) {
  2607. $ipaFile = mysql_real_escape_string($_REQUEST['ipa_file']);
  2608. $svnUrl = $config['websvn']['baseUrl'] . "/svn/repos/" . $project->getRepository();
  2609. if ($ipaFile == "") {
  2610. $ipaFiles = array();
  2611. $svnMessage = array();
  2612. exec("svn list --config-dir /tmp -R " . $svnUrl ." | grep .ipa", $ipaFiles);
  2613. exec("svn log --config-dir /tmp -r HEAD " . $svnUrl, $svnMessage);
  2614. if (count($ipaFiles) > 0) {
  2615. echo json_encode(array(
  2616. "ipaFiles" => $ipaFiles,
  2617. "message" => $svnMessage[3]
  2618. ));
  2619. } else {
  2620. echo json_encode(array(
  2621. "error" => "No .ipa files in repository."
  2622. ));
  2623. }
  2624. } else {
  2625. $fileName = "/tmp/" . md5( time().rand() );
  2626. exec("svn export --config-dir /tmp " . $svnUrl . "/" . $ipaFile . " " . $fileName);
  2627. $ch = curl_init();
  2628. curl_setopt($ch, CURLOPT_HEADER, 0);
  2629. curl_setopt($ch, CURLOPT_VERBOSE, 0);
  2630. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  2631. curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
  2632. curl_setopt($ch, CURLOPT_URL, "http://testflightapp.com/api/builds.json");
  2633. curl_setopt($ch, CURLOPT_POST, true);
  2634. $post = array(
  2635. "api_token" => TESTFLIGHT_API_TOKEN,
  2636. "team_token" => $testFlightTeamToken,
  2637. "file" => "@" . $fileName,
  2638. "notes" => mysql_real_escape_string($_REQUEST['message']),
  2639. "notify" => mysql_real_escape_string($_REQUEST['notify'])
  2640. );
  2641. curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
  2642. $out = curl_exec($ch);
  2643. if (json_decode($out) != $out) {
  2644. echo $out;
  2645. } else {
  2646. echo json_encode(array(
  2647. "error" => $out
  2648. ));
  2649. }
  2650. }
  2651. } else {
  2652. echo json_encode(array(
  2653. "error" => "You don't have the permissions."
  2654. ));
  2655. }
  2656. }
  2657. }
  2658. function updateBudget() {
  2659. $error = false;
  2660. $message = '';
  2661. if (!isset($_SESSION['userid'])) {
  2662. echo json_encode(array('success' => false, 'message' => 'error: unauthorized'));
  2663. return;
  2664. }
  2665. if (!isset($_REQUEST['budget_seed']) || !isset($_REQUEST['budget_source'])
  2666. || !isset($_REQUEST['budget_source_combo']) || !isset($_REQUEST['budget_note'])
  2667. || !isset($_REQUEST['add_funds_to'])) {
  2668. echo json_encode(array('success' => false, 'message' => 'error: args'));
  2669. return;
  2670. }
  2671. $budget_seed = (int) $_REQUEST['budget_seed'];
  2672. $budget_source = mysql_real_escape_string($_REQUEST['budget_source']);
  2673. $budget_source_combo = (int) $_REQUEST['budget_source_combo'];
  2674. $add_funds_to = (int) $_REQUEST['add_funds_to'];
  2675. $budget_note = mysql_real_escape_string($_REQUEST['budget_note']);
  2676. if ($budget_seed == 1) {
  2677. $budget_source_combo = 0;
  2678. $source = $budget_source;
  2679. if (empty($source)) {
  2680. echo json_encode(array('success' => false, 'message' => 'Source field is mandatory'));
  2681. return;
  2682. }
  2683. } else {
  2684. $source = "Amount from budget id: " . $budget_source_combo;
  2685. if ($budget_source_combo == 0) {
  2686. echo json_encode(array('success' => false, 'message' => 'Source field is mandatory'));
  2687. return;
  2688. }
  2689. }
  2690. $receiver_id = intval($_REQUEST['receiver_id']);
  2691. $amount = isset($_REQUEST['amount']) ? floatval($_REQUEST['amount']) : 0;
  2692. $reason = mysql_real_escape_string($_REQUEST['reason']);
  2693. if (empty($receiver_id)) {
  2694. echo json_encode(array('success' => false, 'message' => 'Receiver field is mandatory'));
  2695. return;
  2696. }
  2697. if (empty($amount)) {
  2698. echo json_encode(array('success' => false, 'message' => 'Amount field is mandatory'));
  2699. return;
  2700. }
  2701. if ($add_funds_to == 0 && empty($reason)) {
  2702. echo json_encode(array('success' => false, 'message' => 'For field is mandatory'));
  2703. return;
  2704. }
  2705. $giver = new User();
  2706. $receiver = new User();
  2707. if (!$giver->findUserById($_SESSION['userid']) || !$receiver->findUserById($receiver_id)) {
  2708. echo json_encode(array('success' => false, 'message' => 'error: invalid user'));
  2709. return;
  2710. }
  2711. $stringAmount = number_format($amount, 2);
  2712. if ($budget_seed != 1) {
  2713. $budget = new Budget();
  2714. if (!$budget->loadById($budget_source_combo) ) {
  2715. echo json_encode(array('success' => false, 'message' => 'Invalid budget!'));
  2716. return;
  2717. }
  2718. // Check if user is owner of source budget
  2719. if ($budget->receiver_id != $_SESSION['userid']) {
  2720. echo json_encode(array('success' => false, 'message' => 'You\'re not the owner of this budget!'));
  2721. error_log('Possible Hacking attempt: User ' . $_SESSION['userid'] . ' attempted to budget ' . $amount . ' to ' . $receiver_id . ' from budget ' . $budget->id);
  2722. return;
  2723. }
  2724. $remainingFunds = $budget->getRemainingFunds();
  2725. }
  2726. $add_funds_to_budget = false;
  2727. if ($add_funds_to != 0) {
  2728. $add_funds_to_budget = new Budget();
  2729. if (!$add_funds_to_budget->loadById($add_funds_to) ) {
  2730. echo json_encode(array('success' => false, 'message' => 'Invalid budget (add funds parameter)!'));
  2731. return;
  2732. }
  2733. $grantor = new User();
  2734. if (!$grantor->findUserById($add_funds_to_budget->giver_id)) {
  2735. echo json_encode(array('success' => false, 'message' => 'error: invalid grantor'));
  2736. return;
  2737. }
  2738. }
  2739. if ($budget_seed == 1 ||
  2740. ($amount <= $budget->getRemainingFunds())) {
  2741. $receiver->setBudget($receiver->getBudget() + $amount)->save();
  2742. if ($add_funds_to == 0) {
  2743. $query = "INSERT INTO `" . BUDGETS .
  2744. "` (`giver_id`, `receiver_id`, `amount`, `remaining`, `reason`, `transfer_date`, `seed`, `source_data`, `notes`, `active`) VALUES ('" .
  2745. $_SESSION['userid'] .
  2746. "', '$receiver_id', '$amount', '$amount', '$reason', NOW(), '$budget_seed', '$source', '$budget_note', 1)";
  2747. if (!mysql_unbuffered_query($query)){
  2748. $json = json_encode(array('success' => false, 'message' => 'Error in query.'));
  2749. echo $json;
  2750. return;
  2751. }
  2752. $add_funds_to = mysql_insert_id();
  2753. } else {
  2754. $query = "UPDATE `" . BUDGETS .
  2755. "` SET `amount`= `amount` + $amount, `remaining` = `remaining` + $amount
  2756. WHERE id = $add_funds_to";
  2757. if (!mysql_unbuffered_query($query)){
  2758. $json = json_encode(array('success' => false, 'message' => 'Error in query.'));
  2759. echo $json;
  2760. return;
  2761. }
  2762. }
  2763. $query = "INSERT INTO `" . BUDGET_SOURCE .
  2764. "` (`giver_id`, `budget_id`, `source_budget_id`, `amount_granted`, `original_amount`, `transfer_date`, `source_data`) VALUES ('" .
  2765. $_SESSION['userid'] .
  2766. "', '$add_funds_to', '$budget_source_combo', '$amount', '0', NOW(), '$source')";
  2767. if (!mysql_unbuffered_query($query)){
  2768. $json = json_encode(array('success' => false, 'message' => 'Error in query.'));
  2769. echo $json;
  2770. return;
  2771. }
  2772. if ($budget_seed != 1) {
  2773. $giver->updateBudget(- $amount, $budget_source_combo);
  2774. $budget = new Budget();
  2775. $budget->loadById($add_funds_to);
  2776. $reason = $budget->reason;
  2777. }
  2778. $query2 = " UPDATE `" . USERS . "` SET `is_runner` = 1 WHERE `id` = $receiver_id AND `is_runner` = 0 ";
  2779. if (mysql_unbuffered_query($query2)) {
  2780. $journal_message = '@' . $giver->getNickname() . ' budgeted @' . $receiver->getNickname() . " $" . number_format($amount, 2) .
  2781. " for " . $reason . ".";
  2782. sendJournalNotification($journal_message);
  2783. if ($add_funds_to_budget == false) {
  2784. Notification::notifyBudget($amount, $reason, $giver, $receiver);
  2785. } else {
  2786. Notification::notifyBudgetAddFunds($amount, $giver, $receiver, $grantor, $add_funds_to_budget);
  2787. }
  2788. if ($budget_seed == 1) {
  2789. Notification::notifySeedBudget($amount, $reason, $source, $giver, $receiver);
  2790. }
  2791. $receiver = getUserById($receiver_id);
  2792. $message = 'You gave ' . '$' . $stringAmount . ' budget to ' . $receiver->nickname;
  2793. } else {
  2794. $error = true;
  2795. $message = 'Error in query.';
  2796. }
  2797. } else {
  2798. $error = true;
  2799. $message = 'You do not have enough budget available to give this amount (total: $' . $giver->getBudget() . ", from budget: " . $budget->id . ")";
  2800. }
  2801. $json = json_encode(array('success' => !$error, 'message' => $message));
  2802. echo $json;
  2803. }
  2804. function userNotes() {
  2805. $usernotes = new UserNotes();
  2806. $usernotes->validateRequest(array('method'));
  2807. $method = $_REQUEST['method'];
  2808. $usernotes->$method();
  2809. }
  2810. function visitQuery() {
  2811. /*
  2812. * Google Analytics API Token
  2813. * New tokens can be created by calling auth.php in the subdir resources
  2814. */
  2815. $token = GOOGLE_ANALYTICS_TOKEN;
  2816. /* site ids can be obtained from analytics
  2817. * by logging into the profile, it's currently
  2818. * called Profile ID on screen
  2819. */
  2820. $ids = GOOGLE_ANALYTICS_PROFILE_ID;
  2821. $jobid = (int) $_GET['jobid'];
  2822. if ($jobid > 0) {
  2823. $results = VisitQueryTools::getJobResults($jobid, $token, $ids);
  2824. } elseif ($jobid === 0) {
  2825. $results = VisitQueryTools::getAllJobResults($token, $ids);
  2826. }
  2827. if (!isset($results)) {
  2828. echo "{error: 'invalid job id supplied'}";
  2829. } else {
  2830. if(!isset($results['error'])) {
  2831. if ($jobid === 0) {
  2832. $data = VisitQueryTools::parseItems($results['result']);
  2833. } else {
  2834. $data = VisitQueryTools::parseItem($results['result']);
  2835. }
  2836. echo json_encode($data);
  2837. } else {
  2838. echo "{error: '" . $results['error'] . "' }";
  2839. }
  2840. }
  2841. }
  2842. function wdFee() {
  2843. checkLogin();
  2844. $fee_id = (int)$_GET["wd_fee_id"];
  2845. if ($fee_id < 1) { return 'Update Failed'; }
  2846. $fee_update_sql = 'UPDATE '.FEES.' SET withdrawn = \'1\' WHERE id = '.$fee_id;
  2847. //Restrict fee removal to user and those authorized to affect money
  2848. if (empty($_SESSION['is_payer']) && empty($_SESSION['is_runner']) && !empty($_SESSION['userid'])) {
  2849. $fee_update_sql .= ' and `user_id` = ' . ($_SESSION['userid']);
  2850. }
  2851. $fee_update = mysql_query($fee_update_sql) or error_log("wd_fee mysql error: $fee_update_sql\n".json_encode($_SESSION) . mysql_error());
  2852. if ($fee_update) {
  2853. echo 'Update Successful!';
  2854. } else {
  2855. echo 'Update Failed!';
  2856. }
  2857. }
  2858. function budgetInfo() {
  2859. $budgetInfo = new BudgetInfo();
  2860. $budgetInfo->validateRequest(array('method'));
  2861. $method = $_REQUEST['method'];
  2862. $budgetInfo->$method();
  2863. }
  2864. function budgetHistory() {
  2865. $id = (int) $_REQUEST['id'];
  2866. $fromUserid = "n";
  2867. if(isset($_REQUEST['fromUserid'])) {
  2868. $fromUserid = $_REQUEST['fromUserid'];
  2869. }
  2870. if(!isset($_REQUEST['page'])) {
  2871. $_REQUEST['page'] = 1;
  2872. }
  2873. $userId = getSessionUserId();
  2874. $user = new User();
  2875. if ($userId > 0) {
  2876. $user->findUserById($userId);
  2877. } else {
  2878. $user->setId(0);
  2879. }
  2880. $inDiv = $_REQUEST['inDiv'];
  2881. $page = (int) $_REQUEST['page'];
  2882. $limit = 8;
  2883. $init = ($page -1) * $limit;
  2884. $fromUseridFilter = "";
  2885. if ($fromUserid == "y") {
  2886. $fromUseridFilter = " AND b.giver_id = " . $userId;
  2887. }
  2888. // Query to get User's Budget entries
  2889. $query = ' SELECT DATE_FORMAT(b.transfer_date, "%Y-%m-%d") AS date, b.amount,'
  2890. . ' IF( b.active=1, b.remaining, 0.00) AS remaining, b.reason, b.active, b.notes, b.seed, b.id AS budget_id, '
  2891. . '(SELECT COUNT(s.giver_id) FROM ' . BUDGET_SOURCE .
  2892. ' AS s WHERE s.budget_id = b.id AND s.giver_id = ' . $userId . ') AS userid_count, '
  2893. . '(SELECT COUNT(DISTINCT giver_id) FROM ' . BUDGET_SOURCE . ' AS s WHERE s.budget_id = b.id ) AS givers_count, '
  2894. . '(SELECT u.nickname FROM ' . USERS . ' AS u, ' . BUDGET_SOURCE
  2895. . ' AS s WHERE u.id = s.giver_id AND s.budget_id = b.id LIMIT 0, 1) AS nickname '
  2896. . ' FROM ' . BUDGETS . ' AS b '
  2897. . ' WHERE b.receiver_id = ' . $id
  2898. . $fromUseridFilter
  2899. . ' ORDER BY b.id DESC '
  2900. . ' LIMIT ' . $init . ',' . $limit;
  2901. // Get total # of entries
  2902. $queryTotal = ' SELECT COUNT(*) AS total'
  2903. . ' FROM ' . BUDGETS . ' AS b '
  2904. . ' WHERE b.receiver_id = ' . $id
  2905. . $fromUseridFilter;
  2906. if($result = mysql_query($queryTotal)) {
  2907. $count = mysql_fetch_assoc($result);
  2908. $totalPages = floor(( (int) $count['total'] - 1) / $limit) + 1;
  2909. } else {
  2910. $total = 1;
  2911. }
  2912. if ( $count['total'] == 0){
  2913. echo "This user hasn't been assigned any budget yet.";
  2914. exit(0);
  2915. }
  2916. ?>
  2917. <table class="table table-striped">
  2918. <thead>
  2919. <tr>
  2920. <th>Created</th>
  2921. <th>ID #</th>
  2922. <th>Grantor</th>
  2923. <th>Amount</th>
  2924. <?php if (!empty($id) && $userId == $id) { ?>
  2925. <th>Remaining</th>
  2926. <?php } ?>
  2927. <th>For</th>
  2928. <th>Active</th>
  2929. </tr>
  2930. </thead>
  2931. <?php
  2932. $result = mysql_query($query);
  2933. $budgetList = array();
  2934. if ($result) {
  2935. $i = 1;
  2936. while ($row = mysql_fetch_assoc($result)) {
  2937. $notes = "";
  2938. if ($userId == $id ||
  2939. (array_key_exists('is_payer', $_SESSION) && $_SESSION['is_payer']) ||
  2940. $row['userid_count'] > 0) {
  2941. if (!empty($row['notes'])) {
  2942. $notes = " title='" . $row['budget_id'] . " - Notes: " . $row['notes'];
  2943. } else {
  2944. $notes = " title='" . $row['budget_id'] . " - Notes: None";
  2945. }
  2946. $notes .= "' ";
  2947. $classBudgetRow = " budgetRow";
  2948. } else {
  2949. $classBudgetRow = "";
  2950. }
  2951. ?>
  2952. <tr class="<?php echo $classBudgetRow; ?>" data-budgetid="<?php echo $row['budget_id']; ?>"
  2953. <?php echo (!empty($notes)) ? $notes : $row['budget_id'] ; ?>
  2954. >
  2955. <td><span><?php echo $row['date']; ?></span></td>
  2956. <td><span><?php echo $row['budget_id']; ?></span></td>
  2957. <td><span><?php echo ($row['givers_count'] == 1 ) ? $row['nickname'] : "Various"; ?></span></td>
  2958. <td><span><?php echo $row['amount']; ?></span></td>
  2959. <?php if (!empty($id) && $userId == $id) { ?>
  2960. <td<?php if ($row['remaining'] < 0) echo ' class="red"'; ?>><span>
  2961. <?php echo $row['remaining']; ?></span></td>
  2962. <?php } ?>
  2963. <td><span><?php echo $row['reason']; ?></span></td>
  2964. <td><span><?php echo ($row['active'] == 1) ? "open" : "closed"; ?></span></td>
  2965. </tr>
  2966. <?php
  2967. $i++;
  2968. }
  2969. }
  2970. ?>
  2971. </table>
  2972. <div><ul class="pagination"><?php
  2973. for ($i = 1; $i <= $totalPages; $i++) {
  2974. if ($i == $page) {
  2975. echo '<li><a href="#">' . $i . '</a></li>';
  2976. } else {
  2977. echo '<li><a href="javascript:Budget.budgetHistory({inDiv: \'' . $inDiv . '\', id: ' . $id . ', page: ' . $i . ', fromUserid: \'' . $fromUserid . '\'});">' . $i . '</a></li>';
  2978. }
  2979. }
  2980. echo '</ul></div>';
  2981. }
  2982. function timeline() {
  2983. require_once('models/Timeline.php');
  2984. $timeline = new Timeline();
  2985. if ($_POST["method"] == "getHistoricalData") {
  2986. if (isset($_POST["project"])) {
  2987. $project = $_POST["project"];
  2988. }
  2989. if ($project) {
  2990. $objectData = $timeline->getHistoricalData($project);
  2991. } else {
  2992. $objectData = $timeline->getHistoricalData();
  2993. }
  2994. echo json_encode($objectData);
  2995. } else if ($_POST["method"] == "getDistinctLocations") {
  2996. $objectData = $timeline->getDistinctLocations();
  2997. echo json_encode($objectData);
  2998. } else if ($_POST["method"] == "storeLatLong") {
  2999. $location = $_POST["location"];
  3000. $latlong = $_POST["latlong"];
  3001. $timeline->insertLocationData($location, $latlong);
  3002. } else if ($_REQUEST["method"] == "getLatLong") {
  3003. $objectData = $timeline->getLocationData();
  3004. echo json_encode($objectData);
  3005. } else if ($_POST["method"] == "getListOfMonths"){
  3006. $months = $timeline->getListOfMonths();
  3007. echo json_encode($months);
  3008. }
  3009. }
  3010. function sendNewUserNotification() {
  3011. $db = new Database();
  3012. $recipient = array('grayson@highfidelity.io', 'chris@highfidelity.io');
  3013. /**
  3014. * The email is to be sent Monday to Friday, therefore on a Monday
  3015. * we want to capture new signups since the previous Friday morning
  3016. */
  3017. $interval = 1;
  3018. if (date('N') === 1) {
  3019. $interval = 3;
  3020. }
  3021. $sql = "
  3022. SELECT * FROM " . USERS . "
  3023. WHERE
  3024. added > DATE_SUB(NOW(), INTERVAL {$interval} DAY)";
  3025. $result_temp = $db->query($sql);
  3026. $data = '<ol>';
  3027. while ($row_temp = mysql_fetch_assoc($result_temp)) {
  3028. $data .= sprintf('<li><a href="%suser/%d">%s</a> / <a href="mailto:%s">%s</a></li>',
  3029. SERVER_URL,
  3030. $row_temp['id'],
  3031. $row_temp['nickname'],
  3032. $row_temp['username'],
  3033. $row_temp['username']
  3034. );
  3035. }
  3036. $data .= '</ol>';
  3037. $mergeData = array(
  3038. 'userList' => $data,
  3039. 'hours' => $interval * 25
  3040. );
  3041. if (! sendTemplateEmail($recipient, 'user-signups', $mergeData)) {
  3042. error_log('sendNewUserNotification cron: Failed to send email report');
  3043. }
  3044. }
  3045. // This is responsible for the weekly job report that is being sent to the users.
  3046. function sendJobReport() {
  3047. // Let's fetch the data.
  3048. $sql = "
  3049. SELECT w.id, u.nickname, w.summary, w.status
  3050. FROM worklist w
  3051. INNER JOIN users u on u.id = w.mechanic_id
  3052. WHERE w.status_changed > DATE_SUB(NOW(), INTERVAL 7 Day)
  3053. AND w.status IN('Working', 'Review', 'Functional', 'Completed', 'Done')
  3054. ORDER BY u.nickname, w.id;";
  3055. // Build our data
  3056. # $jobs_data = array( array(), array() );
  3057. $res = mysql_query($sql);
  3058. if($res) {
  3059. while($row = mysql_fetch_assoc($res)) {
  3060. if ($row['status'] == 'Done') {
  3061. $jobs_data[$row['nickname']]['done'][] = $row;
  3062. } else {
  3063. $jobs_data[$row['nickname']]['working'][] = $row;
  3064. }
  3065. }
  3066. }
  3067. // Build the output
  3068. $html = '<h2>Summary of Worklist activity for the past week:</h2>';
  3069. foreach ($jobs_data as $user_jobs) {
  3070. $nickname = $user_jobs[key($user_jobs)][0]['nickname'];
  3071. $html .= '<h3>Developer: '. $nickname .'</h3>';
  3072. // Completed jobs
  3073. if (isset($user_jobs['done'])) {
  3074. $html .= '<h4>Completed Last Week:</h4>';
  3075. $html .= '<ul>';
  3076. foreach ($user_jobs['done'] as $job) {
  3077. $html .= '<li><a href="https://worklist.net/'. $job['id'] .'">' . $job['id'] . ' - ' . $job['summary'] . '</a></li>';
  3078. }
  3079. $html .= '</ul>';
  3080. }
  3081. // In progress
  3082. if (isset($user_jobs['working'])) {
  3083. $html .= '<h4>In Progress:</h4>';
  3084. $html .= '<ul>';
  3085. foreach ($user_jobs['working'] as $job) {
  3086. $html .= '<li><a href="https://worklist.net/'. $job['id'] .'">' . $job['id'] . ' - ' . $job['summary'] . '</a></li>';
  3087. }
  3088. $html .= '</ul>';
  3089. }
  3090. }
  3091. // Send the emails
  3092. $sql = 'select distinct username from users where is_runner=1' ;
  3093. $user_data = mysql_query($sql);
  3094. $emails = array();
  3095. while ($row = mysql_fetch_assoc($user_data)) {
  3096. array_push($emails, $row["username"]);
  3097. }
  3098. $email_content = array('data' => $html);
  3099. if (! sendTemplateEmail($emails, 'jobs-weekly-report', $email_content, 'contact@highfidelity.io')) {
  3100. error_log('sendJobReport cron: Emails could not be sent.');
  3101. }
  3102. }