index.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. //TODO: Modify this to use controllers/guards
  2. /* API Routes for /api/jira/ (Unguarded Routes) */
  3. var config = require('../../config');
  4. var logger = require('../../utils/logger');
  5. var fs = require('fs');
  6. var ip = require('ip');
  7. var url = require('url');
  8. var Client = require('node-rest-client').Client;
  9. var JiraRestClient = new Client();
  10. var router = require('express').Router();
  11. //Middleware to use for every request
  12. router.use(function (req, res, next) {
  13. next();
  14. });
  15. router.route('/issue')
  16. //Create a new issue in JIRA
  17. .post(function (req, res) {
  18. //Check that a cookie exists first and foremost. This resource requires authentication.
  19. if (req.body.cookie) {
  20. //Also check that the summary, description and toolId were supplied
  21. if (req.body.summary && req.body.description && req.body.toolId && req.body.issueType) {
  22. //At this point, it is safe to attempt to retrieve the data
  23. var cookie = req.body.cookie,
  24. summary = req.body.summary,
  25. description = req.body.description,
  26. toolId = req.body.toolId,
  27. issueType = req.body.issueType;
  28. //Arguments to the POST request
  29. var args = {
  30. data: {
  31. fields: {
  32. project: {
  33. //Project ID SHOULD NOT change. If it does change in JIRA, update the config
  34. id: config.jira.toolSupport.projectId
  35. },
  36. issuetype: {
  37. //Issuetype ID SHOULD NOT change. If it does change in JIRA, update the config
  38. id: issueType
  39. },
  40. //Summary that was passed in by the user
  41. summary: summary,
  42. customfield_10501: {
  43. //JIRA REQUIRES that this be a string and not a number despite the fact that it is represented as a number in JSON
  44. //Regardless, cast to a string. If it was supplied as a string already, this should have no effect
  45. id: "" + toolId
  46. },
  47. //Description that was passed in by the user
  48. description: description
  49. }
  50. },
  51. headers: {
  52. cookie: "JSESSIONID=" + cookie,
  53. "Content-Type": "application/json"
  54. }
  55. };
  56. JiraRestClient.post(_constructUrl(config.jira.api.issue), args, function (data, response) {
  57. var statusCode = response.statusCode;
  58. //HTTP 201 | Created
  59. if (statusCode == 201) {
  60. res.status(201).send({
  61. success: true,
  62. issue: {
  63. id: data.id,
  64. key: data.key,
  65. link: _constructIssueUrl(data.key)
  66. }
  67. });
  68. logger.info("[" + ip.address() + "] JIRA Issue Created: " + data.key);
  69. }
  70. //HTTP 400 | Bad Request
  71. else if (statusCode == 400) {
  72. res.status(400).send({
  73. success: false,
  74. error: "Invalid Input. Check for missing fields or invalid values (see 'errorMessages' for specific errors).",
  75. errorMessages: data.errorMessages
  76. });
  77. }
  78. else if (statusCode == 401) {
  79. res.status(401).send({
  80. success: false,
  81. error: "Authorization failure."
  82. });
  83. }
  84. //Fallback
  85. else {
  86. res.status(statusCode).send({
  87. success: false,
  88. error: "Uncaught Error. Status Code= " + statusCode
  89. })
  90. }
  91. });
  92. }
  93. else {
  94. res.status(401).send('Missing field. Check that you supplied a description, summary, tool id AND issue type id.');
  95. }
  96. }
  97. else {
  98. res.status(401).send('Missing cookie. This resource requires authentication. Check that you supplied a cookie.');
  99. }
  100. });
  101. router.route('/user')
  102. //Get a particular users details (display name/avatar)
  103. .get(function (req, res) {
  104. //Check that the cookie and the username were passed in
  105. //BOTH are required, so one check can be used (validity checks are handle below (HTTP 401/404)
  106. //If it was, continue
  107. if (req.query.cookie && req.query.username) {
  108. var cookie = req.query.cookie;
  109. var username = req.query.username;
  110. var args = {
  111. headers: {
  112. "cookie": "JSESSIONID=" + cookie,
  113. "Content-Type": "application/json"
  114. },
  115. parameters: {username: username}
  116. };
  117. JiraRestClient.get(_constructUrl(config.jira.api.user), args, function (data, response) {
  118. //Possible HTTP Status Codes according to JIRA REST API Docs: 200,401,404
  119. var statusCode = response.statusCode;
  120. //HTTP 200 | OK
  121. if (statusCode == 200) {
  122. //TODO: Cache the avatar
  123. res.status(200).send({
  124. success: true,
  125. avatar: data.avatarUrls["32x32"],
  126. displayName: data.displayName
  127. });
  128. }
  129. //HTTP 401 | Unauthorized
  130. else if (statusCode == 401) {
  131. res.status(401).send({
  132. success: false,
  133. error: "Authentication Error. User is not authenticated."
  134. })
  135. }
  136. //HTTP 404 | Not Found
  137. else if (statusCode == 404) {
  138. res.status(404).send({
  139. success: false,
  140. error: "Not Found. The requested user was not found."
  141. })
  142. }
  143. //Fallback
  144. else {
  145. res.status(statusCode).send({
  146. success: false,
  147. error: "Uncaught Error. Status Code= " + statusCode
  148. })
  149. }
  150. });
  151. }
  152. //If either param was not passed in, send a HTTP 400 back to the client
  153. else {
  154. res.status(400).send('Missing parameters. Check that you supplied a valid JIRA cookie and a valid JIRA username.');
  155. }
  156. });
  157. router.route('/login')
  158. //Login to JIRA
  159. .post(function (req, res) {
  160. if (req.body.username && req.body.password) {
  161. var username = req.body.username;
  162. var password = req.body.password;
  163. var args = {
  164. data: {
  165. "username": username,
  166. "password": password
  167. },
  168. headers: {
  169. "Content-Type": "application/json"
  170. }
  171. };
  172. JiraRestClient.post(_constructUrl(config.jira.api.login), args, function (data, response) {
  173. var statusCode = response.statusCode;
  174. //HTTP 200 | Success
  175. if (statusCode == 200) {
  176. res.send({
  177. success: true,
  178. session: data.session
  179. });
  180. logger.info("[" + ip.address() + "] JIRA login success for user: " + username);
  181. }
  182. //HTTP 401 | Unauthorized
  183. else if (statusCode == 401) {
  184. res.status(401).send({
  185. success: false,
  186. error: "Authentication Error. Invalid user credentials."
  187. });
  188. logger.info("[" + ip.address() + "] JIRA login failure for user: " + username);
  189. }
  190. //HTTP 403 | Forbidden
  191. else if (statusCode == 403) {
  192. res.status(403).send({
  193. success: false,
  194. error: "Login Denied. CAPTCHA required, connection throttled, etc. Try logging in later."
  195. });
  196. logger.info("[" + ip.address() + "] JIRA login failure for user: " + username);
  197. }
  198. //Fallback
  199. else {
  200. res.status(statusCode).send({
  201. success: false,
  202. error: "Uncaught Error. Status Code= " + statusCode
  203. });
  204. logger.info("[" + ip.address() + "] JIRA login failure for user: " + username);
  205. }
  206. });
  207. }
  208. //If either param was not passed in, send a HTTP 400 back to the client
  209. else {
  210. res.status(400).send('Missing parameters. Check that you supplied a valid username and password.');
  211. }
  212. })
  213. //Logout of JIRA
  214. .delete(function (req, res) {
  215. if (req.query.cookie) {
  216. var args = {
  217. headers: {
  218. "cookie": "JSESSIONID=" + req.query.cookie,
  219. "Content-Type": "application/json"
  220. }
  221. };
  222. JiraRestClient.delete(_constructUrl(config.jira.api.login), args, function (data, response) {
  223. var statusCode = response.statusCode;
  224. if (statusCode == 204) {
  225. res.status(204).send({loggedOut: true});
  226. logger.info("[" + ip.address() + "] Logout succeeded.");
  227. }
  228. else if (statusCode == 401) {
  229. res.status(401).send({loggedOut: false});
  230. logger.info("[" + ip.address() + "] Logout failed.");
  231. }
  232. else {
  233. res.status(statusCode).send({
  234. loggedOut: false,
  235. error: "Uncaught Error. Status Code= " + statusCode
  236. });
  237. logger.info("[" + ip.address() + "] Logout failed.");
  238. }
  239. });
  240. }
  241. else {
  242. res.status(400).send('Missing cookie. Make sure you supplied a valid cookie.');
  243. }
  244. })
  245. //Get the user's username from the session cookie
  246. .get(function (req, res) {
  247. //Check that the cookie was actually passed in
  248. if (req.query.cookie) {
  249. //Grab cookie from the query params
  250. var cookie = req.query.cookie;
  251. //Pack the cookie into the header (for authentication)
  252. var args = {
  253. headers: {
  254. "cookie": "JSESSIONID=" + cookie,
  255. "Content-Type": "application/json"
  256. }
  257. };
  258. JiraRestClient.get(_constructUrl(config.jira.api.login), args, function (data, response) {
  259. var statusCode = response.statusCode;
  260. //HTTP 200 | OK
  261. if (statusCode == 200) {
  262. res.status(200).send({
  263. success: true,
  264. name: data.name
  265. });
  266. }
  267. //HTTP 401 | Unauthorized
  268. else if (statusCode == 401) {
  269. res.status(401).send({
  270. success: false,
  271. error: "Authentication Error. User is not authenticated."
  272. })
  273. }
  274. //Fallback
  275. else {
  276. res.status(statusCode).send({
  277. success: false,
  278. error: "Uncaught Error. Status Code= " + statusCode
  279. })
  280. }
  281. });
  282. }
  283. //If the cookie was not passed in, send an HTTP 400 back to the client
  284. else {
  285. res.status(400).send('Missing parameters. Check that you supplied a valid JIRA cookie.');
  286. }
  287. });
  288. //Helper method for constructing URLs for JIRA REST API
  289. function _constructUrl(endpoint) {
  290. var fullUrl = url.format({
  291. protocol: 'https',
  292. hostname: config.jira.url,
  293. port: 443,
  294. pathname: endpoint
  295. });
  296. return decodeURIComponent(fullUrl);
  297. }
  298. //Helper method for constructing URLs for JIRA issues
  299. function _constructIssueUrl(key) {
  300. var fullUrl = url.format({
  301. protocol: 'https',
  302. hostname: config.jira.url,
  303. pathname: '/browse/' + key
  304. });
  305. return decodeURIComponent(fullUrl);
  306. }
  307. module.exports = router;