PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/bugtracking/int_youtrack.php

https://github.com/viglesiasce/testlink
PHP | 454 lines | 324 code | 35 blank | 95 comment | 8 complexity | 0221c4d2ef710c5f744a548dd454fe50 MD5 | raw file
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Sergey Andreev (sergey.andreev@jetbrains.com])
  5. * Date: Jun 17, 2010
  6. */
  7. define('BUG_INTERFACE_CLASSNAME', "youtrackInterface");
  8. class youtrackInterface extends bugtrackingInterface {
  9. //members to store the bugtracking information, these values are
  10. //set in the actual subclasses of this class
  11. var $dbHost = null;
  12. var $dbName = null;
  13. var $dbUser = null;
  14. var $dbPass = null;
  15. var $dbType = null;
  16. var $showBugURL = null;
  17. var $enterBugURL = null;
  18. var $dbCharSet = null;
  19. var $tlCharSet = null;
  20. //members to work with YouTrack
  21. var $username = YOUTRACK_USERNAME;
  22. var $password = YOUTRACK_PASSWORD;
  23. var $baseURL = YOUTRACK_URL;
  24. var $urlRest = null;
  25. var $urlStates = null;
  26. var $urlLogin = null;
  27. var $urlIssue = null;
  28. var $urlCreateIssue = null;
  29. var $urlGetIssue = null;
  30. var $cookie = null;
  31. var $statusMap = array();
  32. //private vars don't touch
  33. var $dbConnection = null;
  34. var $Connected = false;
  35. /*
  36. *
  37. * FUNCTIONS NOT CALLED BY TestLink (helpers):
  38. *
  39. **/
  40. /**
  41. * Constructor of youtrackInterface
  42. * Defines all needed variables, performs login (stores recieved cookies), and gets info abour available statuses
  43. *
  44. * @return void
  45. */
  46. function youtrackInterface() {
  47. $this->urlRest = $this->baseURL . 'rest/';
  48. $this->urlStates = $this->urlRest . BUG_TRACK_REST_STATES;
  49. $this->urlLogin = $this->urlRest . BUG_TRACK_REST_LOGIN;
  50. $this->urlIssue = $this->urlRest . BUG_TRACK_SHOW_ISSUE;
  51. $this->urlCreateIssue = $this->urlIssue;
  52. $this->urlGetIssue = $this->urlIssue;
  53. $this->showBugURL = $this->baseURL . BUG_TRACK_SHOW_ISSUE;
  54. $this->enterBugURL = $this->baseURL . BUG_TRACK_NEW_ISSUE;
  55. try {
  56. $this->session = curl_init($this->urlLogin);
  57. $this->login();
  58. $this->getStatuses();
  59. }
  60. catch (Exception $e) {
  61. tLog($e->getMessage(), 'ERROR');
  62. }
  63. }
  64. /**
  65. * This method perform login to YouTrack
  66. * with Username and Password from config file (youtrack.php.ini)
  67. *
  68. * @return resource
  69. */
  70. function login() {
  71. $loginData = 'login=' . $this->username . '&password=' . $this->password;
  72. try {
  73. $this->session = curl_init();
  74. curl_setopt($this->session, CURLOPT_URL, $this->urlLogin);
  75. curl_setopt($this->session, CURLOPT_POST, true);
  76. curl_setopt($this->session, CURLOPT_POSTFIELDS, $loginData);
  77. curl_setopt($this->session, CURLOPT_HEADER, false);
  78. curl_setopt($this->session, CURLOPT_HEADERFUNCTION, array($this, 'readHeader'));
  79. curl_setopt($this->session, CURLOPT_RETURNTRANSFER, true);
  80. curl_close($this->session);
  81. return $this->session;
  82. }
  83. catch (Exception $e) {
  84. tLog($e->getMessage(), 'WARNING');
  85. }
  86. }
  87. /**
  88. * This method defines cookies owner User
  89. *
  90. * @return mixed xml that describes cookies owner
  91. */
  92. function getUserName() {
  93. $tmp = $this->urlRest . 'user/current';
  94. try {
  95. $session = curl_init();
  96. curl_setopt($session, CURLOPT_URL, $tmp);
  97. curl_setopt($session, CURLOPT_POST, false);
  98. curl_setopt($session, CURLOPT_HEADER, false);
  99. curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
  100. curl_setopt($session, CURLOPT_COOKIE, $this->cookie);
  101. curl_setopt($session, CURLOPT_VERBOSE, true);
  102. $response = curl_exec($session);
  103. curl_close($session);
  104. }
  105. catch (Exception $e) {
  106. tLog($e->getMessage(), 'WARNING');
  107. }
  108. return $response;
  109. }
  110. /**
  111. * This method grabs cookies from response on Login operation
  112. * and stores them to reuse in other requests
  113. *
  114. * @param $string - HTTP response headers
  115. * @return void
  116. */
  117. function readHeader($string) {
  118. if (!strncmp($string, "Set-Cookie:", 11)) {
  119. $cookie_str = trim(substr($string, 11, -1));
  120. $this->cookie = explode("\n", $cookie_str);
  121. $this->cookie = explode('=', $this->cookie[0]);
  122. $cookie_name = trim(array_shift($this->cookie));
  123. $cookiearr[$cookie_name] = trim(implode('=', $this->cookie));
  124. }
  125. $this->cookie = "";
  126. if (trim($string) == "") {
  127. foreach ($cookiearr as $key => $value)
  128. {
  129. $this->cookie .= "$key=$value; ";
  130. }
  131. }
  132. }
  133. /**
  134. * This method gets issue from YouTrack by its ID
  135. *
  136. * @param $id - issue ID in YouTrack
  137. * @return xml formatted issue or error response
  138. */
  139. function getIssue($id) {
  140. $this->session = curl_init();
  141. $get_issue_url = $this->urlGetIssue . $id;
  142. try {
  143. curl_setopt($this->session, CURLOPT_URL, $get_issue_url);
  144. curl_setopt($this->session, CURLOPT_POST, false);
  145. curl_setopt($this->session, CURLOPT_HEADER, false);
  146. curl_setopt($this->session, CURLOPT_RETURNTRANSFER, true);
  147. curl_setopt($this->session, CURLOPT_COOKIE, $this->cookie);
  148. curl_setopt($this->session, CURLOPT_VERBOSE, false);
  149. $response = curl_exec($this->session);
  150. curl_close($this->session);
  151. }
  152. catch (Exception $e) {
  153. tLog($e->getMessage(), 'WARNING');
  154. }
  155. return $response;
  156. }
  157. function isIssueExists($id) {
  158. $this->session = curl_init();
  159. $get_issue_exists = $this->urlGetIssue . $id . "/exists";
  160. try {
  161. curl_setopt($this->session, CURLOPT_URL, $get_issue_exists);
  162. curl_setopt($this->session, CURLOPT_POST, false);
  163. curl_setopt($this->session, CURLOPT_HEADER, false);
  164. curl_setopt($this->session, CURLOPT_RETURNTRANSFER, true);
  165. curl_setopt($this->session, CURLOPT_COOKIE, $this->cookie);
  166. curl_setopt($this->session, CURLOPT_VERBOSE, false);
  167. $response = curl_exec($this->session);
  168. curl_close($this->session);
  169. }
  170. catch (Exception $e) {
  171. tLog($e->getMessage(), 'WARNING');
  172. }
  173. return $response;
  174. }
  175. /**
  176. * This methods gets list of available Statuses from YouTrack
  177. * @return void
  178. */
  179. function getStatuses() {
  180. try {
  181. $session = curl_init();
  182. curl_setopt($session, CURLOPT_URL, $this->urlStates);
  183. curl_setopt($session, CURLOPT_POST, false);
  184. curl_setopt($session, CURLOPT_HEADER, false);
  185. curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
  186. curl_setopt($session, CURLOPT_COOKIE, $this->cookie);
  187. curl_setopt($session, CURLOPT_VERBOSE, false);
  188. $response = curl_exec($session);
  189. curl_close($session);
  190. }
  191. catch (Exception $e) {
  192. tLog($e->getMessage(), 'WARNING');
  193. }
  194. try {
  195. $xml = new SimpleXMLElement($response);
  196. foreach ($xml->state as $state)
  197. {
  198. $this->statusMap[(string) $state['name']] = (string) $state['resolved'];
  199. }
  200. }
  201. catch (Exception $e) {
  202. tLog($e->getMessage(), 'WARNING');
  203. }
  204. }
  205. /**
  206. * Mock method overloaded from the bugtrackingInterface.
  207. * This function fakes establishing the database connection to the
  208. * bugtracking system.
  209. *
  210. **/
  211. function connect() {
  212. $this->Connected = true;
  213. return $this->Connected;
  214. }
  215. /**
  216. * Mock method overloaded from the bugtrackingInterface.
  217. * This function returns the fake state of the db connection
  218. *
  219. **/
  220. function isConnected() {
  221. return $this->Connected;
  222. }
  223. /**
  224. * Mock method overloaded from the bugtrackingInterface.
  225. * This function imitates closing the db connection (if any)
  226. *
  227. **/
  228. function disconnect() {
  229. $this->Connected = false;
  230. }
  231. /**
  232. * Method overloaded from the bugtrackingInterface.
  233. * Returns the URL to the bugtracking page for viewing
  234. * the bug with the given ID.
  235. * This function is not directly called by TestLink at the moment
  236. *
  237. * @param bug ID in YouTrack
  238. *
  239. * @return string returns a complete URL to view the given bug, or false if the bug
  240. * wasn't found
  241. *
  242. **/
  243. function buildViewBugURL($id) {
  244. return ($this->showBugURL . $id);
  245. }
  246. /**
  247. * Method overloaded from the bugtrackingInterface.
  248. * Returns the status of the bug with the given ID.
  249. * This function is not directly called by TestLink.
  250. *
  251. * @param $id - bug id in YouTrack
  252. * @return returns the status of the given bug, or "error" if the bug
  253. * was not found
  254. */
  255. function getBugStatus($id) {
  256. $issue_status_id = "error";
  257. try {
  258. $issueXml = $this->getIssue($id);
  259. $xml = new SimpleXMLElement($issueXml);
  260. foreach ($xml->field as $field) {
  261. switch ((string) $field['name']) {
  262. case 'state':
  263. $issue_status_id = (string) $field->value;
  264. break;
  265. }
  266. }
  267. } catch (Exception $e) {
  268. tLog($e->getMessage(), 'WARNING');
  269. }
  270. return $issue_status_id;
  271. }
  272. /**
  273. * Method overloaded from the bugtrackingInterface.
  274. * Returns the status in a readable form for the bug with the given ID.
  275. * This function is not directly called by TestLink.
  276. *
  277. * @param bug ID in YouTrack
  278. *
  279. * @return returns the status (in a readable form) of the given bug, or "error"
  280. * if the bug is not found
  281. **/
  282. function getBugStatusString($id) {
  283. $status_name = "error";
  284. $status = $this->getBugStatus($id);
  285. $status_completion = $this->statusMap["$status"];
  286. if ('false' == $status_completion) {
  287. $status_name = "<b>" . $id . "</b> (" . $status . ") ";
  288. }
  289. elseif ('true' == $status_completion) {
  290. $status_name = "<del>" . $status . "</del>";
  291. $status_name = "<b>" . $id . "</b> (" . $status_name . ") ";
  292. } else {
  293. $status_name = "Bug " . $id . " does not exist in YouTrack, or you don't have permissions to access.";
  294. }
  295. return $status_name;
  296. }
  297. /*
  298. *
  299. * FUNCTIONS CALLED BY TestLink:
  300. *
  301. **/
  302. /**
  303. * Method overloaded from the bugtrackingInterface.
  304. * default implementation for fetching the bug summary from the
  305. * bugtracking system
  306. *
  307. * @param bug ID in YouTrack
  308. *
  309. * @return string returns the bug summary (if bug is found), or Error message
  310. *
  311. **/
  312. function getBugSummaryString($id) {
  313. $issueXml = $this->getIssue($id);
  314. $issue_summary = "Error: Summary not found in YouTrack for issue $id";
  315. try {
  316. $xml = new SimpleXMLElement($issueXml);
  317. foreach ($xml->field as $field) {
  318. switch ((string) $field['name']) {
  319. case 'summary':
  320. $issue_summary = (string) $field->value;
  321. break;
  322. }
  323. }
  324. } catch (Exception $e) {
  325. tLog($e->getMessage(), 'WARNING');
  326. }
  327. return $issue_summary;
  328. }
  329. /**
  330. * Method overloaded from the bugtrackingInterface.
  331. * Checks a bug id for validity
  332. *
  333. * @return bool returns true if the bugid has the right format, false else
  334. **/
  335. function checkBugID($id) {
  336. $is_valid = true;
  337. if (trim($id) == "") {
  338. $is_valid = false;
  339. }
  340. if ($is_valid) {
  341. $forbidden_chars = '/[/]/';
  342. if (preg_match($forbidden_chars, $id)) {
  343. $is_valid = false;
  344. }
  345. }
  346. return $is_valid;
  347. }
  348. /**
  349. * Method overloaded from the bugtrackingInterface.
  350. * return the maximum length in chars of a bug id
  351. * @return int the maximum length of a bugID, let it be 32
  352. */
  353. function getBugIDMaxLength() {
  354. return 32;
  355. }
  356. /**
  357. * Method overloaded from the bugtrackingInterface.
  358. * default implementation for generating a link to the bugtracking page for viewing
  359. * the bug with the given id in a new page
  360. *
  361. * @param bug ID in YouTrack
  362. *
  363. * @return string returns a complete URL to view the bug (if found in db)
  364. **/
  365. function buildViewBugLink($bugID, $bWithSummary = false) {
  366. $link = "<a href='" . $this->buildViewBugURL($bugID) . "' target='_blank'>";
  367. $status = $this->getBugStatusString($bugID);
  368. if (!is_null($status)) {
  369. $link .= $status;
  370. }
  371. else
  372. $link .= $bugID;
  373. if ($bWithSummary) {
  374. $summary = $this->getBugSummaryString($bugID);
  375. if (!is_null($summary)) {
  376. $link .= " : " . $summary;
  377. }
  378. }
  379. $link .= "</a>";
  380. return $link;
  381. }
  382. /**
  383. * Method overloaded from the bugtrackingInterface.
  384. * checks if bug id is present on BTS
  385. * Function has to be overloaded on child classes
  386. *
  387. * @return bool
  388. **/
  389. function checkBugID_existence($id) {
  390. try {
  391. $responseXML = $this->isIssueExists($id);
  392. if ((stristr($responseXML, "<error>") == TRUE)) {
  393. return false;
  394. }
  395. }
  396. catch (Exception $e) {
  397. tLog($e->getMessage(), 'WARNING');
  398. return false;
  399. }
  400. return true;
  401. }
  402. }
  403. ?>