public function acceptBid($bid_id, $budget_id = 0, $is_mechanic = true) { $this->conditionalLoadByBidId($bid_id); /*if ($this->hasAcceptedBids()) { throw new Exception('Can not accept an already accepted bid.'); }*/ $user_id = isset($_SESSION['userid']) ? (int) $_SESSION['userid'] : 0; $is_runner = isset($_SESSION['is_runner']) ? (int) $_SESSION['is_runner'] : 0; // If a bid is being accepted, and the runner for the workitem does not exist (incase a bid went from suggested straight // to working) or is different than current user, then we should set the person accepting the bid as the runner; if ($this->getRunnerId() != $user_id) { $this->setRunnerId($user_id); } $res = mysql_query('SELECT * FROM `' . BIDS . '` WHERE `id`=' . $bid_id); $bid_info = mysql_fetch_assoc($res); $workitem_info = $this->getWorkItem($bid_info['worklist_id']); // Get bidder information $bidder = new User(); if (!$bidder->findUserById($bid_info['bidder_id'])) { // If bidder doesn't exist, return false. Don't want to throw an // exception because it would kill multiple bid acceptances return false; } $bid_info['nickname'] = $bidder->getNickname(); $project = new Project($this->getProjectId()); // Get the repo for this project $repository = $this->getRepository(); $job_id = $this->getId(); /* Verify whether the user already has this repo forked on his account *If not create the fork *Check for existing unix account in dev. If new, make call to create account */ $GitHubUser = new User($bid_info['bidder_id']); $url = TOWER_API_URL; $fields = array('action' => 'create_unixaccount', 'nickname' => $bidder->getNickname()); $result = CURLHandler::Post($url, $fields); if (!$GitHubUser->verifyForkExists($project)) { $forkStatus = $GitHubUser->createForkForUser($project); $bidderEmail = $bidder->getUsername(); $emailTemplate = 'forked-repo'; $data = array('project_name' => $forkStatus['data']['full_name'], 'nickname' => $bidder->getNickname(), 'users_fork' => $forkStatus['data']['git_url'], 'master_repo' => str_replace('https://', 'git://', $project->getRepository())); $senderEmail = 'Worklist <*****@*****.**>'; Utils::sendTemplateEmail($bidderEmail, $emailTemplate, $data, $senderEmail); sleep(10); } // Create a branch for the user if (!$forkStatus['error']) { $branchStatus = $GitHubUser->createBranchForUser($job_id, $project); $bidderEmail = $bidder->getUsername(); $emailTemplate = 'branch-created'; $data = array('branch_name' => $job_id, 'nickname' => $bidder->getNickname(), 'users_fork' => $forkStatus['data']['git_url'], 'master_repo' => str_replace('https://', 'git://', $project->getRepository())); $bid_info = array_merge($data, $bid_info); } if (!$branchStatus['error']) { $bid_info['sandbox'] = $branchStatus['branch_url']; } $bid_info['bid_done'] = strtotime('+' . $bid_info['bid_done_in'], time()); // Adding transaction wrapper around steps if (mysql_query('BEGIN')) { $is_runner_or_assignee = $is_runner || $this->getAssigned_id() == $user_id; // changing mechanic of the job $sql = "UPDATE `" . WORKLIST . "` SET " . ($is_mechanic ? "`mechanic_id` = '" . $bid_info['bidder_id'] . "', " : '') . ($is_runner_or_assignee && $user_id > 0 && $workitem_info['runner_id'] != $user_id ? "`runner_id` = '" . $user_id . "', " : '') . " `status` = 'In Progress',`status_changed`=NOW(),`sandbox` = '" . $bid_info['sandbox'] . "',`budget_id` = " . $budget_id . " WHERE `" . WORKLIST . "`.`id` = " . $bid_info['worklist_id']; if (!($myresult = mysql_query($sql))) { error_log("AcceptBid:UpdateMechanic failed: " . mysql_error()); mysql_query("ROLLBACK"); return false; } // marking bid as "accepted" if (!($result = mysql_query("UPDATE `" . BIDS . "` SET `accepted` = 1, `bid_done` = FROM_UNIXTIME('" . $bid_info['bid_done'] . "') WHERE `id` = " . $bid_id))) { error_log("AcceptBid:MarkBid failed: " . mysql_error()); mysql_query("ROLLBACK"); return false; } // adding bid amount to list of fees if (!($result = mysql_query("INSERT INTO `" . FEES . "` (`id`, `worklist_id`, `amount`, `user_id`, `desc`, `bid_notes`, `date`, `bid_id`) VALUES (NULL, " . $bid_info['worklist_id'] . ", '" . $bid_info['bid_amount'] . "', '" . $bid_info['bidder_id'] . "', 'Accepted Bid', '" . mysql_real_escape_string($bid_info['notes']) . "', NOW(), '{$bid_id}')"))) { error_log("AcceptBid:Insert Fee failed: " . mysql_error()); mysql_query("ROLLBACK"); return false; } $creator_fee = 0; $creator_fee_desc = 'Creator'; $creator_fee_added = false; $runner_fee = 0; $runner_fee_desc = 'Designer'; $runner_fee_added = false; $accepted_bid_amount = $bid_info['bid_amount']; $fee_category = ''; $is_expense = ''; $is_rewarder = ''; $fees = $this->getFees($this->getId()); foreach ($fees as $fee) { // find the accepted bid amount if ($fee['desc'] == 'Accepted Bid') { $accepted_bid_amount = $fee['amount']; } if (preg_match($reviewer_fee_desc, $fee['desc'])) { $reviewer_fee_added = true; } if ($fee['desc'] == $creator_fee_desc) { $creator_fee_added = true; } if ($fee['desc'] == $runner_fee_desc) { $runner_fee_added = true; } } // get project creator role settings, if not available, no fee is added // and will need to be added manually if applicable $project = new Project(); $project_roles = $project->getRoles($this->getProjectId(), "role_title = 'Creator'"); if (count($project_roles) != 0 && !$creator_fee_added) { // fees are not automatically created for internal users if (!$this->getCreator()->isInternal()) { $creator_role = $project_roles[0]; if ($creator_role['percentage'] !== null && $creator_role['min_amount'] !== null) { $creator_fee = $creator_role['percentage'] / 100 * $accepted_bid_amount; if ((double) $creator_fee < $creator_role['min_amount']) { $creator_fee = $creator_role['min_amount']; } // add the fee /** * @TODO - We call addfees and then deduct from budget * seems we should add the deduction process to the Fee::add * function * */ Fee::add($this->getId(), $creator_fee, $fee_category, $creator_fee_desc, $this->getCreatorId(), $is_expense, $is_rewarder); // and reduce the runners budget $myRunner = new User(); $myRunner->findUserById($this->getRunnerId()); $myRunner->updateBudget(-$creator_fee, $this->getBudget_id()); } } } $project_roles = $project->getRoles($this->getProjectId(), "role_title = 'Runner'"); if (count($project_roles) != 0 && !$runner_fee_added) { error_log("[FEES] we have a role for runner"); $runner_role = $project_roles[0]; // fees are not automatically created for internal users if (!$this->getRunner()->isInternal()) { if ($runner_role['percentage'] !== null && $runner_role['min_amount'] !== null) { $runner_fee = $runner_role['percentage'] / 100 * $accepted_bid_amount; if ((double) $runner_fee < $runner_role['min_amount']) { $runner_fee = $runner_role['min_amount']; } // add the fee Fee::add($this->getId(), $runner_fee, $fee_category, $runner_fee_desc, $this->getRunnerId(), $is_expense, $is_rewarder); // and reduce the runners budget $myRunner = new User(); $myRunner->findUserById($this->getRunnerId()); $myRunner->updateBudget(-$runner_fee, $this->getBudget_id()); } } } // add an entry to the status log $status_sql = "\n INSERT INTO " . STATUS_LOG . " (worklist_id, status, user_id, change_date)\n VALUES({$bid_info['worklist_id']}, 'Working', {$_SESSION['userid']}, NOW())"; if (!($result = mysql_query($status_sql))) { error_log("AcceptedBid:Insert status log failed: " . mysql_error()); mysql_query("ROLLBACK"); return false; } // When we get this far, commit and return bid_info if (mysql_query('COMMIT')) { $bid_info['summary'] = $workitem_info['summary']; $this->setMechanicId($bid_info['bidder_id']); return $bid_info; } else { return false; } } else { return false; } }