storm.module

Tracking 6.x-2.x branch
  1. drupal
    1. 6 contributions/storm/storm.module

Main module file for the Storm module. Basic Storm module provides a dashboard and some API functions. 1: Hooks (help, perm, init, menu, theme) 2: Dashboard 3: Admin Settings 4: Date / time manipulation 5: Taxation functions 6: Storm Icons 7: SQL Functions 8: Node form theming

Functions & methods

NameDescription
storm_admin_settings@function Defines the administration settings form for the Storm module
storm_admin_settings_form_submit
storm_admin_settings_icons_path_validateValidate Icon Path form element.
storm_attributes_bydomain
storm_attribute_access
storm_attribute_value
storm_blockImplementation of hook_block().
storm_dashboardFunction to create a dashboard (call to theme function)
storm_dashboard_get_linksReturn links array for the storm dashboard.
storm_dateext_expand
storm_dateext_validate
storm_datetime_expand
storm_datetime_validate
storm_db_rewrite_sql
storm_dependent_select_process
storm_elements
storm_form_alter
storm_get_assignment_optionsGet a list of people and teams for select boxes
storm_help@function Implementation of hook_help().
storm_icon
storm_icon_add
storm_icon_add_node
storm_icon_default
storm_icon_delete
storm_icon_delete_node
storm_icon_edit
storm_icon_edit_node
storm_icon_l
storm_icon_recache
storm_init
storm_menu@function Implementation of hook_menu().
storm_perm@function Implementation of hook_perm().
storm_rewrite_sql
storm_storm_dashboard_links
storm_storm_dashboard_typesImplementation of hook_storm_dashboard_types(). Defines dashboard types page and block. This can be used as an example for other types
storm_taxation@function Calculates taxation for Storm nodes
storm_theme
storm_views_pre_renderImplements hook_views_pre_render to add the storm_icon_add
_storm_dashboard_sort_linksHelper function for storm_dashboard_get_links(). Order dashboard links by their weight. This is a uasort callback function.
_storm_datetime_to_gmtimestamp
_storm_date_to_gmtimestamp
_storm_gmtimestamp_to_date
_storm_gmtimestamp_to_datetime
_storm_gmtimestamp_without_time
_storm_icon_urlencode_helper
_storm_number_of_itemsHelper function to count nodes of type destination module with parent nid of type source module.
_storm_strtotime
_timestamp_to_gm
_timetostr

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * Main module file for the Storm module.
  5. * Basic Storm module provides a dashboard and some API functions.
  6. * 1: Hooks (help, perm, init, menu, theme)
  7. * 2: Dashboard
  8. * 3: Admin Settings
  9. * 4: Date / time manipulation
  10. * 5: Taxation functions
  11. * 6: Storm Icons
  12. * 7: SQL Functions
  13. * 8: Node form theming
  14. */
  15. // HOOKS
  16. /**
  17. * @function
  18. * Implementation of hook_help().
  19. */
  20. function storm_help($path, $arg) {
  21. $output = '';
  22. switch ($path) {
  23. case "admin/help#storm":
  24. $output = '<p>'. t("Provides a complete project management environment") .'</p>';
  25. break;
  26. case "admin/help#stormattribute":
  27. $output = '<p>'. t("Provides attributes support for Storm") .'</p>';
  28. $output .= '<p>'. t("Price Modes - Price modes are used calculate the price of the Storm node when added to an invoice. A price mode can be added to any Storm node type and any type can be added to an invoice. When a node is added to an invoice it looks for a price mode in the following order:") .'</p>';
  29. $output .= '<p>'. t("Ticket, Task, Project, Organization.") .'</p>';
  30. $output .= '<p>'. t("It will take the price mode for it's current node or the first valid node type above in it's tree. e.g. For a task node type, if that node doesn't have a price mode it will look at the project and then the organization and take the first one it finds. This means you can define a price mode for the organization and it will be used for all nodes under that organization unless it's given a different one.") .'</p>';
  31. $output .= '<p>'. t("The following price modes keys are defined:") .'<br />';
  32. $output .= '<ul>';
  33. $output .= '<li>'. t("not applicable - This is ignored by the system. This means that no price mode is defined.") .'</li>';
  34. $output .= '<li>'. t("fixed - Price of 0 is used (so the invoice would need to be manually updated.") .'</li>';
  35. $output .= '<li>'. t("hourly - Price taken from node and multiplied by billing duration.") .'</li>';
  36. $output .= '<li>'. t("daily - Price given is for daily rate. This price is divided by 8 hours and then multiplied by the billing duration.") .'</li>';
  37. $output .= '<li>'. t("fixed_price - Will use the price given as the fixed price for that invoice item.") .'</li>';
  38. $output .= '</ul>';
  39. break;
  40. }
  41. return $output;
  42. }
  43. /**
  44. * @function
  45. * Implementation of hook_perm().
  46. */
  47. function storm_perm() {
  48. return array(
  49. 'Storm: access dashboard',
  50. 'Storm: access administration pages',
  51. );
  52. }
  53. // Note #370120. It is intended to move these calls to pages which specifically need them rather than on hook_init.
  54. function storm_init() {
  55. drupal_add_js(drupal_get_path('module', 'storm') .'/storm.js', 'module', 'header', FALSE);
  56. drupal_add_css(drupal_get_path('module', 'storm') .'/storm.css', 'module');
  57. }
  58. /**
  59. * @function
  60. * Implementation of hook_menu().
  61. */
  62. function storm_menu() {
  63. $items = array();
  64. $dashboard_types = module_invoke_all('storm_dashboard_types');
  65. foreach ($dashboard_types as $type => $type_info) {
  66. if (isset($type_info['url'])) {
  67. $title = isset($type_info['title']) ? $type_info['title'] : 'Storm Dashboard';
  68. $items[$type_info['url']] = array(
  69. 'title' => $title,
  70. 'description' => $title,
  71. 'page callback' => 'storm_dashboard',
  72. 'page arguments' => array($type),
  73. 'access arguments' => array('Storm: access dashboard'),
  74. 'parent' => '',
  75. 'type' => MENU_NORMAL_ITEM,
  76. );
  77. if (isset($type_info['menu_options'])) {
  78. $items[$type_info['url']] = array_merge($items[$type_info['url']], $type_info['menu_options']);
  79. }
  80. }
  81. }
  82. $items['admin/settings/storm'] = array(
  83. 'title' => 'Storm',
  84. 'description' => 'Storm administration page',
  85. 'page callback' => 'drupal_get_form',
  86. 'page arguments' => array('storm_admin_settings'),
  87. 'access arguments' => array('Storm: access administration pages'),
  88. 'type' => MENU_NORMAL_ITEM,
  89. );
  90. $items['admin/settings/storm/storm'] = array(
  91. 'title' => 'Storm',
  92. 'description' => 'Storm administration page',
  93. 'access arguments' => array('Storm: access administration pages'),
  94. 'type' => MENU_DEFAULT_LOCAL_TASK,
  95. 'weight' => -100,
  96. );
  97. $items['storm/attributes'] = array(
  98. 'title' => 'Attributes',
  99. 'description' => 'Storm attributes',
  100. 'page callback' => 'storm_attribute_list',
  101. 'access arguments' => array('Storm: access administration pages'),
  102. 'file' => 'storm.admin.inc',
  103. 'type' => MENU_NORMAL_ITEM,
  104. 'weight' => 11,
  105. );
  106. $items['storm/attributes/add'] = array(
  107. 'title' => 'Add a new attribute',
  108. 'description' => 'Storm attributes',
  109. 'page callback' => 'drupal_get_form',
  110. 'page arguments' => array('storm_attribute_add'),
  111. 'access arguments' => array('Storm: access administration pages'),
  112. 'file' => 'storm.admin.inc',
  113. 'type' => MENU_CALLBACK);
  114. $items['storm/attributes/edit/%'] = array(
  115. 'title' => 'Edit an attribute',
  116. 'description' => 'Storm attributes',
  117. 'page callback' => 'drupal_get_form',
  118. 'page arguments' => array('storm_attribute_edit', 3),
  119. 'access arguments' => array('Storm: access administration pages'),
  120. 'file' => 'storm.admin.inc',
  121. 'type' => MENU_CALLBACK);
  122. $items['storm/attributes/delete/%'] = array(
  123. 'title' => 'Delete an attribute',
  124. 'description' => 'Storm attributes',
  125. 'page callback' => 'drupal_get_form',
  126. 'page arguments' => array('storm_attribute_delete', 3),
  127. 'access arguments' => array('Storm: access administration pages'),
  128. 'file' => 'storm.admin.inc',
  129. 'type' => MENU_CALLBACK);
  130. $items['storm/attributes/domain/autocomplete'] = array(
  131. 'title' => 'List of attributes',
  132. 'description' => 'Storm attributes',
  133. 'page callback' => '_storm_attribute_domain_autocomplete',
  134. 'page arguments' => array(4),
  135. 'access arguments' => array('Storm: access administration pages'),
  136. 'file' => 'storm.admin.inc',
  137. 'type' => MENU_CALLBACK);
  138. return $items;
  139. }
  140. function storm_theme() {
  141. return array(
  142. 'storm_form_group' => array(
  143. 'file' => 'storm.theme.inc',
  144. 'arguments' => array('header', 'form'),
  145. ),
  146. 'datetime' => array(
  147. 'file' => 'storm.theme.inc',
  148. 'arguments' => array('element'),
  149. ),
  150. 'dateext' => array(
  151. 'file' => 'storm.theme.inc',
  152. 'arguments' => array('element'),
  153. ),
  154. 'storm_link' => array(
  155. 'file' => 'storm.theme.inc',
  156. 'arguments' => array('source_module', 'destination_module', 'node_nid', 'weight'),
  157. ),
  158. 'storm_list_report' => array(
  159. 'file' => 'storm.theme.inc',
  160. 'arguments' => array('header', 'rows', 'title', 'footer', 'headtitle'),
  161. ),
  162. 'storm_report' => array(
  163. 'file' => 'storm.theme.inc',
  164. 'arguments' => array('header', 'content', 'title', 'footer'),
  165. ),
  166. 'storm_view_item' => array(
  167. 'file' => 'storm.theme.inc',
  168. 'arguments' => array('label', 'value'),
  169. ),
  170. 'storm_dashboard' => array(
  171. 'file' => 'storm.theme.inc',
  172. 'arguments' => array('links' => array()),
  173. ),
  174. 'storm_dashboard_block' => array(
  175. 'file' => 'storm.theme.inc',
  176. 'arguments' => array('links' => array()),
  177. ),
  178. 'storm_dashboard_link' => array(
  179. 'file' => 'storm.theme.inc',
  180. 'arguments' => array('link_blocks' => array()),
  181. ),
  182. 'storm_dashboard_links_weight_table' => array(
  183. 'file' => 'storm.theme.inc',
  184. 'arguments' => array('form' => array()),
  185. ),
  186. 'storm_number_items' => array(
  187. 'file' => 'storm.theme.inc',
  188. 'arguments' => array('number' => ''),
  189. ),
  190. 'storm_attribute_list' => array(
  191. 'file' => 'storm.theme.inc',
  192. 'arguments' => array('form'),
  193. ),
  194. );
  195. }
  196. /**
  197. * Function to create a dashboard (call to theme function)
  198. *
  199. * @param string $type dashboard type, used for storm_get_dashboard_links
  200. * @param null|string $theme Theme function to use, if omitted it uses storm_dashboard
  201. * @return string themed string
  202. */
  203. function storm_dashboard($type = 'page') {
  204. $types = module_invoke_all('storm_dashboard_types');
  205. // only set Page Title if it has a url, so there is a menu entry for that
  206. // The block type has no url and shouldn't change the title!
  207. if (isset($types[$type]['url']) && isset($types[$type]['title'])) {
  208. drupal_set_title($types[$type]['title']);
  209. }
  210. drupal_add_css(drupal_get_path('module', 'storm') .'/storm-dashboard.css');
  211. $link_blocks = storm_dashboard_get_links(TRUE, $type);
  212. if (!empty($link_blocks)) {
  213. // DIVIDE LINKS INTO TWO BLOCKS
  214. $count = ceil(count($link_blocks) / 2);
  215. $link_blocks = array_chunk($link_blocks, $count);
  216. }
  217. $theme = isset($types[$type]['theme']) ? $types[$type]['theme'] : 'storm_dashboard';
  218. $content = theme($theme, $link_blocks);
  219. return $content;
  220. }
  221. /**
  222. * Return links array for the storm dashboard.
  223. *
  224. * @param bool $check_active when FALSE, returns all links, no matter if activated or not (needed for admin settings)
  225. * @param string $type
  226. * @return array dashboard links
  227. */
  228. function storm_dashboard_get_links($check_active = TRUE, $type = 'page') {
  229. $links = module_invoke_all('storm_dashboard_links', $type);
  230. if (!empty($links)) {
  231. $default_dashboard_settings = variable_get('storm_'. $type .'dashboard_settings', array());
  232. $weight = 0;
  233. foreach ($links as $key => &$link_array) {
  234. // ACTIVE CHECK
  235. if ($check_active && isset($default_dashboard_settings[$link_array['path']]['active']) && $default_dashboard_settings[$link_array['path']]['active'] == FALSE) {
  236. unset($links[$key]);
  237. continue;
  238. }
  239. // MODULE EXIST CHECK
  240. if (isset($link_array['destination_module']) && !module_exists($link_array['destination_module'])) {
  241. unset($links[$key]);
  242. continue;
  243. }
  244. // ACCESS CHECK
  245. if (!empty($link_array['access_callback'])) {
  246. if (function_exists($link_array['access_callback'])) {
  247. if (!isset($link_array['access_arguments'])) {
  248. $link_array['access_arguments'] = "";
  249. }
  250. // USE THE ACCESS CHECK OF THE MENU API
  251. _menu_check_access($link_array, $link_array['map']);
  252. }
  253. }
  254. elseif (isset($link_array['access_arguments'])) {
  255. $link_array['access'] = user_access($link_array['access_arguments']);
  256. }
  257. else {
  258. $link_array['access'] = TRUE;
  259. }
  260. if (!$link_array['access']) {
  261. unset($links[$key]);
  262. }
  263. if (isset($default_dashboard_settings[$link_array['path']]['weight'])) {
  264. $link_array['weight'] = $default_dashboard_settings[$link_array['path']]['weight'];
  265. }
  266. elseif (!isset($link_array['weight'])) {
  267. $link_array['weight'] = $weight;
  268. $weight++;
  269. }
  270. }
  271. // HOOK FOR ALTERING LINKS
  272. drupal_alter('storm_dashboard_links', $links, $type);
  273. // SORT LINKS BY WEIGHT
  274. uasort($links, '_storm_dashboard_sort_links');
  275. }
  276. return $links;
  277. }
  278. /**
  279. * Helper function for storm_dashboard_get_links().
  280. * Order dashboard links by their weight.
  281. * This is a uasort callback function.
  282. *
  283. * @see uasort()
  284. * @param array $a dashboard link array
  285. * @param array $b dashboard link array
  286. * @return int
  287. */
  288. function _storm_dashboard_sort_links($a, $b) {
  289. if (intval($a['weight']) == intval($b['weight'])) {
  290. return 0;
  291. }
  292. elseif (intval($a['weight']) < intval($b['weight'])) {
  293. return -1;
  294. }
  295. else {
  296. return 1;
  297. }
  298. }
  299. function storm_storm_dashboard_links($type) {
  300. $links = array();
  301. if ($type == 'page' || $type == 'block') {
  302. $links[] = array(
  303. 'title' => t('Configuration'),
  304. 'icon' => 'stormconfiguration',
  305. 'path' => 'admin/settings/storm',
  306. 'params' => array(),
  307. 'access_arguments' => 'Storm: access administration pages',
  308. 'node_type' => '',
  309. 'add_type' => '',
  310. 'map' => array(),
  311. 'weight' => 15,
  312. );
  313. $links[] = array(
  314. 'theme' => 'storm_dashboard_link',
  315. 'title' => t('Attributes'),
  316. 'icon' => 'stormattributes',
  317. 'path' => 'storm/attributes',
  318. 'params' => array(),
  319. 'access_arguments' => 'Storm: access administration pages',
  320. 'map' => array(),
  321. 'weight' => 14,
  322. );
  323. }
  324. return $links;
  325. }
  326. /**
  327. * Implementation of hook_storm_dashboard_types().
  328. * Defines dashboard types page and block.
  329. * This can be used as an example for other types
  330. * @return array
  331. */
  332. function storm_storm_dashboard_types() {
  333. return array(
  334. 'page' => array(
  335. // URL: menu path which should be used, if omitted no menu item will be created
  336. 'url' => 'storm',
  337. // title: Required. Title of menu item, page title and title for the storm settings
  338. 'title' => 'Storm dashboard',
  339. // description: Required. Description for the fieldset in the storm settings
  340. 'description' => t('You can disable or reorder the links from the !dashboard here', array('!dashboard' => l(t('dashboard'), 'storm'))),
  341. // theme: theme which should be used to display this dashboard. If omitted uses standard theme storm_dashboard
  342. 'theme' => 'storm_dashboard',
  343. // menu_options: This array will be merged into the default menu item array. If the menu should have special access arguments, title, it can be set here.
  344. // page callback and page argument shouldn't been overwritten.
  345. 'menu_options' => array(
  346. 'title' => 'Storm',
  347. 'description' => 'Storm dashboard',
  348. ),
  349. ),
  350. 'block' => array(
  351. 'title' => 'Dashboard block',
  352. 'description' => t('You can disable or reorder the links from the dashboard !block here', array('!block' => l(t('block'), 'admin/build/block'))),
  353. 'theme' => 'storm_dashboard_block',
  354. ),
  355. );
  356. }
  357. /**
  358. * Implementation of hook_block().
  359. */
  360. function storm_block($op = 'list', $delta = 0) {
  361. switch ($op) {
  362. case 'list' :
  363. // DASHBOARD AS TOP NAVIGATION
  364. $blocks['storm_dashboard_block']['info'] = t('Storm dashboard block');
  365. return $blocks;
  366. break;
  367. case 'view':
  368. switch ($delta) {
  369. // DASHBOARD AS BLOCK
  370. case 'storm_dashboard_block':
  371. $block = array(
  372. 'subject' => '',
  373. 'content' => storm_dashboard('block'),
  374. );
  375. return $block;
  376. }
  377. break;
  378. }
  379. }
  380. /**
  381. * @function
  382. * Defines the administration settings form for the Storm module
  383. */
  384. function storm_admin_settings() {
  385. $form = array();
  386. $w = -10;
  387. $form['icons'] = array(
  388. '#type' => 'fieldset',
  389. '#title' => t('Icons'),
  390. '#collapsed' => TRUE,
  391. '#collapsible' => TRUE,
  392. '#weight' => $w++,
  393. );
  394. $form['icons']['storm_icons_display'] = array(
  395. '#type' => 'checkbox',
  396. '#title' => t('Display Storm icons'),
  397. '#default_value' => variable_get('storm_icons_display', TRUE),
  398. '#description' => t('The icons that ship with Storm may not fit well with some themes. If this box is unchecked, icons will be hidden.'),
  399. '#weight' => $w++,
  400. );
  401. $form['icons']['storm_icons_path'] = array(
  402. '#type' => 'textfield',
  403. '#title' => t('Icons directory'),
  404. '#default_value' => variable_get('storm_icons_path', drupal_get_path('module', 'storm') .'/icons'),
  405. '#description' => t("The directory that contains Storm's icons."),
  406. '#weight' => $w++,
  407. '#element_validate' => array('storm_admin_settings_icons_path_validate'),
  408. );
  409. $form['lists'] = array(
  410. '#type' => 'fieldset',
  411. '#title' => t('Lists'),
  412. '#collapsed' => TRUE,
  413. '#collapsible' => TRUE,
  414. '#weight' => $w++,
  415. );
  416. $form['lists']['storm_default_items_per_page'] = array(
  417. '#type' => 'textfield',
  418. '#title' => t('Default Items per Page'),
  419. '#default_value' => variable_get('storm_default_items_per_page', 10),
  420. '#description' => t('Default items per page when viewing lists'),
  421. '#size' => 5,
  422. '#weight' => $w++
  423. );
  424. $form['reports'] = array(
  425. '#type' => 'fieldset',
  426. '#title' => t('Reports'),
  427. '#collapsed' => TRUE,
  428. '#collapsible' => TRUE,
  429. '#weight' => $w++,
  430. );
  431. $form['reports']['storm_report_header'] = array(
  432. '#type' => 'textarea',
  433. '#title' => t('Report header'),
  434. '#default_value' => variable_get('storm_report_header', ''),
  435. '#description' => t('The header that will appear on Storm reports'),
  436. '#weight' => $w++,
  437. );
  438. $form['yearsrange'] = array(
  439. '#type' => 'fieldset',
  440. '#title' => t('Years range in dates'),
  441. '#collapsed' => TRUE,
  442. '#collapsible' => TRUE,
  443. '#weight' => $w++,
  444. );
  445. $form['yearsrange']['group0'] = array(
  446. '#type' => 'markup',
  447. '#theme' => 'storm_form_group',
  448. '#weight' => $w++,
  449. );
  450. $form['yearsrange']['group0']['storm_yearsrangebegin'] = array(
  451. '#type' => 'select',
  452. '#title' => t('Begin'),
  453. '#options' => drupal_map_assoc(range(1970, 2037)),
  454. '#default_value' => variable_get('storm_yearsrangebegin', 2001),
  455. );
  456. $form['yearsrange']['group0']['storm_yearsrangeend'] = array(
  457. '#type' => 'select',
  458. '#title' => t('End'),
  459. '#options' => drupal_map_assoc(range(1970, 2037)),
  460. '#default_value' => variable_get('storm_yearsrangeend', 2012),
  461. );
  462. $form['taxation'] = array(
  463. '#type' => 'fieldset',
  464. '#title' => t('Taxation defaults'),
  465. '#collapsed' => TRUE,
  466. '#collapsible' => TRUE,
  467. '#weight' => $w++,
  468. );
  469. $form['taxation']['storm_tax1_app'] = array(
  470. '#type' => 'select',
  471. '#title' => t('Tax 1: Application'),
  472. '#default_value' => variable_get('storm_tax1_app', 1),
  473. '#description' => t('The method of application to use for Tax 1'),
  474. '#options' => array(
  475. 1 => t('Apply to item amount'),
  476. 0 => t('Do not apply tax'),
  477. ),
  478. '#weight' => $w++,
  479. );
  480. $form['taxation']['group0'] = array(
  481. '#type' => 'markup',
  482. '#theme' => 'storm_form_group',
  483. '#weight' => $w++,
  484. );
  485. $form['taxation']['group0']['storm_tax1_name'] = array(
  486. '#type' => 'textfield',
  487. '#title' => t('Tax 1: Name'),
  488. '#default_value' => variable_get('storm_tax1_name', 'VAT'),
  489. '#description' => t('The name to use for Tax 1'),
  490. '#weight' => $w++,
  491. );
  492. $form['taxation']['group0']['storm_tax1_percent'] = array(
  493. '#type' => 'textfield',
  494. '#title' => t('Tax 1: Default percentage'),
  495. '#default_value' => variable_get('storm_tax1_percent', 20),
  496. '#description' => t('Default percentage for Tax 1'),
  497. '#size' => 20,
  498. '#weight' => $w++
  499. );
  500. $form['taxation']['storm_tax2_app'] = array(
  501. '#type' => 'select',
  502. '#title' => t('Tax 2: Application'),
  503. '#default_value' => variable_get('storm_tax2_app', 0),
  504. '#description' => t('The method of application to use for Tax 2'),
  505. '#options' => array(
  506. 2 => t('Apply to total of item amount plus previous tax'),
  507. 1 => t('Apply to item amount'),
  508. 0 => t('Do not apply tax'),
  509. ),
  510. '#weight' => $w++,
  511. );
  512. $form['taxation']['group1'] = array(
  513. '#type' => 'markup',
  514. '#theme' => 'storm_form_group',
  515. '#weight' => $w++,
  516. );
  517. $form['taxation']['group1']['storm_tax2_name'] = array(
  518. '#type' => 'textfield',
  519. '#title' => t('Tax 2: Name'),
  520. '#default_value' => variable_get('storm_tax2_name', 'Tax 2 Name'),
  521. '#description' => t('The name to use for Tax 2'),
  522. '#weight' => $w++,
  523. );
  524. $form['taxation']['group1']['storm_tax2_percent'] = array(
  525. '#type' => 'textfield',
  526. '#title' => t('Tax 2: Default percentage'),
  527. '#default_value' => variable_get('storm_tax2_percent', 20),
  528. '#description' => t('Default percentage for Tax 2'),
  529. '#size' => 20,
  530. '#weight' => $w++,
  531. );
  532. $form['taxation']['storm_tax_display'] = array(
  533. '#type' => 'checkbox',
  534. '#title' => t('Display tax edit fields'),
  535. '#default_value' => variable_get('storm_tax_display', TRUE),
  536. '#description' => t('If disabled, all tax fields will use the default values and you will not be able to override them for any nodes until this setting is enabled again.'),
  537. '#weight' => $w++,
  538. );
  539. $form['taxation']['storm_tax2_display'] = array(
  540. '#type' => 'checkbox',
  541. '#title' => t('Display tax 2 edit fields'),
  542. '#default_value' => variable_get('storm_tax2_display', TRUE),
  543. '#description' => t('If disabled, tax 2 fields will use the default values and you will not be able to override them for any nodes until this setting is enabled again. This setting will be ignored unless the general "Display tax edit fields" setting is enabled above.'),
  544. '#weight' => $w++,
  545. );
  546. // DASHBOARD SETTINGS
  547. $form['storm_dashboard_settings'] = array(
  548. '#type' => 'fieldset',
  549. '#title' => t('Dashboard settings'),
  550. '#collapsible' => TRUE,
  551. '#collapsed' => TRUE,
  552. );
  553. $types = module_invoke_all('storm_dashboard_types');
  554. foreach ($types as $type => $type_data) {
  555. $all_links_options = array();
  556. $all_links = storm_dashboard_get_links(FALSE, $type);
  557. foreach ($all_links as $link) {
  558. $all_links_options[$link['path']] = l($link['title'], $link['path']);
  559. }
  560. $default_dashboard_settings = variable_get('storm_'. $type .'dashboard_settings', array());
  561. $form['storm_dashboard_settings'][$type] = array(
  562. '#type' => 'fieldset',
  563. '#title' => t($type_data['title']),
  564. '#description' => $type_data['description'],
  565. '#collapsible' => TRUE,
  566. '#collapsed' => TRUE,
  567. );
  568. $form['storm_dashboard_settings'][$type]['dashboard_links'] = array(
  569. '#theme' => 'storm_dashboard_links_weight_table',
  570. '#infix' => $type,
  571. );
  572. $weight = 0;
  573. foreach ($all_links_options as $path => $title) {
  574. $form['storm_dashboard_settings'][$type]['dashboard_links'][$path][$type .'_storm_dashboard_link_active_'. $path] = array(
  575. '#type' => 'checkbox',
  576. '#default_value' => isset($default_dashboard_settings[$path]['active']) ? $default_dashboard_settings[$path]['active'] : TRUE,
  577. );
  578. $form['storm_dashboard_settings'][$type]['dashboard_links'][$path][$type .'_storm_dashboard_link_weight_'. $path] = array(
  579. '#type' => 'weight',
  580. '#default_value' => isset($default_dashboard_settings[$path]['weight']) ? $default_dashboard_settings[$path]['weight'] : $weight,
  581. '#delta' => 30,
  582. );
  583. $form['storm_dashboard_settings'][$type]['dashboard_links'][$path]['#value'] = $title;
  584. $weight++;
  585. }
  586. }
  587. if (empty($form['#submit'])) {
  588. $form['#submit'] = array();
  589. }
  590. $form['#submit'] = array('storm_admin_settings_form_submit');
  591. return system_settings_form($form);
  592. }
  593. /**
  594. * Validate Icon Path form element.
  595. *
  596. * @param $form
  597. * @param $form_values
  598. */
  599. function storm_admin_settings_icons_path_validate($form, $form_values) {
  600. $icon_path_old = variable_get('storm_icons_path', drupal_get_path('module', 'storm') .'/icons');
  601. $icon_path = $form_values['values']['storm_icons_path'];
  602. // check if directory exists
  603. if (!is_dir($icon_path)) {
  604. form_set_error('storm_icons_path', t('Icon path %path does not exist', array('%path' => $icon_path)));
  605. }
  606. // if it exists and changed, delete cache, so there are no old values in the cache
  607. elseif ($icon_path != $icon_path_old) {
  608. cache_clear_all('storm:icons', 'cache', FALSE);
  609. }
  610. }
  611. function storm_admin_settings_form_submit($form, $form_state) {
  612. $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
  613. // RESET
  614. if ($op == t('Reset to defaults')) {
  615. $types = module_invoke_all('storm_dashboard_types');
  616. foreach ($types as $type => $type_data) {
  617. variable_del('storm_'. $type .'dashboard_settings');
  618. };
  619. return;
  620. }
  621. // GET OPTIONS
  622. $types = module_invoke_all('storm_dashboard_types');
  623. foreach ($types as $type => $type_data) {
  624. $all_links = storm_dashboard_get_links(FALSE, $type);
  625. $settings = array();
  626. foreach ($all_links as $link) {
  627. $path = $link['path'];
  628. $settings[$path]['active'] = $form_state['values'][$type .'_storm_dashboard_link_active_'. $path];
  629. $settings[$path]['weight'] = $form_state['values'][$type .'_storm_dashboard_link_weight_'. $path];
  630. }
  631. variable_set('storm_'. $type .'dashboard_settings', $settings);
  632. }
  633. }
  634. // DATE / TIME MANIPULATION
  635. function storm_elements() {
  636. $type['datetime'] = array(
  637. '#input' => TRUE,
  638. '#process' => array('storm_datetime_expand'),
  639. '#element_validate' => array('storm_datetime_validate'),
  640. '#default_value' => array(
  641. 'day' => format_date(time(), 'custom', 'j'),
  642. 'month' => format_date(time(), 'custom', 'n'),
  643. 'year' => format_date(time(), 'custom', 'Y'),
  644. 'hour' => format_date(time(), 'custom', 'H'),
  645. 'minute' => format_date(time(), 'custom', 'i'),
  646. ),
  647. );
  648. $type['dateext'] = array(
  649. '#input' => TRUE,
  650. '#process' => array('storm_dateext_expand'),
  651. '#element_validate' => array('storm_dateext_validate'),
  652. '#default_value' => time(),
  653. '#withnull' => FALSE,
  654. '#disable_date_popup' => FALSE,
  655. );
  656. return $type;
  657. }
  658. function storm_datetime_expand($element) {
  659. if (empty($element['#value'])) {
  660. $element['#value'] = array(
  661. 'day' => format_date(time(), 'custom', 'j'),
  662. 'month' => format_date(time(), 'custom', 'n'),
  663. 'year' => format_date(time(), 'custom', 'Y'),
  664. 'hour' => format_date(time(), 'custom', 'H'),
  665. 'minute' => format_date(time(), 'custom', 'i'),
  666. );
  667. }
  668. $element['#tree'] = TRUE;
  669. // Determine the order of day, month, year in the site's chosen date format.
  670. $format = variable_get('date_format_short', 'm/d/Y - H:i');
  671. $sort = array();
  672. $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j'));
  673. $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M'));
  674. $sort['year'] = strpos($format, 'Y');
  675. $sort['hour'] = strpos($format, 'H');
  676. $sort['minute'] = strpos($format, 'i');
  677. asort($sort);
  678. $order = array_keys($sort);
  679. // Output multi-selector for date.
  680. foreach ($order as $type) {
  681. switch ($type) {
  682. case 'year':
  683. $options = drupal_map_assoc(range(variable_get('storm_yearsrangebegin', 2001), variable_get('storm_yearsrangeend', 2012)));
  684. break;
  685. case 'month':
  686. $options = drupal_map_assoc(range(1, 12), 'map_month');
  687. break;
  688. case 'day':
  689. $options = drupal_map_assoc(range(1, 31));
  690. break;
  691. case 'hour':
  692. $options = drupal_map_assoc(range(0, 23));
  693. break;
  694. case 'minute':
  695. $options = drupal_map_assoc(range(0, 59));
  696. break;
  697. }
  698. $parents = $element['#parents'];
  699. $parents[] = $type;
  700. $element[$type] = array(
  701. '#type' => 'select',
  702. '#value' => $element['#value'][$type],
  703. '#attributes' => $element['#attributes'],
  704. '#options' => $options,
  705. );
  706. }
  707. return $element;
  708. }
  709. function storm_datetime_validate($form) {
  710. if (!checkdate($form['#value']['month'], $form['#value']['day'], $form['#value']['year'])) {
  711. form_error($form, t('The specified date is invalid.'));
  712. }
  713. }
  714. function storm_dateext_expand($element, $edit, $form_state, $form) {
  715. if (empty($element['#value'])) {
  716. if (!$element['#withnull']) {
  717. $element['#value'] = array(
  718. 'day' => format_date(time(), 'custom', 'j'),
  719. 'month' => format_date(time(), 'custom', 'n'),
  720. 'year' => format_date(time(), 'custom', 'Y'),
  721. );
  722. }
  723. else {
  724. $element['#value'] = array('day' => -1, 'month' => -1, 'year' => -1);
  725. }
  726. }
  727. $element['#tree'] = TRUE;
  728. // If date popup exists, we should use date popup,
  729. // but you can force to disable it by set disable_date_popup to true
  730. if (module_exists('date_popup') && (!isset($element['disable_date_popup']) || !$element['disable_date_popup'])) {
  731. // value is timestamp
  732. if (is_numeric($element['#value']) && $element['#value'] != 0) {
  733. $element['#value'] = array('popup' => format_date($element['#value'], 'custom', 'Y-m-d'));
  734. }
  735. // value is date array
  736. elseif (is_array($element['#value']) && !isset($element['#value']['popup']) && $element['#value']['day'] != -1) {
  737. $element['#value'] = array('popup' => sprintf("%04d-%02d-%02d", $element['#value']['year'], $element['#value']['month'], $element['#value']['day']));
  738. }
  739. elseif (is_numeric($element['#value']) || !isset($element['#value']['popup']) || (isset($element['#value']['day']) && $element['#value']['day'] == -1)) {
  740. $element['#value'] = array('popup' => '');
  741. }
  742. if (is_array($element['#value']['popup']) && isset($element['#value']['popup']['date'])) {
  743. $value = $element['#value']['popup']['date'];
  744. }
  745. else {
  746. $value = $element['#value']['popup'];
  747. }
  748. $current_year = date('Y');
  749. $begin = variable_get('storm_yearsrangebegin', 2001) - $current_year;
  750. if ($begin > 0) {
  751. $begin = '+'. $begin;
  752. }
  753. $end = variable_get('storm_yearsrangeend', 2012) - $current_year;
  754. if ($end > 0) {
  755. $end = '+'. $end;
  756. }
  757. $parents = $element['#parents'];
  758. $parents[] = 'popup';
  759. $element['popup'] = array(
  760. '#type' => 'date_popup',
  761. '#date_timezone' => date_default_timezone_name(),
  762. '#date_format' => "Y-m-d",
  763. '#date_year_range' => $begin .':'. $end,
  764. '#default_value' => $value,
  765. '#attributes' => $element['#attributes'],
  766. '#withnull' => $element['#withnull'],
  767. );
  768. }
  769. // fallback - use select boxes to choose the date
  770. else {
  771. // its a timestamp, convert it to a date format
  772. if (is_numeric($element['#value']) && $element['#value'] != 0) {
  773. $element['#value'] = _storm_gmtimestamp_to_date($element['#value']);
  774. }
  775. // Determine the order of day, month, year in the site's chosen date format.
  776. $format = variable_get('date_format_short', 'm/d/Y - H:i');
  777. $sort = array();
  778. $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j'));
  779. $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M'));
  780. $sort['year'] = strpos($format, 'Y');
  781. asort($sort);
  782. $order = array_keys($sort);
  783. // Output multi-selector for date.
  784. foreach ($order as $type) {
  785. switch ($type) {
  786. case 'year':
  787. $options = drupal_map_assoc(range(variable_get('storm_yearsrangebegin', 2001), variable_get('storm_yearsrangeend', 2012)));
  788. break;
  789. case 'month':
  790. $options = drupal_map_assoc(range(1, 12), 'map_month');
  791. break;
  792. case 'day':
  793. $options = drupal_map_assoc(range(1, 31));
  794. break;
  795. }
  796. if ($element['#withnull']) {
  797. $options = array('-1' => '-') + $options;
  798. }
  799. if (empty($element['#attributes'])) {
  800. $element['#attributes'] = array();
  801. }
  802. $parents = $element['#parents'];
  803. $parents[] = $type;
  804. $element[$type] = array(
  805. '#type' => 'select',
  806. '#value' => isset($element['#value'][$type]) ? $element['#value'][$type] : NULL,
  807. '#options' => $options,
  808. '#attributes' => array_merge(array('onchange' => "storm_datext_tonull(this, '". $element['#id'] ."')"), $element['#attributes']),
  809. );
  810. }
  811. }
  812. return $element;
  813. }
  814. function storm_dateext_validate($element, &$form_state) {
  815. // value is a string, convert it back to array
  816. if (is_array($element['#value']) && isset($element['#value']['popup'])) {
  817. if (!$element['#withnull'] && empty($element['#value']['popup']['date'])) {
  818. form_set_error($element, t('Field %field is required.', array('%field' => !empty($element['#title']) ? $element['#title'] : '')));
  819. }
  820. if (preg_match('/(\d{4})-(\d{2})-(\d{2})/', $element['#value']['popup']['date'], $matches)) {
  821. $element['#value'] = array();
  822. $element['#value']['day'] = (int) $matches[3];
  823. $element['#value']['month'] = (int) $matches[2];
  824. $element['#value']['year'] = (int) $matches[1];
  825. }
  826. else {
  827. if (!$element['#withnull'] && !empty($element['#value']['popup']['date'])) {
  828. form_set_error($element, t('Wrong Format for Field %field. Format should be YYYY-MM-DD.', array('%field' => !empty($element['#title']) ? $element['#title'] : '')));
  829. }
  830. $element['#value'] = array('day' => -1, 'month' => -1, 'year' => -1);
  831. }
  832. form_set_value($element, $element['#value'], $form_state);
  833. }
  834. if ($element['#value']['day'] == -1 && !$element['#withnull']) {
  835. form_set_error($element, t('Field %field is required.', array('%field' => !empty($element['#title']) ? $element['#title'] : '')));
  836. }
  837. if ($element['#value']['day'] != -1 && !checkdate($element['#value']['month'], $element['#value']['day'], $element['#value']['year'])) {
  838. form_error($element, t('The specified date is invalid.'));
  839. }
  840. return $element;
  841. }
  842. function storm_dependent_select_process($form, $edit, $form_state, $complete_form) {
  843. unset($form['#needs_validation']);
  844. return $form;
  845. }
  846. function _timestamp_to_gm($timestamp, $timezone=NULL) {
  847. if (!isset($timezone)) {
  848. global $user;
  849. if (variable_get('configurable_timezones', 1) && $user->uid && drupal_strlen($user->timezone)) {
  850. $timezone = $user->timezone;
  851. }
  852. else {
  853. $timezone = variable_get('date_default_timezone', 0);
  854. }
  855. }
  856. $timestamp -= $timezone;
  857. return $timestamp;
  858. }
  859. function _storm_date_to_gmtimestamp($date, $timezone=NULL) {
  860. if ($date['month'] == -1 || $date['year'] == -1 || $date['day'] == -1) {
  861. return NULL;
  862. }
  863. else {
  864. $gmttimestamp = gmmktime(0, 0, 0, intval($date['month']), intval($date['day']), intval($date['year']));
  865. return _timestamp_to_gm($gmttimestamp, $timezone);
  866. }
  867. }
  868. function _storm_datetime_to_gmtimestamp($datetime, $timezone=NULL) {
  869. $gmttimestamp = gmmktime(intval($datetime['hour']), intval($datetime['minute']), 0, intval($datetime['month']),
  870. intval($datetime['day']), intval($datetime['year']));
  871. return _timestamp_to_gm($gmttimestamp, $timezone);
  872. }
  873. function _storm_gmtimestamp_to_datetime($timestamp, $timezone=NULL) {
  874. $datetime = array(
  875. 'day' => format_date($timestamp, 'custom', 'j', $timezone),
  876. 'month' => format_date($timestamp, 'custom', 'n', $timezone),
  877. 'year' => format_date($timestamp, 'custom', 'Y', $timezone),
  878. 'hour' => (int)format_date($timestamp, 'custom', 'H', $timezone),
  879. 'minute' => (int)format_date($timestamp, 'custom', 'i', $timezone),
  880. );
  881. return $datetime;
  882. }
  883. function _storm_gmtimestamp_to_date($timestamp, $timezone=NULL) {
  884. if ($timestamp) {
  885. $date = array(
  886. 'day' => format_date($timestamp, 'custom', 'j', $timezone),
  887. 'month' => format_date($timestamp, 'custom', 'n', $timezone),
  888. 'year' => format_date($timestamp, 'custom', 'Y', $timezone),
  889. );
  890. }
  891. else {
  892. $date = array(
  893. 'day' => -1,
  894. 'month' => -1,
  895. 'year' => -1,
  896. );
  897. }
  898. return $date;
  899. }
  900. function _storm_gmtimestamp_without_time($timestamp, $timezone=NULL) {
  901. $date = _storm_gmtimestamp_to_date($timestamp, $timezone);
  902. $gmttimestamp = gmmktime(0, 0, 0, $date['month'], $date['day'], $date['year']);
  903. return _timestamp_to_gm($gmttimestamp, $timezone);
  904. }
  905. function _storm_strtotime($timestr='') {
  906. $timestr = drupal_substr($timestr, 0, 5);
  907. $time = array();
  908. $time['hour'] = 0;
  909. $time['minute'] = 0;
  910. $ar = explode(':', $timestr);
  911. if (is_array($ar)) {
  912. if (array_key_exists(0, $ar)) $time['hour'] = $ar[0];
  913. if (array_key_exists(1, $ar)) $time['minute'] = $ar[1];
  914. }
  915. return $time;
  916. }
  917. function _timetostr($time=array()) {
  918. $timestr = str_pad($time['hour'], 2, "0", STR_PAD_LEFT) .':'. str_pad($time['minute'], 2, "0", STR_PAD_RIGHT);
  919. return $timestr;
  920. }
  921. /**
  922. * @function
  923. * Calculates taxation for Storm nodes
  924. */
  925. function storm_taxation(&$node) {
  926. // If values are not set, then use default values
  927. if (!isset($node->tax1app)) {
  928. $node->tax1app = variable_get('storm_tax1_app', 'none');
  929. }
  930. if (!isset($node->tax1percent)) {
  931. $node->tax1percent = variable_get('storm_tax1_percent', '20');
  932. }
  933. if (!isset($node->tax2app)) {
  934. $node->tax2app = variable_get('storm_tax2_app', 'none');
  935. }
  936. if (!isset($node->tax2percent)) {
  937. $node->tax2percent = variable_get('storm_tax2_percent', '20');
  938. }
  939. switch ($node->tax1app) {
  940. case 0:
  941. $node->tax1 = 0;
  942. break;
  943. case 1:
  944. $node->tax1 = $node->amount * $node->tax1percent / 100;
  945. break;
  946. default:
  947. // ERROR
  948. drupal_set_message(t('Error during tax calculations (Storm module)'), 'error');
  949. }
  950. $node->subtotal = $node->amount + $node->tax1;
  951. switch ($node->tax2app) {
  952. case 0:
  953. $node->tax2 = 0;
  954. break;
  955. case 1:
  956. $node->tax2 = $node->amount * $node->tax2percent / 100;
  957. break;
  958. case 2:
  959. $node->tax2 = $node->subtotal * $node->tax2percent / 100;
  960. break;
  961. default:
  962. // ERROR
  963. drupal_set_message(t('Error during tax calculations (Storm module)'), 'error');
  964. }
  965. $node->total = $node->subtotal + $node->tax2;
  966. }
  967. // STORM ICON ADD / EDIT / LINK FUNCTIONS
  968. function storm_icon_add_node($node, $params=array()) {
  969. return storm_icon_add('node/add/'. $node->type, $node, $params);
  970. }
  971. function storm_icon_edit_node($node, $params=array()) {
  972. return storm_icon_edit('node/'. $node->nid .'/edit', $node, $params);
  973. }
  974. function storm_icon_delete_node($node, $params=array()) {
  975. return storm_icon_delete('node/'. $node->nid .'/delete', $node, $params);
  976. }
  977. function storm_icon_add($path, $item, $params=array()) {
  978. global $user;
  979. if (!node_access('create', $item, $user)) return '';
  980. $attributes = array('class' => 'popups-form');
  981. return storm_icon_l('application_add', $path, t('Add'), '', $params, $attributes);
  982. }
  983. function storm_icon_edit($path, $item, $params=array()) {
  984. global $user;
  985. if (!node_access('update', $item, $user)) return '';
  986. $attributes = array('class' => 'popups-form');
  987. return storm_icon_l('application_edit', $path, t('Edit'), '', $params, $attributes);
  988. }
  989. function storm_icon_delete($path, $item, $params=array()) {
  990. global $user;
  991. if (!node_access('delete', $item, $user)) return '';
  992. $attributes = array('class' => 'popups-form');
  993. return storm_icon_l('application_delete', $path, t('Delete'), '', $params, $attributes);
  994. }
  995. function storm_icon_l($icon, $path, $title, $permission='', $params=array(), $attributes=array()) {
  996. if ($permission && !user_access($permission)) return '';
  997. $icon = storm_icon($icon, $title);
  998. $attributes ['title'] = $title;
  999. $query = '';
  1000. if (array_key_exists('q', $params)) {
  1001. $destination = $params['q'];
  1002. unset($params['q']);
  1003. $c = 0;
  1004. if (array_key_exists('page', $params)) {
  1005. $destination .= '?page='. $params['page'];
  1006. unset($params['page']);
  1007. $c++;
  1008. }
  1009. if (array_key_exists('sort', $params)) {
  1010. if ($c) {
  1011. $destination .= '&';
  1012. }
  1013. else {
  1014. $destination .= '?';
  1015. }
  1016. $destination .= 'sort='. $params['sort'];
  1017. unset($params['sort']);
  1018. $c++;
  1019. }
  1020. if (array_key_exists('order', $params)) {
  1021. if ($c) {
  1022. $destination .= '&';
  1023. }
  1024. else {
  1025. $destination .= '?';
  1026. }
  1027. $destination .= 'order='. $params['order'];
  1028. unset($params['order']);
  1029. $c++;
  1030. }
  1031. $query .= 'destination='. urlencode($destination);
  1032. unset($params['destination']);
  1033. }
  1034. $params = _storm_icon_urlencode_helper($params);
  1035. foreach ($params as $key => $value) {
  1036. if ($query) $query .= '&';
  1037. $query .= $key .'='. urlencode($value);
  1038. }
  1039. $o = l($icon, $path, array('attributes' => $attributes, 'query' => $query, 'html' => TRUE));
  1040. return $o;
  1041. }
  1042. function _storm_icon_urlencode_helper($params, $org_key = "") {
  1043. $new_params = array();
  1044. foreach ($params as $key => $value) {
  1045. if (!empty($org_key)) {
  1046. $new_key = $org_key ."[". $key ."]";
  1047. }
  1048. else {
  1049. $new_key = $key;
  1050. }
  1051. if (is_array($value)) {
  1052. $new_params = array_merge(_storm_icon_urlencode_helper($value, $new_key), $new_params);
  1053. }
  1054. else {
  1055. $new_params[$new_key] = $value;
  1056. }
  1057. }
  1058. return $new_params;
  1059. }
  1060. function storm_icon($icon, $title) {
  1061. global $base_path;
  1062. // Running checkplain on these variables means that we can call storm_icon without further sanitising
  1063. $icon = check_plain($icon);
  1064. $title = check_plain($title);
  1065. $icon = str_replace(' ', '_', $icon);
  1066. if (variable_get('storm_icons_display', TRUE) == TRUE) {
  1067. $available = cache_get('storm:icons');
  1068. if (!is_object($available)) {
  1069. // Cache miss
  1070. $available = storm_icon_recache();
  1071. }
  1072. if (in_array($icon .'.png', $available->data)) {
  1073. // Standard route - display normal image
  1074. $img_src = $base_path . variable_get('storm_icons_path', drupal_get_path('module', 'storm') .'/icons') .'/'. $icon .'.png';
  1075. $o = '<img src="'. $img_src .'" alt="'. $title .'" title="'. $title .'" />';
  1076. }
  1077. else {
  1078. // Icon not found
  1079. $o = storm_icon_default($icon, $title);
  1080. }
  1081. }
  1082. else {
  1083. // Icons set to not display
  1084. $o = $title;
  1085. }
  1086. return $o;
  1087. }
  1088. function storm_icon_recache() {
  1089. $available = array();
  1090. // For PHP5, replace with scandir() function
  1091. $dir = variable_get('storm_icons_path', drupal_get_path('module', 'storm') . '/icons');
  1092. $files = file_scan_directory($dir, '.*');
  1093. foreach ($files as $file) {
  1094. $available[] = $file->basename;
  1095. }
  1096. cache_set('storm:icons', $available, 'cache', CACHE_TEMPORARY);
  1097. $available = cache_get('storm:icons');
  1098. return $available;
  1099. }
  1100. function storm_icon_default($icon, $title) {
  1101. // For now, just return $title.
  1102. // A future extension could be more intelligent using $icon.
  1103. return $title;
  1104. }
  1105. // SQL FUNCTIONS
  1106. function storm_rewrite_sql($sql, $where=array(), $join=array()) {
  1107. $where = empty($where) ? '' : '('. implode(') AND (', $where) .')';
  1108. $join = empty($join) ? '' : implode(' ', $join);
  1109. if (!empty($where) || !empty($join)) {
  1110. if (!empty($where)) {
  1111. $new = "WHERE $where ";
  1112. }
  1113. $new = " $join $new";
  1114. if (strpos($sql, 'WHERE')) {
  1115. $sql = str_replace('WHERE', $new .'AND (', $sql);
  1116. $insert = ') ';
  1117. }
  1118. else {
  1119. $insert = $new;
  1120. }
  1121. if (strpos($sql, 'GROUP')) {
  1122. $replace = 'GROUP';
  1123. }
  1124. elseif (strpos($sql, 'HAVING')) {
  1125. $replace = 'HAVING';
  1126. }
  1127. elseif (strpos($sql, 'ORDER')) {
  1128. $replace = 'ORDER';
  1129. }
  1130. elseif (strpos($sql, 'LIMIT')) {
  1131. $replace = 'LIMIT';
  1132. }
  1133. else {
  1134. $sql .= $insert;
  1135. }
  1136. if (isset($replace)) {
  1137. $sql = str_replace($replace, $insert . $replace, $sql);
  1138. }
  1139. }
  1140. return $sql;
  1141. }
  1142. function storm_db_rewrite_sql($query, $primary_table, $primary_field, $args) {
  1143. if (($primary_table == 'n' || $primary_table == 'node') && $primary_field == 'nid') {
  1144. if (preg_match("/'storm_access'='storm_access'/", $query)) {
  1145. return array();
  1146. }
  1147. global $user;
  1148. $conditions = array();
  1149. foreach (module_invoke_all('storm_rewrite_where_sql', $query, $primary_table, $user) as $condition) {
  1150. if ($condition) {
  1151. $conditions[] = $condition;
  1152. }
  1153. }
  1154. $return = array();
  1155. $where = '';
  1156. if ($conditions) {
  1157. switch ($GLOBALS['db_type']) {
  1158. case 'mysql':
  1159. case 'mysqli':
  1160. $where = '(';
  1161. $where .= " CASE ${primary_table}.type ";
  1162. foreach ($conditions as $condition) {
  1163. $where .= $condition .' ';
  1164. }
  1165. $where .= ' ELSE 1 END ';
  1166. $where .= ' )=1 ';
  1167. $return['where'] = $where;
  1168. break;
  1169. case 'pgsql':
  1170. break;
  1171. }
  1172. }
  1173. return $return;
  1174. }
  1175. }
  1176. // FUNCTION TO ADD STORM CLASSES TO NODE FORM
  1177. function storm_form_alter(&$form, $form_state, $form_id) {
  1178. if (!isset($form['type'])) {
  1179. return;
  1180. }
  1181. if ($form_id == $form['type']['#value'] .'_node_form') {
  1182. $class = NULL;
  1183. if (isset($form['#attributes']['class'])) $class = $form['#attributes']['class'];
  1184. if ($class) $class .= ' ';
  1185. $class .= $form_id;
  1186. $form['#attributes']['class'] = $class;
  1187. foreach ($form as $key => $elem) {
  1188. if (is_array($elem) && (isset($elem['#type']) ? $elem['#type'] : NULL)=='fieldset') {
  1189. $class = (isset($elem['#attributes']['class'])) ? $elem['#attributes']['class'] : NULL;
  1190. if ($class) $class .= ' ';
  1191. $class .= $key;
  1192. $form[$key]['#attributes']['class'] = $class;
  1193. }
  1194. }
  1195. }
  1196. }
  1197. /**
  1198. * Get a list of people and teams for select boxes
  1199. *
  1200. * Params:
  1201. * $organization_nid
  1202. * Leave blank to get a list of all teams and persons, otherwise also provide
  1203. * $project_nid
  1204. * to get a limited list of teams and persons following the following logic:
  1205. * - If the project is assigned to a person, only that person is listed as an option
  1206. * - If the project is assigned to a team, all team members are listed as options
  1207. * - If the project is neither assigned to a person nor a team, all people that are
  1208. * assigned to the given origanization are listed as options
  1209. * - In addition, if the project is assigned to a manager, that person is also listed
  1210. * - Finally, look into all existing teams and list those teams that exclusively
  1211. * contain members that are already selected
  1212. * If $organization_nid is provided but $project_nid is omitted, then the logic is as
  1213. * above, just for all projects of the given organization.
  1214. */
  1215. function storm_get_assignment_options($organization_nid = 0, $project_nid = 0) {
  1216. $teams = t('Teams:');
  1217. $people = t('People:');
  1218. $options = array();
  1219. if (!$organization_nid) {
  1220. $options['all'] = t('- no filter -');
  1221. $options['mine'] = t('- mine -');
  1222. }
  1223. $options['none'] = t('- unassigned -');
  1224. if (module_exists('stormteam')) {
  1225. $options[$teams] = array();
  1226. }
  1227. if (module_exists('stormperson')) {
  1228. $options[$people] = array();
  1229. }
  1230. $add_org_people = TRUE;
  1231. if ($organization_nid) {
  1232. $add_org_people = FALSE;
  1233. $manager = array();
  1234. $projects = array();
  1235. if ($project_nid) {
  1236. $projects[] = $project_nid;
  1237. }
  1238. else {
  1239. $sql = "SELECT n.nid FROM {node} AS n
  1240. INNER JOIN {stormproject} AS spr
  1241. ON n.vid=spr.vid
  1242. WHERE n.status=1
  1243. AND n.type='stormproject'
  1244. AND spr.organization_nid=%d";
  1245. $sql = stormproject_access_sql($sql);
  1246. $result = db_query(db_rewrite_sql($sql), $organization_nid);
  1247. while ($project = db_fetch_object($result)) {
  1248. $projects[] = $project->nid;
  1249. }
  1250. $add_org_people = TRUE;
  1251. }
  1252. foreach ($projects as $pid) {
  1253. $project = node_load($pid);
  1254. if ($project->manager_nid) {
  1255. $manager[] = node_load($project->manager_nid);
  1256. }
  1257. if ($project->assigned_nid) {
  1258. $node = node_load($project->assigned_nid);
  1259. if ($node->type == 'stormperson') {
  1260. if (module_exists('stormperson')) {
  1261. $options[$people][$node->nid] = check_plain($node->title);
  1262. }
  1263. }
  1264. else { // ($node->type == 'stormteam')
  1265. if (module_exists('stormteam')) {
  1266. $options[$teams][$node->nid] = check_plain($node->title);
  1267. foreach ($node->members_array as $nid => $name) {
  1268. // do not add deactivated persons
  1269. if (!array_key_exists($nid, $node->members_deactivated_array)) {
  1270. $options[$people][$nid] = check_plain($name);
  1271. }
  1272. }
  1273. }
  1274. }
  1275. }
  1276. else {
  1277. $add_org_people = TRUE;
  1278. }
  1279. }
  1280. }
  1281. if ($add_org_people) {
  1282. if (module_exists('stormperson')) {
  1283. $where = (isset($organization_nid) && $organization_nid != 0) ? 'WHERE spe.organization_nid = %d' : '';
  1284. $sql = "SELECT spe.nid,
  1285. spe.fullname,
  1286. n.title
  1287. FROM {node} n
  1288. INNER JOIN {stormperson} spe
  1289. ON n.vid = spe.vid
  1290. $where
  1291. ORDER BY spe.fullname ASC";
  1292. $sql = stormperson_access_sql($sql);
  1293. $sql = db_rewrite_sql($sql);
  1294. $result = db_query($sql, array($organization_nid));
  1295. while ($person = db_fetch_object($result)) {
  1296. $options[$people][$person->nid] = ($person->fullname) ? check_plain($person->fullname) : check_plain($person->title);
  1297. if (empty($options[$people][$person->nid])) {
  1298. $options[$people][$person->nid] = t('Person !nid', array('!nid' => $person->nid));
  1299. }
  1300. }
  1301. }
  1302. }
  1303. else {
  1304. if (isset($manager) && module_exists('stormperson')) {
  1305. foreach ($manager as $manager_node) {
  1306. if (!array_key_exists($manager_node->nid, $options[$people])) {
  1307. $options[$people][$manager_node->nid] = check_plain($manager_node->title);
  1308. }
  1309. }
  1310. }
  1311. }
  1312. if (module_exists('stormteam')) {
  1313. $where = array();
  1314. $args = array();
  1315. $having = "";
  1316. // do not add teams, which we already added
  1317. if (!empty($options[$teams])) {
  1318. $where[] = "ste.nid NOT IN (". db_placeholders($options[$teams]) .")";
  1319. $args = array_merge($args, array_keys($options[$teams]));
  1320. }
  1321. // only add teams, which have at least the same members as persons we added so far
  1322. if (!empty($organization_nid) && !empty($options[$people])) {
  1323. // add all persons which should be in the team
  1324. $where[] = "ste.mnid IN (". db_placeholders($options[$people]) .")";
  1325. $args = array_merge($args, array_keys($options[$people]));
  1326. // add a count, how many of the given persons should be in the other teams
  1327. $having = " HAVING COUNT(ste.nid) = %d ";
  1328. $args[] = count($options[$people]);
  1329. }
  1330. $sql = "SELECT n.nid, n.vid, n.title
  1331. FROM {node} n
  1332. INNER JOIN {stormteam} ste
  1333. ON n.vid = ste.vid
  1334. WHERE n.type = 'stormteam'
  1335. GROUP BY ste.nid". $having ."
  1336. ORDER BY n.title ASC";
  1337. $sql = stormteam_access_sql($sql, $where);
  1338. $sql = db_rewrite_sql($sql);
  1339. $result = db_query($sql, $args);
  1340. while ($team = db_fetch_object($result)) {
  1341. $options[$teams][$team->nid] = check_plain($team->title);
  1342. }
  1343. }
  1344. if (isset($options[$people]) && array_key_exists(0, $options[$people])) {
  1345. unset($options[$people][0]);
  1346. }
  1347. if (isset($options[$teams]) && array_key_exists(0, $options[$teams])) {
  1348. unset($options[$teams][0]);
  1349. }
  1350. if (isset($options[$people]) && !sizeof($options[$people])) {
  1351. unset($options[$people]);
  1352. }
  1353. if (isset($options[$teams]) && !sizeof($options[$teams])) {
  1354. unset($options[$teams]);
  1355. }
  1356. // SORT OPTIONS
  1357. if (!empty($options[$people]) && is_array($options[$people])) {
  1358. asort($options[$people], SORT_LOCALE_STRING);
  1359. }
  1360. if (!empty($options[$teams]) && is_array($options[$teams])) {
  1361. asort($options[$teams], SORT_LOCALE_STRING);
  1362. }
  1363. return $options;
  1364. }
  1365. /**
  1366. * Helper function to count nodes of type destination module with parent nid of type source module.
  1367. *
  1368. * @param string $source_module A string of module where the request is comming from
  1369. * @param string $destination_module A string with name of targeted module
  1370. * @param int $nid node id of source module
  1371. * @return ''|int
  1372. * empty string if can't be counted or the count of destination nodes in source node
  1373. * @see theme_storm_link()
  1374. */
  1375. function _storm_number_of_items($source_module, $destination_module, $nid) {
  1376. global $user;
  1377. $nmb_of_items = '';
  1378. $valid_destination_modules = array();
  1379. switch ($source_module) {
  1380. case "stormorganization":
  1381. $column_name = 'organization_nid';
  1382. $valid_destination_modules = array('stormproject', 'stormtask', 'stormticket', 'stormtimetracking', 'stormnote', 'stormperson', 'stormexpense', 'storminvoice');
  1383. break;
  1384. case "stormproject":
  1385. $column_name = 'project_nid';
  1386. $valid_destination_modules = array('stormtask', 'stormticket', 'stormtimetracking', 'stormnote', 'stormexpense', 'storminvoice');
  1387. break;
  1388. case "stormtask":
  1389. $column_name = 'task_nid';
  1390. $valid_destination_modules = array('stormticket', 'stormtimetracking', 'stormnote', 'stormexpense');
  1391. break;
  1392. case "stormticket":
  1393. $column_name = 'ticket_nid';
  1394. $valid_destination_modules = array('stormtimetracking', 'stormexpense');
  1395. break;
  1396. }
  1397. if (in_array($destination_module, $valid_destination_modules)) {
  1398. switch ($destination_module) {
  1399. case 'stormproject':
  1400. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormproject} AS spr ON n.vid=spr.vid WHERE n.status=1 AND
  1401. n.type='stormproject' and spr.". $column_name ." = %d";
  1402. $sql = stormproject_access_sql($sql);
  1403. break;
  1404. case 'stormtask':
  1405. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormtask} AS sta ON n.vid=sta.vid WHERE n.status=1 AND
  1406. n.type='stormtask' and sta.". $column_name ." = %d";
  1407. $sql = stormtask_access_sql($sql);
  1408. break;
  1409. case 'stormticket':
  1410. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormticket} AS sti ON n.vid=sti.vid WHERE n.status=1 AND
  1411. n.type='stormticket' and sti.". $column_name ." = %d";
  1412. $sql = stormticket_access_sql($sql);
  1413. break;
  1414. case 'stormtimetracking':
  1415. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormtimetracking} AS stt ON n.vid=stt.vid WHERE n.status=1 AND
  1416. n.type='stormtimetracking' and stt.". $column_name ." = %d";
  1417. $sql = stormtimetracking_access_sql($sql);
  1418. break;
  1419. case 'stormperson':
  1420. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormperson} AS spe ON n.vid=spe.vid WHERE n.status=1 AND
  1421. n.type='stormperson' and spe.". $column_name ." = %d";
  1422. $sql = stormperson_access_sql($sql);
  1423. break;
  1424. case 'stormnote':
  1425. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormnote} AS sno ON n.vid=sno.vid WHERE n.status=1 AND
  1426. n.type='stormnote' and sno.". $column_name ." = %d";
  1427. $sql = stormnote_access_sql($sql);
  1428. break;
  1429. case 'stormexpense':
  1430. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {stormexpense} AS sex ON n.vid=sex.vid WHERE n.status=1 AND
  1431. n.type='stormexpense' and sex.". $column_name ." = %d";
  1432. $sql = stormexpense_access_sql($sql);
  1433. break;
  1434. case 'storminvoice':
  1435. $sql = "SELECT COUNT(*) FROM {node} AS n INNER JOIN {storminvoice} AS sin ON n.vid=sin.vid WHERE n.status=1 AND
  1436. n.type='storminvoice' and sin.". $column_name ." = %d";
  1437. $sql = storminvoice_access_sql($sql);
  1438. break;
  1439. }
  1440. $sql = db_rewrite_sql($sql);
  1441. $nmb_of_items = db_result(db_query($sql, $nid));
  1442. }
  1443. return $nmb_of_items;
  1444. }
  1445. /**
  1446. * Implements hook_views_pre_render to add the storm_icon_add
  1447. *
  1448. * @param $view
  1449. */
  1450. function storm_views_pre_render(&$view) {
  1451. if (isset($view->field['operation'])
  1452. && $view->field['operation'] instanceof storm_handler_field_operation
  1453. && isset($view->field['operation']->definition['type'])
  1454. && $view->field['operation']->options['display_add_icon']
  1455. ) {
  1456. $i = new stdClass();
  1457. $i->type = $view->field['operation']->definition['type'];
  1458. if ($view->field['operation']->options['display_icons']) {
  1459. $view->attachment_before .= '<span class="storm-icon-add-view">'. storm_icon_add_node($i, $_GET) .'</span>';
  1460. }
  1461. else {
  1462. global $user;
  1463. $type = $i->type;
  1464. $af = $type .'_access';
  1465. if ($af('create', $i, $user)) {
  1466. $view->attachment_before .= '<span class="storm-icon-add-view">'. l(t('Add'), 'node/add/'. $type) .'</span>';
  1467. }
  1468. }
  1469. }
  1470. }
  1471. function storm_attribute_access($op, $item=NULL, $account=NULL) {
  1472. if (empty($account)) {
  1473. global $user;
  1474. $account = $user;
  1475. }
  1476. if ($op == 'create') {
  1477. return user_access('Storm: access administration pages');
  1478. }
  1479. if ($op == 'delete') {
  1480. return user_access('Storm: access administration pages');
  1481. }
  1482. if ($op == 'update') {
  1483. return user_access('Storm: access administration pages');
  1484. }
  1485. return FALSE;
  1486. }
  1487. function storm_attributes_bydomain($domain) {
  1488. static $attributes_cache = array();
  1489. $attributes = array();
  1490. if (array_key_exists($domain, $attributes_cache)) return $attributes_cache[$domain];
  1491. $s = "SELECT * FROM {stormattribute} WHERE LOWER(domain) LIKE LOWER('%s') AND isactive=1 ORDER BY weight, avalue";
  1492. $r = db_query($s, $domain);
  1493. $attributes['values'] = array();
  1494. while ($attribute = db_fetch_object($r)) {
  1495. // The variable is deliberately passed through t() for translatability
  1496. $attributes['values'][$attribute->akey] = t($attribute->avalue);
  1497. if ($attribute->isdefault) {
  1498. $attributes['default'] = $attribute->akey;
  1499. }
  1500. }
  1501. if (is_array($attributes['values']) && !array_key_exists('default', $attributes)) {
  1502. $v = array_flip($attributes['values']);
  1503. $attributes['default'] = array_shift($v);
  1504. }
  1505. $attributes_cache[$domain] = $attributes;
  1506. return $attributes;
  1507. }
  1508. function storm_attribute_value($domain, $key) {
  1509. $attributes_array = storm_attributes_bydomain($domain);
  1510. $attributes = $attributes_array['values'];
  1511. if (array_key_exists($key, $attributes)) {
  1512. return $attributes[$key];
  1513. }
  1514. return $key;
  1515. }