PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/application/models/FindingTable.php

https://bitbucket.org/openfisma-ondemand/openfisma
PHP | 395 lines | 326 code | 11 blank | 58 comment | 5 complexity | 43a8f06e7e67017adde8d027e6284bf6 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, GPL-3.0, Apache-2.0, EPL-1.0
  1. <?php
  2. /**
  3. * Copyright (c) 2010 Endeavor Systems, Inc.
  4. *
  5. * This file is part of OpenFISMA.
  6. *
  7. * OpenFISMA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
  8. * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
  9. * version.
  10. *
  11. * OpenFISMA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  12. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with OpenFISMA. If not, see
  16. * {@link http://www.gnu.org/licenses/}.
  17. */
  18. /**
  19. * FindingTable
  20. *
  21. * @uses Fisma_Doctrine_Table
  22. * @package Model
  23. * @copyright (c) Endeavor Systems, Inc. 2009 {@link http://www.endeavorsystems.com}
  24. * @author Josh Boyd <joshua.boyd@endeavorsystems.com>
  25. * @license http://www.openfisma.org/content/license GPLv3
  26. */
  27. class FindingTable extends Fisma_Doctrine_Table implements Fisma_Search_Searchable,
  28. Fisma_Search_CustomChunkSize_Interface
  29. {
  30. protected $_customLogicalNames = array(
  31. 'createdTs' => 'Created',
  32. 'modifiedTs' => 'Updated'
  33. );
  34. protected $_viewUrl = '/finding/remediation/view/id/';
  35. /**
  36. * Because the finding model is quite complex, it has a smaller-than-normal index chunk size which
  37. * uses less memory and should provide a more responsive UI.
  38. *
  39. * @var int
  40. */
  41. const INDEX_CHUNK_SIZE = 20;
  42. /**
  43. * Implement the interface for Searchable
  44. */
  45. public function getSearchableFields()
  46. {
  47. return array (
  48. 'id' => array(
  49. 'initiallyVisible' => true,
  50. 'label' => 'ID',
  51. 'sortable' => true,
  52. 'type' => 'integer',
  53. 'formatter' => 'Fisma.TableFormat.recordLink',
  54. 'formatterParameters' => array(
  55. 'prefix' => '/finding/remediation/view/id/'
  56. )
  57. ),
  58. 'legacyFindingKey' => array(
  59. 'initiallyVisible' => false,
  60. 'sortable' => true,
  61. 'type' => 'text'
  62. ),
  63. 'discoveredDate' => array(
  64. 'initiallyVisible' => false,
  65. 'sortable' => true,
  66. 'type' => 'date',
  67. 'formatter' => 'date'
  68. ),
  69. 'auditYear' => array(
  70. 'initiallyVisible' => false,
  71. 'sortable' => true,
  72. 'type' => 'integer'
  73. ),
  74. 'createdTs' => array(
  75. 'initiallyVisible' => true,
  76. 'sortable' => true,
  77. 'type' => 'datetime',
  78. 'formatter' => 'date'
  79. ),
  80. 'createdByUser' => array(
  81. 'initiallyVisible' => false,
  82. 'label' => 'Creator',
  83. 'join' => array(
  84. 'model' => 'User',
  85. 'relation' => 'CreatedBy',
  86. 'field' => 'displayName'
  87. ),
  88. 'sortable' => true,
  89. 'type' => 'text'
  90. ),
  91. 'residualRisk' => array(
  92. 'enumValues' => $this->getEnumValues('residualRisk'),
  93. 'initiallyVisible' =>
  94. Fisma::configuration()->getConfig('threat_type') == 'residual_risk' ? true : false,
  95. 'sortable' => true,
  96. 'type' => 'enum',
  97. 'hidden' => Fisma::configuration()->getConfig('threat_type') == 'residual_risk' ? false : true
  98. ),
  99. 'threatLevel' => array(
  100. 'enumValues' => $this->getEnumValues('threatLevel'),
  101. 'initiallyVisible' =>
  102. Fisma::configuration()->getConfig('threat_type') == 'threat_level' ? true : false,
  103. 'sortable' => true,
  104. 'type' => 'enum'
  105. ),
  106. 'threat' => array(
  107. 'initiallyVisible' => false,
  108. 'sortable' => true,
  109. 'type' => 'text'
  110. ),
  111. 'pocUser' => array(
  112. 'initiallyVisible' => true,
  113. 'label' => 'Finding_Point_of_Contact',
  114. 'join' => array(
  115. 'model' => 'User',
  116. 'relation' => 'PointOfContact',
  117. 'field' => 'displayName'
  118. ),
  119. 'sortable' => true,
  120. 'type' => 'text'
  121. ),
  122. 'pocOrg' => array(
  123. 'initiallyVisible' => false,
  124. 'extraCriteria' => array(
  125. 'organizationSubtree' => array(
  126. 'idField' => 'pocOrgId',
  127. 'idProvider' => 'OrganizationTable::getOrganizationSubtreeIds',
  128. 'label' => 'Organizational Unit',
  129. 'renderer' => 'text',
  130. 'query' => 'oneInput',
  131. ),
  132. 'organizationChildren' => array(
  133. 'idField' => 'responsibleOrganizationId',
  134. 'idProvider' => 'OrganizationTable::getOrganizationChildrenIds',
  135. 'label' => 'Managed Under',
  136. 'renderer' => 'text',
  137. 'query' => 'oneInput',
  138. )
  139. ),
  140. 'label' => 'Finding_Point_of_Contact_Organization',
  141. 'join' => array(
  142. 'model' => 'Organization',
  143. 'relation' => 'PointOfContact.ReportingOrganization',
  144. 'field' => 'nickname'
  145. ),
  146. 'sortable' => true,
  147. 'type' => 'text'
  148. ),
  149. 'organization' => array(
  150. 'initiallyVisible' => true,
  151. 'extraCriteria' => array(
  152. // This criterion requires the responsibleOrganizationId field to be indexed on finding (see below)
  153. 'organizationSubtree' => array(
  154. 'idField' => 'responsibleOrganizationId',
  155. 'idProvider' => 'OrganizationTable::getOrganizationSubtreeIds',
  156. 'label' => 'Organizational Unit',
  157. 'renderer' => 'text',
  158. 'query' => 'oneInput',
  159. ),
  160. 'organizationChildren' => array(
  161. 'idField' => 'responsibleOrganizationId',
  162. 'idProvider' => 'OrganizationTable::getOrganizationChildrenIds',
  163. 'label' => 'Managed Under',
  164. 'renderer' => 'text',
  165. 'query' => 'oneInput',
  166. )
  167. ),
  168. 'label' => 'Organization/System',
  169. 'join' => array(
  170. 'model' => 'Organization',
  171. 'relation' => 'Organization',
  172. 'field' => 'nickname'
  173. ),
  174. 'sortable' => true,
  175. 'type' => 'text'
  176. ),
  177. 'parentOrganization' => array(
  178. 'initiallyVisible' => false,
  179. 'label' => 'Parent Organization',
  180. 'join' => array(
  181. 'model' => 'Organization',
  182. 'relation' => 'ParentOrganization',
  183. 'field' => 'nickname'
  184. ),
  185. 'sortable' => true,
  186. 'type' => 'text'
  187. ),
  188. 'source' => array(
  189. 'initiallyVisible' => false,
  190. 'label' => 'Source',
  191. 'join' => array(
  192. 'model' => 'Source',
  193. 'relation' => 'Source',
  194. 'field' => 'nickname'
  195. ),
  196. 'sortable' => true,
  197. 'type' => 'text'
  198. ),
  199. 'securityControl' => array(
  200. 'initiallyVisible' => false,
  201. 'label' => 'Security Control',
  202. 'join' => array(
  203. 'model' => 'SecurityControl',
  204. 'relation' => 'SecurityControl',
  205. 'field' => 'code'
  206. ),
  207. 'sortable' => true,
  208. 'type' => 'text'
  209. ),
  210. 'description' => array(
  211. 'initiallyVisible' => false,
  212. 'sortable' => false,
  213. 'type' => 'text'
  214. ),
  215. 'recommendation' => array(
  216. 'initiallyVisible' => false,
  217. 'sortable' => false,
  218. 'type' => 'text'
  219. ),
  220. 'jsonComments' => array(
  221. 'initiallyVisible' => false,
  222. 'sortable' => false,
  223. 'type' => 'text',
  224. 'label' => 'Comments',
  225. 'formatter' => 'Fisma.TableFormat.formatComments'
  226. ),
  227. 'mitigationStrategy' => array(
  228. 'initiallyVisible' => false,
  229. 'sortable' => false,
  230. 'type' => 'text'
  231. ),
  232. 'originalEcd' => array(
  233. 'initiallyVisible' => false,
  234. 'sortable' => true,
  235. 'type' => 'date',
  236. 'formatter' => 'date'
  237. ),
  238. 'currentEcd' => array(
  239. 'initiallyVisible' => true,
  240. 'sortable' => true,
  241. 'type' => 'date',
  242. 'formatter' => 'Fisma.TableFormat.formatDuedate'
  243. ),
  244. 'nextDueDate' => array(
  245. 'initiallyVisible' => true,
  246. 'sortable' => true,
  247. 'type' => 'date',
  248. 'formatter' => 'Fisma.TableFormat.formatDuedate'
  249. ),
  250. 'countermeasuresEffectiveness' => array(
  251. 'enumValues' => $this->getEnumValues('countermeasuresEffectiveness'),
  252. 'initiallyVisible' => false,
  253. 'sortable' => true,
  254. 'type' => 'enum',
  255. 'hidden' => Fisma::configuration()->getConfig('threat_type') == 'residual_risk' ? false : true
  256. ),
  257. 'countermeasures' => array(
  258. 'initiallyVisible' => false,
  259. 'sortable' => true,
  260. 'type' => 'text',
  261. 'hidden' => Fisma::configuration()->getConfig('threat_type') == 'residual_risk' ? false : true
  262. ),
  263. 'workflow' => array(
  264. 'initiallyVisible' => false,
  265. 'label' => 'Workflow',
  266. 'sortable' => true,
  267. 'type' => 'text',
  268. 'join' => array(
  269. 'model' => 'Workflow',
  270. 'relation' => 'CurrentStep.Workflow',
  271. 'field' => 'name'
  272. )
  273. ),
  274. 'workflowStep' => array(
  275. 'initiallyVisible' => true,
  276. 'label' => 'Workflow Step',
  277. 'sortable' => true,
  278. 'type' => 'text',
  279. 'join' => array(
  280. 'model' => 'WorkflowStep',
  281. 'relation' => 'CurrentStep',
  282. 'field' => 'name'
  283. )
  284. ),
  285. 'isResolved' => array(
  286. 'initiallyVisible' => false,
  287. 'label' => 'Finding_Status',
  288. 'sortable' => true,
  289. 'type' => 'boolean'
  290. ),
  291. 'closedTs' => array(
  292. 'initiallyVisible' => false,
  293. 'sortable' => true,
  294. 'type' => 'datetime',
  295. 'formatter' => 'date'
  296. ),
  297. 'deleted_at' => array(
  298. 'hidden' => true,
  299. 'type' => 'datetime'
  300. ),
  301. 'responsibleOrganizationId' => array(
  302. 'hidden' => true,
  303. 'type' => 'integer'
  304. ),
  305. 'pocOrgId' => array(
  306. 'hidden' => true,
  307. 'join' => array(
  308. 'model' => 'Organization',
  309. 'relation' => 'PointOfContact.ReportingOrganization',
  310. 'field' => 'id'
  311. ),
  312. 'type' => 'integer'
  313. ),
  314. 'uploadid' => array(
  315. 'initiallyVisible' => false,
  316. 'sortable' => true,
  317. 'type' => 'integer'
  318. )
  319. );
  320. }
  321. /**
  322. * Return a list of fields which are used for access control
  323. *
  324. * @return array
  325. */
  326. public function getAclFields()
  327. {
  328. return array(
  329. 'pocUser' => 'CurrentUser::getAclDisplayName',
  330. 'responsibleOrganizationId' => 'FindingTable::getOrganizationIds'
  331. );
  332. }
  333. /**
  334. * Provide ID list for ACL filter
  335. *
  336. * @return array
  337. */
  338. public static function getOrganizationIds()
  339. {
  340. $currentUser = CurrentUser::getInstance();
  341. $organizationIds = $currentUser->getOrganizationsByPrivilege('finding', 'read')->toKeyValueArray('id', 'id');
  342. return $organizationIds;
  343. }
  344. /**
  345. * Implement required interface for custom chunk size.
  346. *
  347. * @return int
  348. */
  349. public function getIndexChunkSize()
  350. {
  351. return self::INDEX_CHUNK_SIZE;
  352. }
  353. /**
  354. * Return the query to fetch one attachment (if any) from a finding
  355. *
  356. * @param int $findingId THe id of the Finding to get
  357. * @param int $attachmentId The id of the Attachment to get
  358. *
  359. * @return Doctrine_Query
  360. */
  361. public static function getAttachmentQuery($findingId, $attachmentId)
  362. {
  363. return Doctrine_Query::create()
  364. ->from('Finding f')
  365. ->leftJoin('f.Attachments a')
  366. ->where('f.id = ?', $findingId)
  367. ->andWhere('a.id = ?', $attachmentId);
  368. }
  369. protected $_editableFields = array(
  370. 'pocId',
  371. 'auditYear',
  372. 'description',
  373. 'recommendation',
  374. 'mitigationStrategy',
  375. 'resourcesRequired',
  376. 'currentEcd',
  377. 'threatLevel',
  378. 'threat',
  379. 'countermeasuresEffectiveness',
  380. 'countermeasures',
  381. 'securityControlId',
  382. 'sourceId'
  383. );
  384. }