public function view($job_id) { $this->write('statusListRunner', array("Draft", "Suggestion", "Bidding", "In Progress", "QA Ready", "Code Review", "Merged", "Done", "Pass")); $statusListMechanic = array("In Progress", "QA Ready", "Code Review", "Merged", "Pass"); $this->write('statusListMechanic', $statusListMechanic); $this->write('statusListCreator', array("Suggestion", "Pass")); if (!defined("WORKITEM_URL")) { define("WORKITEM_URL", SERVER_URL); } if (!defined("WORKLIST_REDIRECT_URL")) { define("WORKLIST_REDIRECT_URL", SERVER_URL); } $worklist_id = intval($job_id); $is_runner = isset($_SESSION['is_runner']) ? $_SESSION['is_runner'] : 0; $currentUsername = isset($_SESSION['username']) ? $_SESSION['username'] : ''; //initialize user accessing the page $userId = Session::uid(); $user = new User(); if ($userId > 0) { $user->findUserById($userId); } else { $user->setId(0); } $this->write('user', $user); // TODO: Would be good to take out all the checks for isset($_SESSION['userid'] etc. and have them use $user instead, check $user->getId() > 0. if (empty($worklist_id)) { $this->view = null; return; } //Set an empty variable for $journal_message to avoid errors/warnings with .= $journal_message = null; //initialize the workitem class $workitem = new WorkItem(); try { $workitem->loadById($worklist_id); } catch (Exception $e) { $error = $e->getMessage(); $this->view = null; die($error); } if ($workitem->isInternal() && !$user->isInternal()) { $this->write('msg', 'You don\'t have permissions to view this job.'); $this->write('link', WORKLIST_URL); $this->view = new ErrorView(); parent::run(); exit; } if ($workitem->getStatus() == 'Draft' && $workitem->getCreatorId() != $_SESSION['userid']) { $this->write('msg', 'You don\'t have permissions to view this job.'); $this->write('link', WORKLIST_URL); $this->view = new ErrorView(); parent::run(); exit; } $this->write('workitem', $workitem); // we need to be able to grant runner rights to a project founder for all jobs for their project $workitem_project = Project::getById($workitem->getProjectId()); $is_project_founder = false; if ($workitem_project->getOwnerId() == $_SESSION['userid']) { $is_project_founder = true; } $this->write('workitem_project', $workitem_project); $this->write('is_project_founder', $is_project_founder); $this->write('isGitHubConnected', $user->isGithub_connected($workitem_project->getGithubId())); //used for is_project_runner rights $is_project_runner = false; if ($workitem->getIsRelRunner() == 1) { $is_project_runner = true; } $this->write('is_project_runner', $is_project_runner); $redirectToDefaultView = false; $promptForReviewUrl = true; $runner_budget = $user->getBudget(); $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'view'; if ($workitem->getStatus() == 'Done' && $action == 'edit') { $action = 'view'; } $view_bid_id = 0; if (isset($_REQUEST['withdraw_bid'])) { $action = "withdraw_bid"; } else { if (isset($_REQUEST['decline_bid'])) { $action = "decline_bid"; } else { if (isset($_REQUEST['save_workitem'])) { $action = "save_workitem"; } else { if (isset($_REQUEST['place_bid'])) { $action = "place_bid"; } else { if (isset($_REQUEST['swb'])) { $action = "swb"; } else { if (isset($_REQUEST['edit_bid'])) { $action = "edit_bid"; } else { if (isset($_REQUEST['add_fee'])) { $action = "add_fee"; } else { if (isset($_REQUEST['add_tip'])) { $action = "add_tip"; } else { if (isset($_REQUEST['accept_bid'])) { $action = "accept_bid"; } else { if (isset($_REQUEST['accept_multiple_bid'])) { $action = "accept_multiple_bid"; } else { if (isset($_REQUEST['status-switch'])) { $action = "status-switch"; } else { if (isset($_REQUEST['newcomment'])) { $action = 'new-comment'; } } } } } } } } } } } } if ($action == 'view_bid') { $action = "view"; $this->write('view_bid_id', isset($_REQUEST['bid_id']) ? $_REQUEST['bid_id'] : 0); } // for any other action user has to be logged in if ($action != 'view') { Utils::checkLogin(); $action_error = ''; $action = $workitem->validateAction($action, $action_error); } $this->write('action', $action); // Save WorkItem was requested. We only support Update here $notifyEmpty = true; $job_changes = array(); $status_change = ''; if ($action == 'save_workitem') { $this->edit($worklist_id); } if ($action == 'new-comment') { if (isset($_REQUEST['worklist_id']) && !empty($_REQUEST['worklist_id']) && (isset($_REQUEST['user_id']) && !empty($_REQUEST['user_id'])) && (isset($_REQUEST['comment']) && !empty($_REQUEST['comment']))) { if (isset($_REQUEST['comment_id']) && !empty($_REQUEST['comment_id'])) { $parent_comment = (int) $_REQUEST['comment_id']; } else { $parent_comment = NULL; } $worklist_id = (int) $_REQUEST['worklist_id']; $user_id = (int) $_REQUEST['user_id']; $comment = $_REQUEST['comment']; $rt = $this->addComment($worklist_id, $user_id, $comment, $parent_comment); // Send journal notification if ($workitem->getStatus() != 'Draft') { $related = $this->getRelated($comment); $journal_message .= '@' . $_SESSION['nickname'] . ' posted a comment on #' . $worklist_id . $related; $options = array('type' => 'comment', 'workitem' => $workitem, 'recipients' => array('creator', 'runner', 'mechanic', 'followers'), 'emails' => $rt['correspondent']); $data = array('who' => $_SESSION['nickname'], 'comment' => $comment, 'related' => $related, 'comment-id' => $rt['id']); Notification::workitemNotify($options, $data, false); Notification::workitemNotifyHipchat($options, $data); // workitem mentions $matches = array(); if (preg_match_all('/@(\\w+)/', $comment, $matches, PREG_SET_ORDER)) { foreach ($matches as $mention) { // validate the username actually exists if ($recipient = User::find($mention[1])) { // exclude creator, designer, developer and followers if ($recipient->getId() != $workitem->getRunnerId() && $recipient->getId() != $workitem->getMechanicId() && $recipient->getId() != $workitem->getCreatorId() && !$workitem->isUserFollowing($recipient->getId())) { $emailTemplate = 'workitem-mention'; $comment_url = WORKLIST_URL . $workitem->getId() . '#comment-' . $rt['id']; $data = array('job_id' => $workitem->getId(), 'summary' => $workitem->getSummary(), 'author' => $_SESSION['nickname'], 'text' => $comment, 'link' => '<a href="' . $comment_url . '">See the comment</a>'); $senderEmail = 'Worklist - ' . $_SESSION['nickname'] . ' <*****@*****.**> '; Utils::sendTemplateEmail($recipient->getUsername(), $emailTemplate, $data, $senderEmail); } } } } } Utils::systemNotification($journal_message); $comment = new Comment(); $comment->findCommentById((int) $rt['id']); $result = array('success' => true, 'id' => $rt['id'], 'comment' => str_replace(array('\\n\\r', '\\r\\n', '\\n', '\\r'), '<br/>', Utils::linkify($comment->getComment())), 'avatar' => $comment->getUser()->getAvatar(), 'nickname' => $comment->getUser()->getNickname(), 'userid' => $comment->getUser()->getId(), 'date' => Utils::relativeTime(strtotime($comment->getDate()) - strtotime(Model::now()))); ob_start(); $json = json_encode($result); } else { $json = json_encode(array('success' => false)); } $this->view = null; echo $json; ob_end_flush(); exit; } if ($action == 'status-switch') { $status = $_REQUEST['quick-status']; $status_error = ''; if ($status == 'Done' && $workitem->getProjectId() == 0) { $status_error = "No project associated with workitem. Could not set to DONE."; } else { if ($this->changeStatus($workitem, $status, $user)) { if ($workitem->save() == false) { $status_error = "Error in save workitem process. Could not change the status."; } else { if ($status == 'Merged') { $workitem->addFeesToCompletedJob(); } if ($status != 'Draft') { $new_update_message = "Status set to *{$status}*. "; $notifyEmpty = false; $status_change = '-' . ucfirst(strtolower($status)); if ($status == 'QA Ready') { Notification::workitemNotify(array('type' => 'new_qa', 'workitem' => $workitem, 'status_change' => $status_change, 'job_changes' => $job_changes, 'recipients' => array($workitem->getRunnerId(), 'creator', 'mechanic', 'followers')), array('changes' => $new_update_message)); $notifyEmpty = true; } if ($status == 'Code Review') { Notification::workitemNotify(array('type' => 'new_review', 'workitem' => $workitem, 'status_change' => $status_change, 'job_changes' => $job_changes, 'recipients' => array($workitem->getRunnerId(), 'creator', 'mechanic', 'followers', 'reviewNotifs')), array('changes' => $new_update_message)); $notifyEmpty = true; } $journal_message = '\\#' . $worklist_id . ' updated by @' . $_SESSION['nickname'] . ' ' . $new_update_message; } } } else { $message = ''; if ($status & 4) { //sandbox not updated $message .= " - Sandbox is not up-to-date\n"; } if ($status & 8) { //sandbox has conflicts $message .= " - Sandbox contains conflicted files\n"; } if ($status & 16) { //sandbox has not-included files $message .= " - Sandbox contains 'not-included' files\n"; } $status_error = "Sandbox verification failed. " . $message; } } } if (!$notifyEmpty) { $options = array('type' => 'modified', 'workitem' => $workitem, 'status_change' => $status_change, 'job_changes' => $job_changes, 'recipients' => array('runner', 'creator', 'mechanic', 'followers')); $data = array('changes' => $new_update_message); Notification::workitemNotify($options, $data); } if ($action == "place_bid") { //Escaping $notes with mysql_real_escape_string is generating \n\r instead of <br> //a new variable is used to send the unenscaped notes in email alert. //so it can parse the new line as <BR> 12-Mar-2011 <webdev> $args = array('bid_amount', 'done_in', 'bid_expires', 'notes', 'mechanic_id'); foreach ($args as $arg) { ${$arg} = mysql_real_escape_string($_REQUEST[$arg]); } $bid_amount = (double) $bid_amount; $mechanic_id = (int) $mechanic_id; if ($_SESSION['timezone'] == '0000') { $_SESSION['timezone'] = '+0000'; } $summary = $workitem->getSummary(); if ($mechanic_id != Session::uid()) { $row = $workitem->getUserDetails($mechanic_id); if (!empty($row)) { $nickname = $row['nickname']; $username = $row['username']; } else { $username = "******"; $nickname = "unknown-{$mechanic_id}"; } } else { $mechanic_id = $_SESSION['userid']; $username = $_SESSION['username']; $nickname = $_SESSION['nickname']; } if ($user->isEligible()) { $bid_id = $workitem->placeBid($mechanic_id, $username, $worklist_id, $bid_amount, $done_in, $bid_expires, $notes); //sending email to the runner of worklist item or all runners if not assigned $row = $workitem->getRunnerSummary($worklist_id); if (!empty($row)) { $id = $row['id']; $summary = $row['summary']; $username = $row['username']; } $options = array('type' => 'bid_placed', 'workitem' => $workitem, 'recipients' => array($workitem->getRunnerId() == '' ? 'projectRunners' : 'runner'), 'jobsInfo' => $user->jobsForProject('Done', $workitem->getProjectId(), 1, 3), 'totalJobs' => $user->jobsCount(array('In Progress', 'QA Ready', 'Review', 'Merged', 'Done')), 'activeJobs' => $user->jobsCount(array('In Progress', 'QA Ready', 'Review'))); $journal_message = 'A bid was placed on #' . $worklist_id; $data = array('done_in' => $done_in, 'bid_expires' => $bid_expires, 'bid_amount' => $bid_amount, 'notes' => str_replace(array('\\n\\r', '\\r\\n', '\\n', '\\r'), '<br/>', $notes), 'bid_id' => $bid_id); // notify runner of new bid Notification::workitemNotify($options, $data); $status = $workitem->loadStatusByBidId($bid_id); $data['new_update_message'] = $new_update_message; Notification::workitemNotifyHipchat($options, $data); } else { error_log("Input forgery detected for user {$userId}: attempting to {$action}."); } $redirectToDefaultView = true; } // Edit Bid if ($action == "edit_bid") { if (!$user->isEligible()) { error_log("Input forgery detected for user {$userId}: attempting to {$action} (isEligible in job)"); } else { //Escaping $notes with mysql_real_escape_string is generating \n\r instead of <br> //a new variable is used to send the unenscaped notes in email alert. //so it can parse the new line as <BR> 12-Mar-2011 <webdev> $args = array('bid_id', 'bid_amount', 'done_in', 'bid_expires', 'notes'); foreach ($args as $arg) { ${$arg} = mysql_real_escape_string($_REQUEST[$arg]); } $bid_amount = (double) $bid_amount; $mechanic_id = (int) $mechanic_id; if ($_SESSION['timezone'] == '0000') { $_SESSION['timezone'] = '+0000'; } $summary = $workitem->getSummary(); $bid_id = $workitem->updateBid($bid_id, $bid_amount, $done_in, $bid_expires, $_SESSION['timezone'], $notes); // Journal notification $journal_message = 'Bid updated on #' . $worklist_id; //sending email to the runner of worklist item $row = $workitem->getRunnerSummary($worklist_id); if (!empty($row)) { $id = $row['id']; $summary = $row['summary']; $username = $row['username']; } $options = array('type' => 'bid_updated', 'workitem' => $workitem, 'recipients' => array('runner'), 'jobsInfo' => $user->jobsForProject('Done', $workitem->getProjectId(), 1, 3), 'totalJobs' => $user->jobsCount(array('In Progress', 'QA Ready', 'Review', 'Merged', 'Done')), 'activeJobs' => $user->jobsCount(array('In Progress', 'QA Ready', 'Review'))); $data = array('done_in' => $done_in, 'bid_expires' => $bid_expires, 'bid_amount' => $bid_amount, 'notes' => str_replace(array('\\n\\r', '\\r\\n', '\\n', '\\r'), '<br/>', $notes), 'bid_id' => $bid_id); // notify runner of new bid Notification::workitemNotify($options, $data); Notification::workitemNotifyHipchat($options, $data); } $redirectToDefaultView = true; } // Request submitted from Add Fee popup if ($action == "add_fee") { if (!$user->isEligible()) { error_log("Input forgery detected for user {$userId}: attempting to {$action}."); } else { $args = array('itemid', 'fee_amount', 'fee_desc', 'mechanic_id', 'is_expense', 'is_rewarder'); foreach ($args as $arg) { if (isset($_REQUEST[$arg])) { ${$arg} = mysql_real_escape_string($_REQUEST[$arg]); } else { ${$arg} = ''; } } $itemid = (int) $itemid; $fee_amount = (double) $fee_amount; $mechanic_id = (int) $mechanic_id; $journal_message = Fee::add($itemid, $fee_amount, '', $fee_desc, $mechanic_id, '', ''); if ($workitem->getStatus() != 'Draft') { $options = array('type' => 'fee_added', 'workitem' => $workitem, 'recipients' => array('runner')); $data = array('fee_adder' => $user->getNickname(), 'fee_amount' => $fee_amount, 'fee_desc' => $fee_desc, 'mechanic_id' => $mechanic_id); Notification::workitemNotify($options, $data); $data['nick'] = $_SESSION['nickname']; Notification::workitemNotifyHipchat($options, $data); // update budget $runner = new User(); $runner->findUserById($workitem->getRunnerId()); $runner->updateBudget(-$fee_amount, $workitem->getBudget_id()); } $redirectToDefaultView = true; } } // Accept a bid if ($action == 'accept_bid') { if (!isset($_REQUEST['bid_id']) || !isset($_REQUEST['budget_id'])) { $_SESSION['workitem_error'] = "Missing parameter to accept a bid!"; } else { $bid_id = intval($_REQUEST['bid_id']); $budget_id = intval($_REQUEST['budget_id']); $budget = new Budget(); if (!$budget->loadById($budget_id)) { $_SESSION['workitem_error'] = "Invalid budget!"; } $is_job_runner = $workitem->getRunnerId() == Session::uid(); $is_assigned = $workitem->getAssigned_id() == Session::uid(); // only runners can accept bids if ($is_project_runner || $is_job_runner || $is_assigned || $user->getIs_admin() == 1 && $is_runner && !$workitem->hasAcceptedBids() && $workitem->getStatus() == "Bidding") { // query to get a list of bids (to use the current class rather than breaking uniformity) // I could have done this quite easier with just 1 query and an if statement.. $bids = (array) $workitem->getBids($workitem->getId()); $exists = false; foreach ($bids as $array) { if ($array['id'] == $bid_id) { $exists = true; $bid_amount = $array["bid_amount"]; break; } } if ($exists) { $remainingFunds = $budget->getRemainingFunds(); if ($bid_amount <= $remainingFunds) { $bid_info = $workitem->acceptBid($bid_id, $budget_id); $budget->recalculateBudgetRemaining(); // Journal notification $journal_message .= '@' . $_SESSION['nickname'] . " accepted {$bid_info['bid_amount']} from " . $bid_info['nickname'] . " on #" . $bid_info['worklist_id'] . " Status set to *In Progress*."; $options = array('type' => 'bid_accepted', 'workitem' => $workitem, 'recipients' => array('mechanic', 'followers')); // mail notification - including any data returned from acceptBid Notification::workitemNotify($options, $bid_info); $data = $bid_info; $data['nick'] = $_SESSION['nickname']; Notification::workitemNotifyHipchat($options, $data); $bidder = new User(); $bidder->findUserById($bid_info['bidder_id']); // Update Budget $runner = new User(); $runner->findUserById($workitem->getRunnerId()); $runner->updateBudget(-$bid_amount, $workitem->getBudget_id()); // Send email to not accepted bidders $this->sendMailToDiscardedBids($worklist_id); } else { $overBudget = money_format('%i', $bid_amount - $remainingFunds); $_SESSION['workitem_error'] = "Failed to accept bid. Accepting this bid would make you " . $overBudget . " over your budget!"; } } else { $_SESSION['workitem_error'] = "Failed to accept bid, bid has been deleted!"; } } else { if ($workitem->getIsRelRunner() || $workitem->getRunnerId() == $_SESSION['userid']) { if ($workitem->hasAcceptedBids()) { $_SESSION['workitem_error'] = "Failed to accept bid on task with an accepted bid!"; } else { $_SESSION['workitem_error'] = "Accept Bid Failed, unknown task state!"; } } } } $redirectToDefaultView = true; } // Accept Multiple bid if ($action == 'accept_multiple_bid') { if (!isset($_REQUEST['budget_id'])) { $_SESSION['workitem_error'] = "Missing budget to accept a bid!"; } else { $bid_id = $_REQUEST['chkMultipleBid']; $mechanic_id = $_REQUEST['mechanic']; $budget_id = intval($_REQUEST['budget_id']); $budget = new Budget(); if (!$budget->loadById($budget_id)) { $_SESSION['workitem_error'] = "Invalid budget!"; } if (count($bid_id) > 0) { //only runners can accept bids if (($is_project_runner || $workitem->getRunnerId() == Session::uid() || $user->getIs_admin() == 1 && $is_runner) && !$workitem->hasAcceptedBids() && $workitem->getStatus() == "Bidding") { $total = 0; foreach ($bid_id as $bid) { $currentBid = new Bid(); $currentBid->findBidById($bid); $total = $total + $currentBid->getBid_amount(); } $remainingFunds = $budget->getRemainingFunds(); if ($total <= $remainingFunds) { foreach ($bid_id as $bid) { $bids = (array) $workitem->getBids($workitem->getId()); $exists = false; foreach ($bids as $array) { if ($array['id'] == $bid) { if ($array['bidder_id'] == $mechanic_id) { $is_mechanic = true; } else { $is_mechanic = false; } $exists = true; break; } } if ($exists) { $bid_info = $workitem->acceptBid($bid, $budget_id, $is_mechanic); // Journal notification $journal_message .= '@' . $_SESSION['nickname'] . " accepted {$bid_info['bid_amount']} from " . $bid_info['nickname'] . " " . ($is_mechanic ? ' as Developer ' : '') . "on #" . $bid_info['worklist_id'] . " Status set to *In Progress*."; // mail notification Notification::workitemNotify(array('type' => 'bid_accepted', 'workitem' => $workitem, 'recipients' => array('mechanic', 'followers'))); } else { $_SESSION['workitem_error'] = "Failed to accept bid, bid has been deleted!"; } } // Send email to not accepted bidders $this->sendMailToDiscardedBids($worklist_id); $runner = new User(); $runner->findUserById($workitem->getRunnerId()); $runner->updateBudget(-$total, $workitem->getBudget_id()); } else { $overBudget = money_format('%i', $total - $remainingFunds); $_SESSION['workitem_error'] = "Failed to accept bids. Accepting this bids would make you " . $overBudget . " over your budget!"; } } } } $redirectToDefaultView = true; } //Withdraw a bid if ($action == "withdraw_bid") { if (isset($_REQUEST['bid_id'])) { $this->withdrawBid(intval($_REQUEST['bid_id']), $_REQUEST['withdraw_bid_reason']); } else { $fee_id = intval($_REQUEST['fee_id']); $res = mysql_query('SELECT f.bid_id, f.amount, w.runner_id FROM `' . FEES . '` AS f, ' . WORKLIST . ' AS w WHERE f.`id`=' . $fee_id . ' AND f.worklist_id = w.id'); $fee = mysql_fetch_object($res); if ((int) $fee->bid_id !== 0) { $this->withdrawBid($fee->bid_id, $_REQUEST['withdraw_bid_reason']); } else { $this->deleteFee($fee_id); } // Update Runner's Budget $runner = new User(); $runner->findUserById($fee->runner_id); $runner->updateBudget($fee->amount, $workitem->getBudget_id()); } $redirectToDefaultView = true; } //Decline a bid if ($action == "decline_bid") { if (isset($_REQUEST['bid_id'])) { $this->withdrawBid(intval($_REQUEST['bid_id']), $_REQUEST['decline_bid_reason']); } else { $fee_id = intval($_REQUEST['fee_id']); $res = mysql_query('SELECT f.bid_id, f.amount, w.runner_id FROM `' . FEES . '` AS f, ' . WORKLIST . ' AS w WHERE f.`id`=' . $fee_id . ' AND f.worklist_id = w.id'); $fee = mysql_fetch_object($res); if ((int) $fee->bid_id !== 0) { $this->withdrawBid($fee->bid_id, $_REQUEST['decline_bid_reason']); } else { $this->deleteFee($fee_id); } // Update Runner's Budget $runner = new User(); $runner->findUserById($fee->runner_id); $runner->updateBudget($fee->amount, $workitem->getBudget_id()); } $redirectToDefaultView = true; } // we have a Journal message, send it to Journal - except for DRAFTS if (isset($journal_message) && $workitem->getStatus() != 'Draft') { Utils::systemNotification($journal_message); //$postProcessUrl = WORKITEM_URL . $worklist_id . "?msg=" . $journal_message; } if ($redirectToDefaultView) { $this->redirect('./' . $worklist_id); } // handle the makeshift error I made.. $erroneous = false; if (isset($_SESSION['workitem_error'])) { $erroneous = true; $the_errors = $_SESSION['workitem_error']; unset($_SESSION['workitem_error']); $this->write('erroneous', $erroneous); $this->write('the_errors', $the_errors); } // Process the request normally and display the page. //get workitem from db $worklist = $workitem->getWorkItem($worklist_id); $this->write('worklist', $worklist); //get bids $bids = $workitem->getBids($worklist_id); // get only those bids that have not expired, used to determine whether // runner can edit the job notes $this->write('activeBids', (array) $workitem->getBids($workitem->getId(), false)); //Findout if the current user already has any bids. // Yes, it's a String instead of boolean to make it easy to use in JS. // Suppress names if not is_runner, or creator of Item. Still show if it's user's bid. $currentUserHasBid = "false"; if (!empty($bids) && is_array($bids)) { foreach ($bids as &$bid) { if ($bid['email'] == $currentUsername) { $currentUserHasBid = "true"; //break; } if (!($user->getId() == $bid['bidder_id'] || $user->isRunnerOfWorkitem($workitem) || $workitem->getIsRelRunner() && !$worklist['runner_id'])) { if ($user->getIs_admin() == 0) { $bid['nickname'] = '*name hidden*'; $bid['bid_amount'] = '***'; $bid['email'] = '********'; $bid['notes'] = '********'; } } $bid['bid_created'] = $this->convertTimezone($bid['unix_bid_created']); if ($bid['unix_bid_accepted'] > 0) { $bid['bid_accepted'] = $this->convertTimezone($bid['unix_bid_accepted']); } else { $bid['bid_accepted'] = ''; } if ($bid['unix_done_full'] > 0 && !empty($bid['unix_done_full'])) { $bid['unix_done_full'] = $this->convertTimezone($bid['unix_done_full']); } else { $bid['unix_done_full'] = ''; } // calculate Total Time to Complete if (isset($bid['unix_done_by']) && $bid['unix_done_by'] != 0) { $timeToComplete = (int) $bid['unix_done_by'] - (int) $bid['unix_bid_created']; if ($bid['unix_bid_accepted'] > 0) { $timeElapsed = (int) $bid['unix_now'] - (int) $bid['unix_bid_accepted']; $timeToComplete -= $timeElapsed; } $fullDays = floor($timeToComplete / (60 * 60 * 24)); $fullHours = floor(($timeToComplete - $fullDays * 60 * 60 * 24) / (60 * 60)); $fullMinutes = floor(($timeToComplete - $fullDays * 60 * 60 * 24 - $fullHours * 60 * 60) / 60); $bid['time_to_complete'] = $fullDays . ($fullDays == 1 ? " day, " : " days, ") . $fullHours . ($fullHours == 1 ? " hour and " : " hours and ") . $fullMinutes . ($fullMinutes == 1 ? " minute." : " minutes."); } else { $bid['time_to_complete'] = null; } } } // break reference to $bid unset($bid); //get fees $fees = $workitem->getFees($worklist_id); $this->write('fees', $fees); $user_id = isset($_SESSION['userid']) ? $_SESSION['userid'] : ""; $is_runner = isset($_SESSION['is_runner']) ? $_SESSION['is_runner'] : 0; $is_admin = isset($_SESSION['is_admin']) ? $_SESSION['is_admin'] : 0; $is_payer = isset($_SESSION['is_payer']) ? $_SESSION['is_payer'] : 0; $creator_id = isset($worklist['creator_id']) ? $worklist['creator_id'] : 0; $mechanic_id = isset($worklist['mechanic_id']) ? $worklist['mechanic_id'] : 0; $runner_id = isset($worklist['runner_id']) ? $worklist['runner_id'] : 0; $status_error = ''; $has_budget = 0; if (!empty($user_id)) { $user = new User(); $user->findUserById($user_id); if ($user->getBudget() > 0) { $has_budget = 1; } // fee defaults to 0 for internal users $crFee = 0; if (!$user->isInternal()) { // otherwise, lookup reviewer fee on the Project $crFee = $this->getCRFee($workitem); } $this->write('crFee', $crFee); } $workitem = WorkItem::getById($worklist['id']); if ($worklist['project_id']) { $workitem_project = new Project($worklist['project_id']); } $projects = Project::getProjects(); $allowEdit = false; $classEditable = ""; if ($workitem->getIsRelRunner() && is_null($worklist['runner_id']) || $user->getIs_admin() == 1 && $is_runner || $creator_id == $user_id && $worklist['status'] == 'Suggestion' && is_null($worklist['runner_id']) || $runner_id == $user_id) { $allowEdit = true; if ($action != "edit") { $classEditable = " editable"; } } $this->write('classEditable', $classEditable); $this->write('allowEdit', $allowEdit); $hideFees = false; if ($worklist['status'] == 'Bidding' || $worklist['status'] == 'Suggestion') { $hideFees = true; } $this->write('hideFees', $hideFees); $this->write('bids', $bids); $this->write('userHasCodeReviewRights', $this->hasCodeReviewRights($user_id, $workitem)); $this->write('mechanic', $workitem->getUserDetails($worklist['mechanic_id'])); $reviewer = new User(); $reviewer->findUserById($workitem->getCReviewerId()); $this->write('reviewer', $reviewer); $this->write('action_error', isset($action_error) ? $action_error : ''); $this->write('comments', Comment::findCommentsForWorkitem($worklist['id'])); $this->write('entries', $this->getTaskPosts($worklist['id'])); $this->write('message', isset($message) ? $message : ''); $this->write('currentUserHasBid', $currentUserHasBid); $this->write('has_budget', $has_budget); $this->write('promptForReviewUrl', $promptForReviewUrl); $this->write('status_error', $status_error); $this->write('{{userinfotoshow}}', isset($_REQUEST['userinfotoshow']) && isset($_SESSION['userid']) ? $_REQUEST['userinfotoshow'] : 0); $job_analytics = VisitQueryTools::visitQuery($worklist_id); $this->write('viewCount', $job_analytics['views']); $job_views = $job_analytics['views'] > 1 ? " views" : " view"; $this->write('views', $job_views); parent::run(); }