PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/classes/Project.class.php

https://github.com/BrianPrz/worklist
PHP | 1384 lines | 1151 code | 142 blank | 91 comment | 141 complexity | 90be355fa10d32764efb1c313757e663 MD5 | raw file
  1. <?php
  2. /**
  3. * Project
  4. *
  5. * @package Project
  6. */
  7. class Project {
  8. protected $project_id;
  9. protected $name;
  10. protected $description;
  11. protected $short_description;
  12. protected $website;
  13. protected $budget;
  14. protected $repository;
  15. protected $contact_info;
  16. protected $last_commit;
  17. protected $active;
  18. protected $owner_id;
  19. protected $fund_id;
  20. protected $testflight_enabled;
  21. protected $testflight_team_token;
  22. protected $logo;
  23. protected $cr_anyone;
  24. protected $cr_project_admin;
  25. protected $cr_3_favorites;
  26. protected $cr_job_runner;
  27. protected $cr_users_specified;
  28. protected $internal;
  29. protected $repo_type;
  30. protected $creation_date;
  31. protected $hipchat_enabled;
  32. protected $hipchat_notification_token;
  33. protected $hipchat_room;
  34. protected $hipchat_color;
  35. protected $github_repo_url;
  36. protected $github_id;
  37. protected $github_secret;
  38. public function __construct($id = null) {
  39. if (!mysql_connect(DB_SERVER, DB_USER, DB_PASSWORD)) {
  40. throw new Exception('Error: ' . mysql_error());
  41. }
  42. if (!mysql_select_db(DB_NAME)) {
  43. throw new Exception('Error: ' . mysql_error());
  44. }
  45. if ($id !== null) {
  46. $this->load($id);
  47. }
  48. }
  49. static public function getById($project_id) {
  50. $project = new Project();
  51. $project->loadById($project_id);
  52. return $project;
  53. }
  54. public function loadById($id) {
  55. return $this->load($id);
  56. }
  57. public function loadByName($name) {
  58. $query = "SELECT project_id FROM `".PROJECTS."` WHERE `name`='" . $name . "'";
  59. $result = mysql_query($query);
  60. if (mysql_num_rows($result)) {
  61. $row = mysql_fetch_assoc($result);
  62. $project_id = $row['project_id'];
  63. $this->load($project_id);
  64. } else {
  65. throw new Exception('There is no project by that name (' . $name . ')');
  66. }
  67. }
  68. public function loadByRepo($repo) {
  69. $query = "SELECT `project_id` FROM `".PROJECTS."` WHERE `repository`='" . $repo . "'";
  70. $result = mysql_query($query);
  71. if (mysql_num_rows($result)) {
  72. $row = mysql_fetch_assoc($result);
  73. $project_id = $row['project_id'];
  74. $this->load($project_id);
  75. } else {
  76. throw new Exception('There is no project with that repository');
  77. }
  78. }
  79. protected function load($project_id = null) {
  80. if ($project_id === null && ! $this->project_id) {
  81. throw new Exception('Missing project id.');
  82. } elseif ($project_id === null) {
  83. $project_id = $this->project_id;
  84. }
  85. $query = "
  86. SELECT
  87. p.project_id,
  88. p.name,
  89. p.description,
  90. p.short_description,
  91. p.website,
  92. p.budget,
  93. p.repository,
  94. p.repo_type,
  95. p.contact_info,
  96. p.last_commit,
  97. p.active,
  98. p.owner_id,
  99. p.fund_id,
  100. p.testflight_enabled,
  101. p.testflight_team_token,
  102. p.logo,
  103. p.cr_anyone,
  104. p.cr_3_favorites,
  105. p.cr_project_admin,
  106. p.cr_job_runner,
  107. p.cr_users_specified,
  108. p.internal,
  109. p.creation_date,
  110. p.hipchat_enabled,
  111. p.hipchat_notification_token,
  112. p.hipchat_room,
  113. p.hipchat_color,
  114. p.github_id,
  115. p.github_secret
  116. FROM ".PROJECTS. " as p
  117. WHERE p.project_id = '" . (int)$project_id . "'";
  118. $res = mysql_query($query);
  119. if (!$res) {
  120. throw new Exception('MySQL error.');
  121. }
  122. $row = mysql_fetch_assoc($res);
  123. if (! $row) {
  124. throw new Exception('Invalid project id.');
  125. }
  126. $this->setProjectId($row['project_id'])
  127. ->setName($row['name'])
  128. ->setDescription($row['description'])
  129. ->setShortDescription($row['short_description'])
  130. ->setWebsite($row['website'])
  131. ->setBudget($row['budget'])
  132. ->setRepository($row['repository'])
  133. ->setRepo_type($row['repo_type'])
  134. ->setContactInfo($row['contact_info'])
  135. ->setLastCommit($row['last_commit'])
  136. ->setActive($row['active'])
  137. ->setTestFlightEnabled($row['testflight_enabled'])
  138. ->setTestFlightTeamToken($row['testflight_team_token'])
  139. ->setLogo($row['logo'])
  140. ->setOwnerId($row['owner_id'])
  141. ->setFundId($row['fund_id']);
  142. $this->setCrAnyone($row['cr_anyone']);
  143. $this->setCrFav($row['cr_3_favorites']);
  144. $this->setCrAdmin($row['cr_project_admin']);
  145. $this->setCrRunner($row['cr_job_runner']);
  146. $this->setCrUsersSpecified($row['cr_users_specified']);
  147. $this->setInternal($row['internal']);
  148. $this->setCreationDate($row['creation_date']);
  149. $this->setHipchatEnabled($row['hipchat_enabled']);
  150. $this->setHipchatNotificationToken($row['hipchat_notification_token']);
  151. $this->setHipchatRoom($row['hipchat_room']);
  152. $this->setHipchatColor($row['hipchat_color']);
  153. $this->setGithubId($row['github_id']);
  154. $this->setGithubSecret($row['github_secret']);
  155. return true;
  156. }
  157. public function getTotalFees($project_id) {
  158. $feesCount = 0;
  159. $feesQuery = "SELECT SUM(F.amount) AS fees_sum FROM " . FEES . " F,
  160. " . WORKLIST . " W
  161. WHERE F.worklist_id = W.id
  162. AND W.project_id = " . $project_id . "
  163. AND F.withdrawn = 0
  164. AND W.status IN ('Completed', 'Done')";
  165. $feesQueryResult = mysql_query($feesQuery);
  166. if (mysql_num_rows($feesQueryResult)) {
  167. $feesCountArray = mysql_fetch_array($feesQueryResult);
  168. if ($feesCountArray['fees_sum']) {
  169. $feesCount = number_format($feesCountArray['fees_sum'], 0, '', ',');
  170. }
  171. }
  172. return $feesCount;
  173. }
  174. public function idExists($project_id) {
  175. $query = "
  176. SELECT project_id
  177. FROM ".PROJECTS."
  178. WHERE project_id=".(int)$project_id;
  179. $res = mysql_query($query);
  180. if (!$res) {
  181. throw new Exception('MySQL error.');
  182. }
  183. $row = mysql_fetch_row($res);
  184. return (boolean)$row[0];
  185. }
  186. public function setProjectId($project_id) {
  187. $this->project_id = (int)$project_id;
  188. return $this;
  189. }
  190. public function getProjectId() {
  191. return $this->project_id;
  192. }
  193. public function setName($name) {
  194. $this->name = $name;
  195. return $this;
  196. }
  197. public function getName() {
  198. return $this->name;
  199. }
  200. public function setDescription($description) {
  201. $this->description = $description;
  202. return $this;
  203. }
  204. public function getDescription() {
  205. return $this->description;
  206. }
  207. public function setShortDescription($description) {
  208. $this->short_description = $description;
  209. return $this;
  210. }
  211. public function getShortDescription() {
  212. return $this->short_description;
  213. }
  214. public function setWebsite($website) {
  215. $this->website = $website;
  216. return $this;
  217. }
  218. public function getWebsite() {
  219. return $this->website;
  220. }
  221. public function getWebsiteLink() {
  222. return linkify($this->website, null, false, true);
  223. }
  224. public function getWebsiteUrl() {
  225. if (strpos($this->getWebsite(), "http") === 0) {
  226. return $this->getWebsite();
  227. } else {
  228. return "http://" . $this->getWebsite();
  229. }
  230. }
  231. public function setBudget($budget) {
  232. $this->budget = $budget;
  233. return $this;
  234. }
  235. public function getBudget() {
  236. return $this->budget;
  237. }
  238. public function setRepository($repository) {
  239. $this->repository = $repository;
  240. return $this;
  241. }
  242. public function getRepository() {
  243. return $this->repository;
  244. }
  245. public function setRepo_type($repo_type) {
  246. $this->repo_type = $repo_type;
  247. return $this;
  248. }
  249. public function getRepo_type() {
  250. return $this->repo_type;
  251. }
  252. public function setContactInfo($contact_info) {
  253. $this->contact_info = $contact_info;
  254. return $this;
  255. }
  256. public function getContactInfo() {
  257. return $this->contact_info;
  258. }
  259. public function setLastCommit($date) {
  260. $this->last_commit = $date;
  261. return $this;
  262. }
  263. public function getLastCommit() {
  264. return $this->last_commit;
  265. }
  266. public function setActive($active) {
  267. $this->active = $active;
  268. return $this;
  269. }
  270. public function getActive() {
  271. return $this->active;
  272. }
  273. public function setOwnerId($owner_id) {
  274. $this->owner_id = $owner_id;
  275. return $this;
  276. }
  277. public function getOwnerId() {
  278. return $this->owner_id;
  279. }
  280. public function setFundId($fund_id) {
  281. $this->fund_id = $fund_id;
  282. }
  283. public function getFundId() {
  284. return $this->fund_id;
  285. }
  286. public function setTestFlightTeamToken($testflight_team_token) {
  287. $this->testflight_team_token = $testflight_team_token;
  288. return $this;
  289. }
  290. public function getTestFlightTeamToken() {
  291. return $this->testflight_team_token;
  292. }
  293. public function setTestFlightEnabled($testflight_enabled) {
  294. $this->testflight_enabled = $testflight_enabled;
  295. return $this;
  296. }
  297. public function getTestFlightEnabled() {
  298. return $this->testflight_enabled;
  299. }
  300. public function setLogo($logo) {
  301. $this->logo = $logo;
  302. return $this;
  303. }
  304. public function getLogo() {
  305. return $this->logo;
  306. }
  307. public function setCrAnyone($cr_anyone) {
  308. $this->cr_anyone = $cr_anyone;
  309. return $this;
  310. }
  311. public function getCrAnyone() {
  312. return $this->cr_anyone;
  313. }
  314. public function setCrFav($cr_3_favorites) {
  315. $this->cr_3_favorites = $cr_3_favorites;
  316. return $this;
  317. }
  318. public function getCrFav() {
  319. return $this->cr_3_favorites;
  320. }
  321. public function setCrAdmin($cr_project_admin) {
  322. $this->cr_project_admin = $cr_project_admin;
  323. return $this;
  324. }
  325. public function getCrAdmin() {
  326. return $this->cr_project_admin;
  327. }
  328. public function setCrRunner($cr_job_runner) {
  329. $this->cr_job_runner = $cr_job_runner;
  330. return $this;
  331. }
  332. public function setCrUsersSpecified($cr_users_specified) {
  333. $this->cr_users_specified = $cr_users_specified;
  334. }
  335. public function getCrRunner() {
  336. return $this->cr_job_runner;
  337. }
  338. public function getCrUsersSpecified() {
  339. return $this->cr_users_specified;
  340. }
  341. public function setInternal($internal) {
  342. $this->internal = $internal ? 1 : 0;
  343. return $this;
  344. }
  345. public function getInternal() {
  346. return $this->internal;
  347. }
  348. public function setCreationDate($creation_date) {
  349. $this->creation_date = $creation_date;
  350. return $this;
  351. }
  352. public function getCreationDate() {
  353. return $this->creation_date;
  354. }
  355. public function setHipchatNotificationToken($hipchat_notification_token) {
  356. $this->hipchat_notification_token = $hipchat_notification_token;
  357. return $this;
  358. }
  359. public function getHipchatNotificationToken() {
  360. return $this->hipchat_notification_token;
  361. }
  362. public function setHipchatEnabled($hipchat_enabled) {
  363. $this->hipchat_enabled = $hipchat_enabled;
  364. return $this;
  365. }
  366. public function getHipchatEnabled() {
  367. return $this->hipchat_enabled;
  368. }
  369. public function setHipchatRoom($hipchat_room) {
  370. $this->hipchat_room = $hipchat_room;
  371. return $this;
  372. }
  373. public function getHipchatRoom() {
  374. return $this->hipchat_room;
  375. }
  376. public function setHipchatColor($hipchat_color) {
  377. $this->hipchat_color = $hipchat_color;
  378. return $this;
  379. }
  380. public function getHipchatColor() {
  381. $hipchat_color = $this->hipchat_color;
  382. if (in_array($hipchat_color, $this->getHipchatColorsArray())) {
  383. return $hipchat_color;
  384. }
  385. return $this->getHipchatDefaultColor();
  386. }
  387. public function getGithubId() {
  388. return $this->github_id;
  389. }
  390. public function setGithubId($github_id) {
  391. $this->github_id = $github_id;
  392. }
  393. public function getGithubSecret() {
  394. return $this->github_secret;
  395. }
  396. public function setGithubSecret($github_secret) {
  397. $this->github_secret = $github_secret;
  398. }
  399. public function getHipchatColorsArray() {
  400. return array(
  401. "yellow",
  402. "red",
  403. "green",
  404. "purple",
  405. "gray",
  406. "random"
  407. );
  408. }
  409. public function getHipchatDefaultColor() {
  410. $colors = $this->getHipchatColorsArray();
  411. return $colors[0];
  412. }
  413. public function sendHipchat_notification($message, $message_format='html', $notify=0) {
  414. $success = true;
  415. $room_id = 0;
  416. $token = $this->getHipchatNotificationToken();
  417. $url = HIPCHAT_API_AUTH_URL . $token;
  418. $response = CURLHandler::Get($url, array());
  419. $response = json_decode($response);
  420. if (count($response->rooms)) {
  421. foreach($response->rooms as $key => $room) {
  422. if ($room->name == trim($this->getHipchatRoom())) {
  423. $room_id = $room->room_id;
  424. break;
  425. }
  426. }
  427. if ($room_id > 0 ) {
  428. $url = HIPCHAT_API_MESSAGE_URL . $token;
  429. $fields = array(
  430. 'room_id' => $room_id,
  431. 'from' => 'Worklist.net',
  432. 'message' => $message,
  433. 'message_format' => $message_format,
  434. 'notify' => $notify,
  435. 'color' => $this->getHipchatColor()
  436. );
  437. $result = CURLHandler::Post($url, $fields);
  438. $result = json_decode($result);
  439. if ($result->status != 'sent') {
  440. $success = false;
  441. $body = "Failed to send message: " . $message;
  442. }
  443. } else {
  444. $success = false;
  445. $body = "Failed to find room " . $this->getHipchatRoom() . ".";
  446. }
  447. } else {
  448. $success = false;
  449. $body = "Failed to authenticate to hipchat.";
  450. }
  451. if ($success == false) {
  452. $email = $this->getContactInfo();
  453. $subject = "HipChat Notification Failed";
  454. if (!send_email($email, $subject, $body, $body, array('Cc' => OPS_EMAIL))) {
  455. error_log("project-class.php: sendHipchat_notification : send_email failed");
  456. }
  457. }
  458. }
  459. protected function insert() {
  460. $query = "INSERT INTO " . PROJECTS . "
  461. (name, description, short_description, website, budget, repository, contact_info, active,
  462. owner_id, testflight_enabled, testflight_team_token,
  463. logo, last_commit, cr_anyone, cr_3_favorites, cr_project_admin,
  464. cr_job_runner,cr_users_specified, internal, creation_date, hipchat_enabled,
  465. hipchat_notification_token, hipchat_room, hipchat_color, repo_type, github_id, github_secret) " .
  466. "VALUES (".
  467. "'".mysql_real_escape_string($this->getName())."', ".
  468. "'".mysql_real_escape_string($this->getDescription())."', ".
  469. "'".mysql_real_escape_string($this->getShortDescription())."', ".
  470. "'".mysql_real_escape_string($this->getWebsite()) . "', " .
  471. "'".mysql_real_escape_string($this->getBudget())."', ".
  472. "'".mysql_real_escape_string($this->getRepository())."', ".
  473. "'".mysql_real_escape_string($this->getContactInfo())."', ".
  474. "'".mysql_real_escape_string($this->getActive())."', ".
  475. "'".mysql_real_escape_string($this->getOwnerId())."', ".
  476. "'".mysql_real_escape_string($this->getTestFlightEnabled())."', ".
  477. "'".mysql_real_escape_string($this->getTestFlightTeamToken())."', ".
  478. "'".mysql_real_escape_string($this->getLogo())."', ".
  479. "NOW(), ".
  480. "1, ".
  481. "'".intval($this->getCrFav())."', ".
  482. "'".intval($this->getCrAdmin())."', ".
  483. "'" . intval($this->getCrRunner()) . "', " .
  484. "'" . intval($this->getCrUsersSpecified()) . "', " .
  485. "'" . intval($this->getInternal()) . "', " .
  486. "NOW(), " .
  487. "'" . intval($this->getHipchatEnabled()) . "', " .
  488. "'" . mysql_real_escape_string($this->getHipchatNotificationToken()) . "', " .
  489. "'" . mysql_real_escape_string($this->getHipchatRoom()) . "', " .
  490. "'" . mysql_real_escape_string($this->getHipchatColor()) . "', " .
  491. "'" . mysql_real_escape_string($this->getRepo_type()) . "', " .
  492. "'" . mysql_real_escape_string($this->getGithubId()) . "', " .
  493. "'" . mysql_real_escape_string($this->getGithubSecret()) . "')";
  494. $rt = mysql_query($query);
  495. $project_id = mysql_insert_id();
  496. $this->setProjectId($project_id);
  497. //for the project added insert 3 pre-populated roles with percentages and minimum amounts <joanne>
  498. $query = "INSERT INTO " . ROLES . " (project_id, role_title, percentage, min_amount)
  499. VALUES
  500. ($project_id,'Creator','10.00','10.00'),
  501. ($project_id,'Runner','25.00','20.00'),
  502. ($project_id,'Reviewer','10.00','5.00')";
  503. $rt = mysql_query($query);
  504. $query = "INSERT INTO " . PROJECT_RUNNERS . " (project_id, runner_id)
  505. VALUES
  506. ($project_id, ' " . mysql_real_escape_string($this->getOwnerId()) . " ')";
  507. $rt = mysql_query($query);
  508. if($rt) {
  509. return 1;
  510. }
  511. return 0;
  512. }
  513. protected function update() {
  514. $query = "
  515. UPDATE ".PROJECTS."
  516. SET
  517. name='".mysql_real_escape_string($this->getName())."',
  518. description='".mysql_real_escape_string($this->getDescription())."',
  519. short_description='".mysql_real_escape_string($this->getShortDescription())."',
  520. website='" . mysql_real_escape_string($this->getWebsite()) . "',
  521. budget='".mysql_real_escape_string($this->getBudget())."',
  522. repository='" .mysql_real_escape_string($this->getRepository())."',
  523. contact_info='".mysql_real_escape_string($this->getContactInfo())."',
  524. last_commit='".mysql_real_escape_string($this->getLastCommit())."',
  525. testflight_enabled='".mysql_real_escape_string($this->getTestFlightEnabled())."',
  526. testflight_team_token='".mysql_real_escape_string($this->getTestFlightTeamToken())."',
  527. logo='".mysql_real_escape_string($this->getLogo())."',
  528. active='".intval($this->getActive())."',
  529. owner_id='".intval($this->getOwnerId())."',
  530. cr_anyone='".intval($this->getCrAnyone())."',
  531. cr_3_favorites='".intval($this->getCrFav())."',
  532. cr_project_admin='".intval($this->getCrAdmin())."',
  533. cr_job_runner='" . intval($this->getCrRunner()) . "',
  534. cr_users_specified='" . intval($this->getCrUsersSpecified()) . "',
  535. internal='" . intval($this->getInternal()) . "',
  536. hipchat_enabled='" . intval($this->getHipchatEnabled()) . "',
  537. hipchat_notification_token='" . mysql_real_escape_string($this->getHipchatNotificationToken()) . "',
  538. hipchat_room='" . mysql_real_escape_string($this->getHipchatRoom()) . "',
  539. hipchat_color='" . mysql_real_escape_string($this->getHipchatColor()) . "'
  540. WHERE project_id=" . $this->getProjectId();
  541. $result = mysql_query($query);
  542. return $result ? 1 : 0;
  543. }
  544. public function save() {
  545. if (isset($this->project_id)) {
  546. if ($this->idExists($this->getProjectId())) {
  547. return $this->update();
  548. } else {
  549. return $this->insert();
  550. }
  551. } else {
  552. return $this->insert();
  553. }
  554. }
  555. /**
  556. Return an array of all projects containing all fields
  557. **/
  558. public function getProjects($active = true, $selections = array(), $onlyInactive = false) {
  559. $query = "
  560. SELECT
  561. " . ((count($selections) > 0) ? implode(",", $selections) : "*") . "
  562. FROM
  563. `" . PROJECTS . "`" ."
  564. WHERE
  565. `" . PROJECTS . "`.internal = 1 AND `" . PROJECTS . "`.active = 1
  566. ORDER BY name ASC";
  567. $result = mysql_query($query);
  568. if (mysql_num_rows($result)) {
  569. while ($project = mysql_fetch_assoc($result)) {
  570. $query = "SELECT
  571. SUM(status IN ('Done', 'Completed')) AS completed,
  572. SUM(status IN ('Working', 'Review', 'SvnHold', 'Functional')) AS underway,
  573. SUM(status='Bidding') AS bidding
  574. FROM
  575. " . WORKLIST . "
  576. WHERE
  577. project_id = " . $project['project_id'];
  578. $resultCount = mysql_query($query);
  579. $resultCount = mysql_fetch_object($resultCount);
  580. $feesCount = 0;
  581. $bCount = $resultCount->bidding === NULL ? 0 : $resultCount->bidding;
  582. $uCount = $resultCount->underway === NULL ? 0 : $resultCount->underway;
  583. $cCount = $resultCount->completed === NULL ? 0 : $resultCount->completed;
  584. if($cCount) {
  585. $feesQuery = "SELECT SUM(F.amount) as fees_sum FROM " . FEES . " F,
  586. " . WORKLIST . " W
  587. WHERE F.worklist_id = W.id
  588. AND F.withdrawn = 0
  589. AND W.project_id = " . $project['project_id'] . "
  590. AND W.status IN ('Completed', 'Done')";
  591. $feesQueryResult = mysql_query($feesQuery);
  592. if (mysql_num_rows($feesQueryResult)) {
  593. $feesCountArray = mysql_fetch_array($feesQueryResult);
  594. if($feesCountArray['fees_sum']) {
  595. $feesCount = number_format($feesCountArray['fees_sum'],0,'',',');
  596. }
  597. }
  598. }
  599. $project['bCount'] = $bCount;
  600. $project['uCount'] = $uCount;
  601. $project['cCount'] = $cCount;
  602. $project['feesCount'] = $feesCount;
  603. $projects[$project['project_id']] = $project;
  604. }
  605. return $projects;
  606. }
  607. return false;
  608. }
  609. /**
  610. * Return an array of repositories
  611. */
  612. public function getRepositoryList() {
  613. $query = "
  614. SELECT `repository`
  615. FROM `".PROJECTS."`
  616. ORDER BY `repository`";
  617. $repos = array();
  618. $result = mysql_query($query);
  619. if (mysql_num_rows($result)) {
  620. while ($project = mysql_fetch_assoc($result)) {
  621. $repos[] = $project['repository'];
  622. }
  623. return $repos;
  624. }
  625. return false;
  626. }
  627. /**
  628. * Build a project URL based on project_id
  629. */
  630. public function getProjectUrl($project_id) {
  631. $query = "SELECT * FROM `".PROJECTS."` WHERE `project_id`=". $project_id;
  632. $result = mysql_query($query);
  633. if (mysql_num_rows($result)) {
  634. $project = mysql_fetch_array($result);
  635. return SERVER_URL . $project['name'];
  636. } else {
  637. return false;
  638. }
  639. }
  640. public function getRepoUrl() {
  641. if ($this->getRepo_type() == 'git') {
  642. return $this->repository;
  643. } else {
  644. return SVN_BASE_URL . $this->repository;
  645. }
  646. }
  647. /**
  648. * Return project_id based on repository name
  649. */
  650. public function getIdFromRepo($repo) {
  651. $query = "SELECT `project_id` FROM `".PROJECTS."` WHERE `repository`='".$repo."'";
  652. $result = mysql_query($query);
  653. if (mysql_num_rows($result)) {
  654. $row = mysql_fetch_assoc($result);
  655. $project_id = $row['project_id'];
  656. return $project_id;
  657. } else {
  658. return false;
  659. }
  660. }
  661. /**
  662. Determine if the given user_id owns the project
  663. */
  664. public function isOwner($user_id = false) {
  665. return $user_id == $this->getOwnerId();
  666. }
  667. public function isProjectCodeReviewer($user_id = false) {
  668. return array_key_exists($user_id, $this->getCodeReviewers());
  669. }
  670. /**
  671. Determine if the given user_id is a project runner
  672. */
  673. public function isProjectRunner($user_id = false) {
  674. return array_key_exists($user_id, $this->getRunners());
  675. }
  676. /**
  677. * new function for getting roles for the project <mikewasmike 15-JUN-2011>
  678. * @param int $project_id
  679. * @return array|null
  680. */
  681. public function getRoles($project_id, $where = ''){
  682. $query = "SELECT * FROM `".ROLES."` WHERE `project_id`={$project_id}";
  683. if (!empty($where)) {
  684. $query .= " AND ". $where;
  685. }
  686. $result_query = mysql_query($query);
  687. if ($result_query) {
  688. $temp_array = array();
  689. while ($row = mysql_fetch_assoc($result_query)) {
  690. $temp_array[] = $row;
  691. }
  692. return $temp_array;
  693. } else {
  694. return null;
  695. }
  696. }
  697. /**
  698. * new function for adding roles in the project <mikewasmike 15-JUN-2011>
  699. * @param int $project_id
  700. * @param varchar $role_title
  701. * @param decimal $percentage
  702. * @param decimal $min_amount
  703. * @return int|null
  704. */
  705. public function addRole($project_id,$role_title,$percentage,$min_amount){
  706. $query = "INSERT INTO `".ROLES."` (id,`project_id`,`role_title`,`percentage`,`min_amount`) VALUES(NULL,'$project_id','$role_title','$percentage','$min_amount')";
  707. return mysql_query($query) ? mysql_insert_id() : null;
  708. }
  709. /**
  710. * new function for editing roles in the project <mikewasmike 15-JUN-2011>
  711. * @param int $role_id
  712. * @param varchar $role_title
  713. * @param decimal $percentage
  714. * @param decimal $min_amount
  715. * @return 1|0
  716. */
  717. public function editRole($role_id,$role_title,$percentage,$min_amount){
  718. $query = "UPDATE `".ROLES."` SET `role_title`='$role_title',`percentage`='$percentage',`min_amount`='$min_amount' WHERE `id`={$role_id}";
  719. return mysql_query($query) ? 1 : 0;
  720. }
  721. /**
  722. * new function for deleting roles in the project <mikewasmike 15-JUN-2011>
  723. * @param int $role_id
  724. * @return 1|0
  725. */
  726. public function deleteRole($role_id){
  727. $query = "DELETE FROM `".ROLES."` WHERE `id`={$role_id}";
  728. return mysql_query($query) ? 1 : 0;
  729. }
  730. /**
  731. * Allows you to add a reviewer to the project
  732. * @param $codeReviewer_id
  733. * @return number
  734. */
  735. public function addCodeReviewer($codeReviewer_id) {
  736. $project_id = $this->getProjectId();
  737. $codeReviewer_id = (int) $codeReviewer_id;
  738. $query = "INSERT INTO `" . REL_PROJECT_CODE_REVIEWERS . "` (project_id, code_reviewer_id) " .
  739. "VALUES (" . $project_id . ", " . $codeReviewer_id . ")";
  740. return mysql_query($query) ? 1 : 0;
  741. }
  742. public function deleteCodeReviewer($codeReviewer_id) {
  743. $codeReviewer_id = (int) $codeReviewer_id;
  744. if ($codeReviewer_id == $this->getOwnerId()) {
  745. return false;
  746. }
  747. $project_id = $this->getProjectId();
  748. $query = "DELETE FROM `" . REL_PROJECT_CODE_REVIEWERS . "` " .
  749. "WHERE `project_id`={$project_id} AND `code_reviewer_id`={$codeReviewer_id}";
  750. return mysql_query($query) ? 1 : 0;
  751. }
  752. /**
  753. * Add Runner to Project
  754. */
  755. public function addRunner($runner_id) {
  756. $project_id = $this->getProjectId();
  757. $runner_id = (int) $runner_id;
  758. $query =
  759. "INSERT INTO `" . PROJECT_RUNNERS . "` (project_id, runner_id) " .
  760. "VALUES (" . $project_id . ", " . $runner_id . ")";
  761. return mysql_query($query) ? 1 : 0;
  762. }
  763. /**
  764. * Remove Runner from Project
  765. */
  766. public function deleteRunner($runner_id) {
  767. $runner_id = (int) $runner_id;
  768. if ($runner_id == $this->getOwnerId()) {
  769. return false;
  770. }
  771. $project_id = $this->getProjectId();
  772. $query =
  773. "DELETE FROM `" . PROJECT_RUNNERS . "` " .
  774. "WHERE `project_id`={$project_id} AND `runner_id`={$runner_id}";
  775. return mysql_query($query) ? 1 : 0;
  776. }
  777. /**
  778. * Get Runners Job Stats for Project
  779. */
  780. public function getRunners() {
  781. $query =
  782. "SELECT DISTINCT u.id, u.nickname, (
  783. SELECT COUNT(DISTINCT(w.id))
  784. FROM " . WORKLIST . " w
  785. LEFT JOIN " . PROJECT_RUNNERS . " p on w.project_id = p.project_id
  786. WHERE w.runner_id = u.id
  787. AND w.status IN('Bidding', 'Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')
  788. AND p.project_id = " . $this->getProjectId() . "
  789. ) totalJobCount
  790. FROM " . USERS . " u
  791. WHERE u.id IN (
  792. SELECT runner_id
  793. FROM rel_project_runners
  794. WHERE project_id = " . $this->getProjectId() . "
  795. )
  796. ORDER BY totalJobCount DESC";
  797. $result = mysql_query($query);
  798. if (is_resource($result) && mysql_num_rows($result) > 0) {
  799. while($row = mysql_fetch_assoc($result)) {
  800. $row['owner'] = ($row['id'] == $this->getOwnerId());
  801. $runners[$row['id']] = $row;
  802. }
  803. return $runners;
  804. } else {
  805. return false;
  806. }
  807. }
  808. /**
  809. * Get the Reviewers for current project
  810. * @return unknown|boolean
  811. */
  812. public function getCodeReviewers() {
  813. $query =
  814. "SELECT DISTINCT u.id, u.nickname, (
  815. SELECT COUNT(DISTINCT(w.id))
  816. FROM " . WORKLIST . " w
  817. LEFT JOIN " . REL_PROJECT_CODE_REVIEWERS . " p on w.project_id = p.project_id
  818. WHERE (w.runner_id = u.id OR w.creator_id = u.id OR w.mechanic_id = u.id)
  819. AND w.status IN('Bidding', 'Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')
  820. AND p.project_id = " . $this->getProjectId() . "
  821. ) totalJobCount
  822. FROM " . USERS . " u
  823. WHERE u.id IN (
  824. SELECT code_reviewer_id
  825. FROM " . REL_PROJECT_CODE_REVIEWERS . "
  826. WHERE project_id = " . $this->getProjectId() . "
  827. )
  828. ORDER BY totalJobCount DESC";
  829. $result = mysql_query($query);
  830. if (is_resource($result) && mysql_num_rows($result) > 0) {
  831. while($row = mysql_fetch_assoc($result)) {
  832. $row['owner'] = ($row['id'] == $this->getOwnerId());
  833. $code_reviewers[$row['id']] = $row;
  834. }
  835. return $code_reviewers;
  836. } else {
  837. return array();
  838. }
  839. }
  840. /*
  841. Get the list of allowed runners for Project
  842. */
  843. public static function getAllowedRunnerlist($project_id) {
  844. $runnerlist = array();
  845. $sql = 'SELECT `u`.*
  846. FROM `' . USERS . '` u
  847. INNER JOIN `' . PROJECT_RUNNERS . '` `pr` ON (`u`.`id` = `pr`.`runner_id`)
  848. WHERE `pr`.`project_id` = ' . $project_id;
  849. $result = mysql_query($sql);
  850. if (mysql_num_rows($result) > 0) {
  851. while ($result && ($row = mysql_fetch_assoc($result))) {
  852. $user = new User();
  853. $user->setId($row['id']);
  854. $user->setUsername($row['username']);
  855. $user->setNickname($row['nickname']);
  856. $runnerlist[] = $user;
  857. }
  858. }
  859. return ((!empty($runnerlist)) ? $runnerlist : false);
  860. }
  861. /*
  862. Check if a Runner can run a specified project.
  863. */
  864. public static function isAllowedRunnerForProject($runner_id, $project_id) {
  865. $sql = 'SELECT `u`.*
  866. FROM `' . USERS . '` u
  867. INNER JOIN `' . PROJECT_RUNNERS . '` `pr` ON (`u`.`id` = `pr`.`runner_id`)
  868. WHERE `pr`.`project_id` = ' . $project_id . ' AND `u`.`id` = ' . $runner_id;
  869. $result = mysql_query($sql);
  870. if (mysql_num_rows($result) > 0) {
  871. return true;
  872. }
  873. return false;
  874. }
  875. /**
  876. * Get the last activity of the reviewer on the current project
  877. * @param $userId
  878. * @return boolean|string
  879. */
  880. public function getCodeReviewersLastActivity($userId) {
  881. $sql = "SELECT MAX(change_date) FROM " . STATUS_LOG . " s
  882. LEFT JOIN " . WORKLIST . " w ON s.worklist_id = w.id
  883. LEFT JOIN " . REL_PROJECT_CODE_REVIEWERS . " p on p.project_id = w.project_id
  884. WHERE s.user_id = " . $userId . " AND p.project_id = " . $this->getProjectId() . " ";
  885. $res = mysql_query($sql);
  886. if($res && $row = mysql_fetch_row($res)){
  887. $lastActivity = strtotime($row[0]);
  888. $rightNow = time();
  889. if($lastActivity == '') {
  890. return false;
  891. } else {
  892. return (formatableRelativeTime($lastActivity, 2) . " ago");
  893. }
  894. }
  895. return false;
  896. }
  897. public function getRunnersLastActivity($userId) {
  898. $sql = "SELECT MAX(change_date) FROM " . STATUS_LOG . " s
  899. LEFT JOIN " . WORKLIST . " w ON s.worklist_id = w.id
  900. LEFT JOIN " . PROJECT_RUNNERS . " p on p.project_id = w.project_id
  901. WHERE s.user_id = '$userId' AND p.project_id = " . $this->getProjectId() . " ";
  902. $res = mysql_query($sql);
  903. if($res && $row = mysql_fetch_row($res)){
  904. $lastActivity = strtotime($row[0]);
  905. $rightNow = time();
  906. if($lastActivity == '') {
  907. return false;
  908. } else {
  909. return (formatableRelativeTime($lastActivity, 2) . " ago");
  910. }
  911. }
  912. return false;
  913. }
  914. public function getFundName() {
  915. $query = "SELECT `name` FROM `" . FUNDS . "` WHERE `id` = {$this->getFundId()}";
  916. if ($result = mysql_query($query)) {
  917. $fund = mysql_fetch_assoc($result);
  918. return $fund['name'];
  919. } else {
  920. return false;
  921. }
  922. }
  923. public function getTotalJobs() {
  924. $query = "
  925. SELECT COUNT(w.id) jobCount
  926. FROM " . WORKLIST . " w
  927. LEFT JOIN " . PROJECTS . " p ON w.project_id = p.project_id
  928. WHERE
  929. w.status NOT IN ('Draft', 'Pass') AND
  930. p.project_id = " . $this->getProjectId();
  931. if($result = mysql_query($query)) {
  932. $count = mysql_fetch_assoc($result);
  933. return $count['jobCount'];
  934. } else {
  935. return 0;
  936. }
  937. }
  938. public function getAvgBidFee() {
  939. $query = "SELECT AVG(b.bid_amount) AS avgBidFeePerProject FROM " . BIDS . " b
  940. LEFT OUTER JOIN " . WORKLIST . " w on b.worklist_id = w.id
  941. LEFT OUTER JOIN " . PROJECTS . " p on w.project_id = p.project_id
  942. WHERE p.project_id = " . $this->getProjectId() . " AND b.accepted = 1";
  943. if($result = mysql_query($query)) {
  944. $count = mysql_fetch_assoc($result);
  945. return $count['avgBidFeePerProject'];
  946. } else {
  947. return 0;
  948. }
  949. }
  950. public function getAvgJobTime() {
  951. $query = "SELECT AVG(TIME_TO_SEC(TIMEDIFF(doneDate, workingDate))) as avgJobTime FROM
  952. (SELECT w.id, s.change_date AS doneDate,
  953. ( SELECT MAX(`date`) AS workingDate FROM fees
  954. WHERE worklist_id = w.id AND `desc` = 'Accepted Bid') as workingDate
  955. FROM status_log s
  956. LEFT JOIN worklist w ON s.worklist_id = w.id
  957. LEFT JOIN projects p on p.project_id = w.project_id
  958. WHERE s.status = 'Done' AND p.project_id = " . $this->getProjectId() . ") AS x";
  959. if($result = mysql_query($query)) {
  960. $row = mysql_fetch_array($result);
  961. return ($row['avgJobTime'] > 0) ? relativeTime($row['avgJobTime'], false, true, false) : '';
  962. } else {
  963. return false;
  964. }
  965. }
  966. public function getDevelopers() {
  967. $query = "
  968. SELECT DISTINCT u.id, u.nickname,
  969. (
  970. SELECT COUNT(*)
  971. FROM " . WORKLIST . " w
  972. LEFT JOIN " . PROJECTS . " p on w.project_id = p.project_id
  973. WHERE ( w.mechanic_id = u.id OR w.creator_id = u.id)
  974. AND w.status IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')
  975. AND p.project_id = " . $this->getProjectId() . "
  976. ) as totalJobCount,
  977. (
  978. SELECT SUM(F.amount)
  979. FROM " . FEES . " F
  980. LEFT OUTER JOIN " . WORKLIST . " w on F.worklist_id = w.id
  981. LEFT JOIN " . PROJECTS . " p on p.project_id = w.project_id
  982. WHERE (F.paid = 1 AND F.withdrawn = 0 AND F.expense = 0 AND F.user_id = u.id)
  983. AND w.status IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')
  984. AND p.project_id = " . $this->getProjectId() . "
  985. ) as totalEarnings
  986. FROM " . BIDS . " b
  987. LEFT JOIN " . WORKLIST . " w ON b.worklist_id = w.id
  988. LEFT JOIN " . PROJECTS . " p ON p.project_id = w.project_id
  989. LEFT JOIN " . USERS . " u ON b.bidder_id = u.id
  990. WHERE b.accepted = 1
  991. AND w.status IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')
  992. AND p.project_id = " . $this->getProjectId() . "
  993. ORDER BY totalEarnings DESC";
  994. if($result = mysql_query($query)) {
  995. $developers = array();
  996. if(mysql_num_rows($result) > 0) {
  997. while($row = mysql_fetch_assoc($result)) {
  998. $developers[$row['id']] = $row;
  999. }
  1000. } else {
  1001. return false;
  1002. }
  1003. } else {
  1004. return false;
  1005. }
  1006. return $developers;
  1007. }
  1008. public function getContributors() {
  1009. $query = "
  1010. SELECT DISTINCT u.id, u.nickname
  1011. FROM " . FEES . " f
  1012. LEFT JOIN " . WORKLIST . " w ON f.worklist_id = w.id
  1013. LEFT JOIN " . PROJECTS . " p ON p.project_id = w.project_id
  1014. LEFT JOIN " . USERS . " u ON f.user_id = u.id
  1015. WHERE f.paid = 1
  1016. AND w.status IN ('Working', 'Functional', 'SvnHold', 'Review', 'Completed', 'Done')
  1017. AND p.project_id = " . $this->getProjectId() . "
  1018. ORDER BY f.date DESC";
  1019. $result = mysql_query($query);
  1020. if ($result) {
  1021. $contributors = array();
  1022. if (mysql_num_rows($result) > 0) {
  1023. while ($row = mysql_fetch_assoc($result)) {
  1024. $contributors[] = $row;
  1025. }
  1026. } else {
  1027. return false;
  1028. }
  1029. } else {
  1030. return false;
  1031. }
  1032. return $contributors;
  1033. }
  1034. public function getActiveJobs() {
  1035. $query = "
  1036. SELECT `id`, `summary`, `status`, `sandbox`
  1037. FROM " . WORKLIST . " w
  1038. WHERE w.status IN ('Bidding', 'Working', 'Functional', 'SvnHold', 'Review', 'Completed')
  1039. AND w.project_id = " . $this->getProjectId() . "
  1040. ORDER BY w.created ASC";
  1041. $result = mysql_query($query);
  1042. if($result) {
  1043. $jobs = array();
  1044. if (mysql_num_rows($result) > 0) {
  1045. while ($row = mysql_fetch_assoc($result)) {
  1046. $jobs[] = $row;
  1047. }
  1048. } else {
  1049. return false;
  1050. }
  1051. } else {
  1052. return false;
  1053. }
  1054. return $jobs;
  1055. }
  1056. public function getDevelopersLastActivity($userId) {
  1057. $sql = "SELECT MAX(change_date) FROM " . STATUS_LOG . " s
  1058. LEFT JOIN " . WORKLIST . " w ON s.worklist_id = w.id
  1059. LEFT JOIN " . PROJECTS . " p on p.project_id = w.project_id
  1060. WHERE s.user_id = '$userId' AND p.project_id = " . $this->getProjectId();
  1061. $res = mysql_query($sql);
  1062. if($res && $row = mysql_fetch_row($res)){
  1063. $lastActivity = strtotime($row[0]);
  1064. $rightNow = time();
  1065. if($lastActivity == '') {
  1066. return false;
  1067. } else {
  1068. if(($rightNow - $lastActivity) > 604800) { //if greater than a week i.e. 7*24*60*60 in seconds
  1069. return date('d-F-Y', $lastActivity);
  1070. } else {
  1071. return (formatableRelativeTime($lastActivity, 2) . " ago");
  1072. }
  1073. }
  1074. }
  1075. return false;
  1076. }
  1077. public function getPaymentStats() {
  1078. $query = "SELECT u.id, u.nickname, f.worklist_id, f.amount, f.paid FROM " . FEES . " f
  1079. LEFT JOIN " . WORKLIST . " w ON f.worklist_id = w.id
  1080. LEFT JOIN " . USERS . " u ON f.user_id = u.id
  1081. WHERE w.status = 'Done' AND w. project_id = " . $this->getProjectId() . "
  1082. AND f.withdrawn = 0 AND f. expense = 0
  1083. ORDER BY f.paid, f.worklist_id ASC";
  1084. if ($result = mysql_query($query)) {
  1085. $payments = array();
  1086. if(mysql_num_rows($result) > 0) {
  1087. while ($row = mysql_fetch_assoc($result)) {
  1088. $payments[] = $row;
  1089. }
  1090. return $payments;
  1091. } else {
  1092. return false;
  1093. }
  1094. } else {
  1095. return false;
  1096. }
  1097. }
  1098. /**
  1099. * Return project_id based on project name
  1100. */
  1101. public function getIdFromName($name) {
  1102. $query = "SELECT `project_id` FROM `" . PROJECTS . "`
  1103. WHERE `name` = '" . mysql_real_escape_string($name) . "'";
  1104. $result = mysql_query($query);
  1105. if (mysql_num_rows($result)) {
  1106. $row = mysql_fetch_assoc($result);
  1107. $project_id = $row['project_id'];
  1108. return $project_id;
  1109. } else {
  1110. return false;
  1111. }
  1112. }
  1113. function getOwnerCompany() {
  1114. if (!$this->getInternal()) {
  1115. return $this->getName();
  1116. } else {
  1117. return "High Fidelity Inc.";
  1118. }
  1119. }
  1120. public function makeApiRequest(
  1121. $path,
  1122. $method,
  1123. $token,
  1124. $params = array(),
  1125. $json = false) {
  1126. // Define response defaults
  1127. $error = false;
  1128. $message = false;
  1129. $data = false;
  1130. $postString = '';
  1131. $headers = array('Accept: application/json', 'User-Agent: Worklist.net');
  1132. // Define variables required for API
  1133. if ($path == 'login/oauth/access_token') {
  1134. $apiURL = 'https://github.com/' . $path;
  1135. } else {
  1136. $apiURL = GITHUB_API_URL . $path;
  1137. }
  1138. $credentials = array(
  1139. 'client_id' => urlencode($this->github_id),
  1140. 'client_secret' => urlencode($this->github_secret)
  1141. );
  1142. $postArray = array_merge($params, $credentials);
  1143. if ($json) {
  1144. $postString = json_encode($params);
  1145. } else {
  1146. foreach ($postArray as $key => $value) {
  1147. $postString .= $key . '=' . $value . '&';
  1148. }
  1149. rtrim($postString,'&');
  1150. }
  1151. // Initialize cURL
  1152. $curl = curl_init();
  1153. if ($method == 'POST') {
  1154. if ($token && $path != 'login/oauth/access_token') {
  1155. $headers[] = 'Authorization: token ' . $token;
  1156. }
  1157. curl_setopt($curl, CURLOPT_POST, count($postArray));
  1158. curl_setopt($curl, CURLOPT_POSTFIELDS, $postString);
  1159. } else if ($method == 'GET') {
  1160. $apiURL .= '?' . $postString;
  1161. if ($token && $path != 'login/oauth/access_token') {
  1162. $apiURL .= (!empty($postString) ? '&' : '') . 'access_token=' . $token;
  1163. }
  1164. }
  1165. //set the url, number of POST vars, POST data
  1166. curl_setopt($curl, CURLOPT_URL, $apiURL);
  1167. curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  1168. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  1169. try {
  1170. $apiResponse = curl_exec($curl);
  1171. if ($apiResponse && !curl_errno($curl)) {
  1172. $error = false;
  1173. $message = "API Call executed successfully";
  1174. $data = json_decode($apiResponse, true);
  1175. } elseif (curl_errno($curl)) {
  1176. $error = true;
  1177. $curlError = curl_error($curl);
  1178. $message = "There was an error processing your request - ERR " . $curlError;
  1179. $data = array(
  1180. 'error' => $curlError);
  1181. }
  1182. } catch(Exception $ex) {
  1183. $error = true;
  1184. $message = $ex;
  1185. $data = array(
  1186. 'error' => $ex
  1187. );
  1188. };
  1189. return array(
  1190. 'error' => $error,
  1191. 'message' => $message,
  1192. 'data' => $data);
  1193. }
  1194. public function extractOwnerAndNameFromRepoURL() {
  1195. $repoDetails = array();
  1196. // Get rid of protocol, domain and .git extension
  1197. $removeFromString = array(
  1198. 'http://',
  1199. 'https://',
  1200. 'github.com',
  1201. 'www.github.com',
  1202. '.git');
  1203. $cleanedRepoURL = str_replace($removeFromString, '', $this->getRepository());
  1204. $explodedRepoURL = explode('/', $cleanedRepoURL);
  1205. $repoDetails['owner'] = $explodedRepoURL[1];
  1206. $repoDetails['name'] = $explodedRepoURL[2];
  1207. return $repoDetails;
  1208. }
  1209. public function pull_request($payload) {
  1210. $headLabel = $payload->pull_request->head->label;
  1211. $labelComponents = explode(':', $headLabel);
  1212. $jobNumber = trim($labelComponents[1]);
  1213. // Try to extract job number from head repository label
  1214. if (preg_match('/^[0-9]{3,}$/', $labelComponents[1])) {
  1215. $workItem = new WorkItem();
  1216. // We have what looks like a workitem number, see if it exists
  1217. // and if it does, we set job to completed and post comment to
  1218. // journal
  1219. if ($workItem->idExists($jobNumber)
  1220. && $payload->pull_request->state == 'closed') {
  1221. $workItem->loadById($jobNumber);
  1222. $pullRequestNumber = $payload->pull_request->number;
  1223. $pullRequestURL = $payload->pull_request->html_url;
  1224. $pullRequestBase = $payload->pull_request->base->label;
  1225. $pullRequestStatus = $payload->pull_request->merged == 'true'
  1226. ? "closed and merged"
  1227. : "closed but not merged";
  1228. $message =
  1229. "#{$jobNumber} - Pull request {$pullRequestNumber}\n\n" .
  1230. "({$pullRequestURL}) has been {$pullRequestStatus} into {$pullRequestBase}";
  1231. sendJournalNotification($message);
  1232. if ($payload->pull_request->merged == 'true') {
  1233. $journal_message = "Job #" . $jobNumber . ' has been automatically set to *Completed*';
  1234. sendJournalNotification($journal_message);
  1235. $workItem->setStatus('Completed');
  1236. $workItem->addFeesToCompletedJob(true);
  1237. $workItem->save();
  1238. }
  1239. }
  1240. }
  1241. }
  1242. }