spiderfw 0.5.19 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (255) hide show
  1. data/CHANGELOG +7 -0
  2. data/VERSION +1 -1
  3. data/apps/core/auth/lib/rbac.rb +7 -2
  4. data/apps/core/auth/models/mixins/rbac_provider.rb +66 -4
  5. data/apps/core/components/assets.rb +63 -33
  6. data/apps/core/components/public/js/jquery/{jquery-1.4.3.js → jquery-1.5.2.js} +2617 -1126
  7. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/overlay/overlay.apple.js +155 -0
  8. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/overlay/overlay.js +293 -0
  9. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/scrollable/scrollable.js +335 -0
  10. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/tabs/tabs.css +59 -0
  11. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/tabs/tabs.js +283 -0
  12. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/toolbox/toolbox.expose.js +224 -0
  13. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/tooltip/tooltip.dynamic.js +150 -0
  14. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/tooltip/tooltip.js +343 -0
  15. data/apps/core/components/public/js/jquery/jquery-tools-1.2.5/tooltip/tooltip.slide.js +78 -0
  16. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/button_bg.png +0 -0
  17. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/datepicker.gif +0 -0
  18. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/icon_sprite.png +0 -0
  19. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/progress_bar.gif +0 -0
  20. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/slider_h_bg.gif +0 -0
  21. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/slider_handles.png +0 -0
  22. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/slider_v_bg.gif +0 -0
  23. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/tab_bg.gif +0 -0
  24. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/the_gradient.gif +0 -0
  25. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-anim_basic_16x16.gif +0 -0
  26. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  27. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  28. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_flat_10_000000_40x100.png +0 -0
  29. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  30. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  31. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  32. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  33. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  34. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  35. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-icons_222222_256x240.png +0 -0
  36. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-icons_228ef1_256x240.png +0 -0
  37. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-icons_ef8c08_256x240.png +0 -0
  38. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-icons_ffd27a_256x240.png +0 -0
  39. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/images/ui-icons_ffffff_256x240.png +0 -0
  40. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4 → jquery-ui-1.8.11}/css/Aristo/jquery-ui.custom.css +0 -0
  41. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-af.js +0 -0
  42. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-ar-DZ.js +23 -0
  43. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ar.js +7 -8
  44. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-az.js +0 -0
  45. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-bg.js +0 -0
  46. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-bs.js +0 -0
  47. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ca.js +0 -0
  48. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-cs.js +0 -0
  49. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-da.js +0 -0
  50. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-de.js +0 -0
  51. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-el.js +0 -0
  52. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-en-AU.js +23 -0
  53. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-en-GB.js +0 -0
  54. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-en-NZ.js +23 -0
  55. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-eo.js +0 -0
  56. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-es.js +0 -0
  57. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-et.js +0 -0
  58. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-eu.js +0 -0
  59. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-fa.js +0 -0
  60. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-fi.js +0 -0
  61. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-fo.js +0 -0
  62. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-fr-CH.js +0 -0
  63. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-fr.js +12 -10
  64. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-gl.js +23 -0
  65. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-he.js +0 -0
  66. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-hr.js +0 -0
  67. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-hu.js +1 -1
  68. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-hy.js +0 -0
  69. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-id.js +0 -0
  70. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-is.js +0 -0
  71. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-it.js +0 -0
  72. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ja.js +0 -0
  73. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ko.js +0 -0
  74. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-kz.js +23 -0
  75. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-lt.js +0 -0
  76. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-lv.js +0 -0
  77. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-ml.js +23 -0
  78. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ms.js +0 -0
  79. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-nl.js +0 -0
  80. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-no.js +23 -0
  81. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-pl.js +0 -0
  82. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-pt-BR.js +0 -0
  83. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-pt.js +22 -0
  84. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-rm.js +21 -0
  85. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ro.js +0 -0
  86. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ru.js +1 -1
  87. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-sk.js +0 -0
  88. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-sl.js +0 -0
  89. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-sq.js +0 -0
  90. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-sr-SR.js +0 -0
  91. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-sr.js +0 -0
  92. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-sv.js +0 -0
  93. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-ta.js +0 -0
  94. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-th.js +1 -1
  95. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/i18n/jquery.ui.datepicker-tj.js +23 -0
  96. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-tr.js +0 -0
  97. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-uk.js +0 -0
  98. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-vi.js +0 -0
  99. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-zh-CN.js +0 -0
  100. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-zh-HK.js +0 -0
  101. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/i18n/jquery.ui.datepicker-zh-TW.js +0 -0
  102. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.blind.js +3 -3
  103. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.bounce.js +3 -3
  104. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.clip.js +3 -3
  105. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.core.js +48 -15
  106. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.drop.js +3 -3
  107. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.explode.js +2 -2
  108. data/apps/core/components/public/js/jquery/jquery-ui-1.8.11/ui/jquery.effects.fade.js +32 -0
  109. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.fold.js +3 -3
  110. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.highlight.js +2 -2
  111. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.pulsate.js +2 -2
  112. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.scale.js +4 -4
  113. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.shake.js +3 -3
  114. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.slide.js +4 -4
  115. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.effects.transfer.js +2 -2
  116. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.accordion.js +33 -20
  117. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.autocomplete.js +104 -42
  118. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.button.js +35 -13
  119. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.core.js +111 -84
  120. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.datepicker.js +87 -46
  121. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.dialog.js +105 -75
  122. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.draggable.js +17 -15
  123. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.droppable.js +5 -5
  124. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.mouse.js +16 -11
  125. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.position.js +51 -32
  126. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.progressbar.js +24 -10
  127. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.resizable.js +7 -7
  128. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.selectable.js +3 -3
  129. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.slider.js +9 -7
  130. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.sortable.js +22 -20
  131. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.tabs.js +15 -14
  132. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → jquery-ui-1.8.11}/ui/jquery.ui.widget.js +50 -25
  133. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → plugins/bsmselect}/GPL-LICENSE.txt +1 -1
  134. data/apps/core/components/public/js/jquery/{jquery-ui-1.8.4/development-bundle → plugins/bsmselect}/MIT-LICENSE.txt +3 -7
  135. data/apps/core/components/public/js/jquery/plugins/bsmselect/README.md +185 -0
  136. data/apps/core/components/public/js/jquery/plugins/bsmselect/css/jquery.bsmselect.css +64 -0
  137. data/apps/core/components/public/js/jquery/plugins/bsmselect/js/jquery.bsmselect.compatibility.js +60 -0
  138. data/apps/core/components/public/js/jquery/plugins/bsmselect/js/jquery.bsmselect.js +381 -0
  139. data/apps/core/components/public/js/jquery/plugins/bsmselect/js/jquery.bsmselect.sortable.js +49 -0
  140. data/apps/core/components/public/js/plugins/sortable.js +16 -7
  141. data/apps/core/components/public/js/spider.js +60 -41
  142. data/apps/core/components/widgets/admin/admin.shtml +1 -1
  143. data/apps/core/components/widgets/list/list.shtml +2 -2
  144. data/apps/core/components/widgets/month_calendar/month_calendar.shtml +23 -20
  145. data/apps/core/components/widgets/switcher/switcher.rb +77 -21
  146. data/apps/core/components/widgets/switcher/templates/default.shtml +8 -0
  147. data/apps/core/components/widgets/switcher/templates/table.shtml +15 -0
  148. data/apps/core/components/widgets/table/table.rb +4 -1
  149. data/apps/core/components/widgets/table/table.shtml +10 -8
  150. data/apps/core/forms/public/css/form.css +9 -1
  151. data/apps/core/forms/public/date_time.js +14 -2
  152. data/apps/core/forms/public/input.js +1 -1
  153. data/apps/core/forms/public/select.js +4 -3
  154. data/apps/core/forms/tags/element_row.erb +11 -2
  155. data/apps/core/forms/widgets/inputs/date_time/date_time.rb +9 -0
  156. data/apps/core/forms/widgets/inputs/date_time/date_time.shtml +1 -1
  157. data/apps/core/forms/widgets/inputs/html_area/html_area.shtml +2 -2
  158. data/apps/core/forms/widgets/inputs/input/input.rb +0 -3
  159. data/apps/core/forms/widgets/inputs/select/select.shtml +2 -2
  160. data/apps/messenger/backends/email/sendmail.rb +20 -0
  161. data/apps/messenger/backends/email/smtp.rb +12 -14
  162. data/apps/messenger/backends/email/test.rb +20 -0
  163. data/apps/messenger/config/options.rb +9 -9
  164. data/apps/messenger/config/test.config.yml +2 -0
  165. data/apps/messenger/controllers/mixins/messenger_helper.rb +41 -15
  166. data/apps/messenger/lib/email_backend.rb +10 -0
  167. data/apps/messenger/messenger.rb +45 -26
  168. data/apps/messenger/test/features/attachments.feature +26 -0
  169. data/apps/messenger/test/features/messenger_helper.feature +31 -0
  170. data/apps/messenger/test/features/sending_email.feature +10 -0
  171. data/apps/messenger/test/features/step_definitions/common_steps.rb +11 -0
  172. data/apps/messenger/test/features/step_definitions/email_steps.rb +98 -0
  173. data/apps/messenger/test/features/support/env.rb +11 -0
  174. data/apps/messenger/test/files/test_file1.txt +1 -0
  175. data/apps/messenger/test/lib/controllers/mail_test_controller.rb +34 -0
  176. data/apps/messenger/test/templates/email/multipart.html.erb +1 -0
  177. data/apps/messenger/test/templates/email/multipart.txt.erb +1 -0
  178. data/apps/messenger/test/templates/email/simple.erb +1 -0
  179. data/apps/messenger/test/templates/email/vars.erb +1 -0
  180. data/lib/spiderfw/cmd/cmd.rb +4 -0
  181. data/lib/spiderfw/cmd/commands/webserver.rb +12 -59
  182. data/lib/spiderfw/config/configuration.rb +4 -0
  183. data/lib/spiderfw/config/options/spider.rb +25 -8
  184. data/lib/spiderfw/controller/controller.rb +10 -4
  185. data/lib/spiderfw/controller/first_responder.rb +6 -20
  186. data/lib/spiderfw/controller/http_controller.rb +2 -1
  187. data/lib/spiderfw/controller/mixins/http_mixin.rb +12 -1
  188. data/lib/spiderfw/controller/mixins/visual.rb +3 -16
  189. data/lib/spiderfw/env.rb +1 -1
  190. data/lib/spiderfw/http/server.rb +178 -2
  191. data/lib/spiderfw/model/base_model.rb +142 -111
  192. data/lib/spiderfw/model/data_type.rb +15 -0
  193. data/lib/spiderfw/model/datatypes/decimal.rb +8 -0
  194. data/lib/spiderfw/model/datatypes/pk.rb +29 -0
  195. data/lib/spiderfw/model/datatypes.rb +1 -0
  196. data/lib/spiderfw/model/element.rb +5 -1
  197. data/lib/spiderfw/model/extended_models/managed.rb +1 -1
  198. data/lib/spiderfw/model/junction.rb +23 -0
  199. data/lib/spiderfw/model/mappers/db_mapper.rb +96 -80
  200. data/lib/spiderfw/model/mappers/document_mapper.rb +315 -0
  201. data/lib/spiderfw/model/mappers/mapper.rb +164 -75
  202. data/lib/spiderfw/model/mixins/list.rb +1 -0
  203. data/lib/spiderfw/model/mixins/versioned.rb +63 -27
  204. data/lib/spiderfw/model/model.rb +36 -9
  205. data/lib/spiderfw/model/query_funcs.rb +3 -0
  206. data/lib/spiderfw/model/query_set.rb +21 -1
  207. data/lib/spiderfw/model/storage/base_storage.rb +259 -6
  208. data/lib/spiderfw/model/storage/{db/db_connection_pool.rb → connection_pool.rb} +25 -21
  209. data/lib/spiderfw/model/storage/db/adapters/mysql.rb +25 -5
  210. data/lib/spiderfw/model/storage/db/adapters/oracle.rb +1 -1
  211. data/lib/spiderfw/model/storage/db/connectors/jdbc_oracle.rb +2 -2
  212. data/lib/spiderfw/model/storage/db/connectors/oci8.rb +3 -4
  213. data/lib/spiderfw/model/storage/db/db_storage.rb +18 -219
  214. data/lib/spiderfw/model/storage/document/adapters/mongodb.rb +307 -0
  215. data/lib/spiderfw/model/storage/document/document.rb +7 -0
  216. data/lib/spiderfw/model/storage/document/document_storage.rb +34 -0
  217. data/lib/spiderfw/model/storage.rb +23 -11
  218. data/lib/spiderfw/model/unit_of_work.rb +45 -22
  219. data/lib/spiderfw/spider.rb +660 -0
  220. data/lib/spiderfw/templates/blocks/html.rb +4 -2
  221. data/lib/spiderfw/templates/blocks/run.rb +1 -1
  222. data/lib/spiderfw/templates/blocks/tag_if.rb +1 -1
  223. data/lib/spiderfw/templates/blocks/widget.rb +1 -1
  224. data/lib/spiderfw/templates/layout.rb +29 -5
  225. data/lib/spiderfw/templates/template.rb +72 -7
  226. data/lib/spiderfw/templates/template_blocks.rb +1 -1
  227. data/lib/spiderfw/test/capybara.rb +7 -0
  228. data/lib/spiderfw/test/cucumber.rb +12 -0
  229. data/lib/spiderfw/test/page_object.rb +29 -0
  230. data/lib/spiderfw/test/spec.rb +20 -0
  231. data/lib/spiderfw/test/stubs/mapper_stub.rb +18 -0
  232. data/lib/spiderfw/test/stubs/storage_stub.rb +23 -0
  233. data/lib/spiderfw/test/unit.rb +23 -0
  234. data/lib/spiderfw/test.rb +89 -0
  235. data/lib/spiderfw/utils/json.rb +6 -0
  236. data/lib/spiderfw/utils/logger.rb +17 -4
  237. data/lib/spiderfw/utils/loggers/apache_commons_logger.rb +61 -0
  238. data/lib/spiderfw/utils/monkey/date_time.rb +2 -2
  239. data/lib/spiderfw/utils/monkey/module.rb +3 -1
  240. data/lib/spiderfw/utils/profiling.rb +2 -2
  241. data/lib/spiderfw/widget/widget.rb +31 -13
  242. data/lib/spiderfw.rb +1 -597
  243. data/spider.gemspec +9 -10
  244. metadata +193 -132
  245. data/apps/admin/_init.rb +0 -9
  246. data/apps/admin/controllers/admin_controller.rb +0 -12
  247. data/apps/admin/widgets/dashboard_widget/dashboard_widget.rb +0 -8
  248. data/apps/core/components/public/js/jquery/jquery-ui-1.8.4/development-bundle/AUTHORS.txt +0 -30
  249. data/apps/core/components/public/js/jquery/jquery-ui-1.8.4/development-bundle/ui/i18n/jquery-ui-i18n.js +0 -1176
  250. data/apps/core/components/public/js/jquery/jquery-ui-1.8.4/development-bundle/ui/i18n/jquery.ui.datepicker-no.js +0 -23
  251. data/apps/core/components/public/js/jquery/jquery-ui-1.8.4/development-bundle/version.txt +0 -1
  252. data/apps/core/components/public/js/jquery/plugins/asmselect/jquery.asmselect.css +0 -64
  253. data/apps/core/components/public/js/jquery/plugins/asmselect/jquery.asmselect.js +0 -407
  254. data/apps/core/components/widgets/switcher/switcher.shtml +0 -17
  255. data/apps/master/po/master.pot +0 -400
@@ -126,8 +126,6 @@ module Spider; module Model; module Storage; module Db; module Connectors
126
126
  case type.name
127
127
  when 'Spider::DataTypes::Decimal', 'BigDecimal'
128
128
  java_bigdecimal(value)
129
- when 'Spider::DataTypes::Bool'
130
- value ? 1 : 0
131
129
  when 'Date', 'DateTime'
132
130
  java_date(value)
133
131
  when 'Time'
@@ -185,6 +183,8 @@ module Spider; module Model; module Storage; module Db; module Connectors
185
183
  method = case type
186
184
  when :INTEGER, :SMALLINT, :TINYING, :BIGINTEGER, :NUMBER, :NUMERIC
187
185
  :getInt
186
+ when :LONG
187
+ :getLong
188
188
  when :FLOAT, :REAL
189
189
  :getFloat
190
190
  when :DECIMAL
@@ -66,9 +66,8 @@ module Spider; module Model; module Storage; module Db; module Connectors
66
66
 
67
67
  def prepare_value(type, value)
68
68
  value = super
69
- if (type < Spider::Model::BaseModel)
70
- type = type.primary_keys[0].type
71
- end
69
+ type = type.primary_keys[0].type if type < Spider::Model::BaseModel
70
+ type = Fixnum if type == Spider::DataTypes::PK
72
71
  return Oracle::OracleNilValue.new(Spider::Model.ruby_type(type)) if (value == nil)
73
72
  case type.name
74
73
  when 'Spider::DataTypes::Binary'
@@ -84,7 +83,7 @@ module Spider; module Model; module Storage; module Db; module Connectors
84
83
  debug_vars = bind_vars.map{|var| var = var.to_s; var && var.length > 50 ? var[0..50]+"...(#{var.length-50} chars more)" : var}
85
84
  end
86
85
  curr[:last_executed] = [sql, bind_vars]
87
- if (Spider.conf.get('storage.db.replace_debug_vars'))
86
+ if Spider.conf.get('storage.db.replace_debug_vars')
88
87
  debug("oci8 #{connection} executing: "+sql.gsub(/:(\d+)/){
89
88
  i = $1.to_i
90
89
  v = bind_vars[i-1]
@@ -1,6 +1,5 @@
1
1
  require 'spiderfw/model/storage/base_storage'
2
2
  require 'spiderfw/model/mappers/db_mapper'
3
- require 'spiderfw/model/storage/db/db_connection_pool'
4
3
  require 'iconv'
5
4
 
6
5
  module Spider; module Model; module Storage; module Db
@@ -31,60 +30,19 @@ module Spider; module Model; module Storage; module Db
31
30
  attr_reader :type_synonyms
32
31
  # Type conversions which do not lose data. See also #safe_schema_conversion?
33
32
  attr_reader :safe_conversions
34
- # An Hash of DB capabilities. The default is
35
- # {:autoincrement => false, :sequences => true, :transactions => true}
36
- # (The BaseStorage class provides file sequences in case the subclass does not support them.)
37
- attr_reader :capabilities
38
33
 
39
- # Returns a new connection. Must be implemented by the subclasses; args are implementation specific.
40
- def new_connection(*args)
41
- raise "Unimplemented"
42
- end
43
-
44
- def max_connections
45
- nil
46
- end
47
-
48
- def connection_pools
49
- @pools ||= {}
50
- end
51
-
52
- def get_connection(*args)
53
- @pools ||= {}
54
- @pools[args] ||= DbConnectionPool.new(args, self)
55
- @pools[args].get_connection
56
- end
57
-
58
- # Frees a connection, relasing it to the pool
59
- def release_connection(conn, conn_params)
60
- return unless conn
61
- return unless @pools && @pools[conn_params]
62
- @pools[conn_params].release(conn)
63
- end
64
-
65
- # Removes a connection from the pool.
66
- def remove_connection(conn, conn_params)
67
- return unless conn
68
- return unless @pools && @pools[conn_params]
69
- @pools[conn_params].remove(conn)
34
+
35
+ def storage_type
36
+ :db
70
37
  end
71
38
 
72
- def disconnect(conn)
73
- raise "Virtual"
74
- end
75
-
76
- # Checks whether a connection is still alive. Must be implemented by subclasses.
77
- def connection_alive?(conn)
78
- raise "Virtual"
39
+ def inherited(subclass)
40
+ subclass.instance_variable_set("@reserved_keywords", @reserved_keywords)
41
+ subclass.instance_variable_set("@type_synonyms", @type_synonyms)
42
+ subclass.instance_variable_set("@safe_conversions", @safe_conversions)
43
+ super
79
44
  end
80
-
81
- def inherited(subclass)
82
- subclass.instance_variable_set("@reserved_keywords", @reserved_keywords)
83
- subclass.instance_variable_set("@type_synonyms", @type_synonyms)
84
- subclass.instance_variable_set("@safe_conversions", @safe_conversions)
85
- subclass.instance_variable_set("@capabilities", @capabilities)
86
- end
87
-
45
+
88
46
  end
89
47
 
90
48
  def query_start
@@ -100,70 +58,11 @@ module Spider; module Model; module Storage; module Db
100
58
  Spider.logger.info("Db query (#{@instance_name}) done in #{diff}ms")
101
59
  end
102
60
 
103
- def curr
104
- Thread.current[:db_storages] ||= {}
105
- Thread.current[:db_storages][@connection_params] ||= {
106
- :transaction_nesting => 0, :savepoints => []
107
- }
108
- end
109
-
110
- def connection_pool
111
- self.class.connection_pools[@connection_params]
112
- end
113
-
114
61
  # The constructor takes the connection URL, which will be parsed into connection params.
115
62
  def initialize(url)
116
63
  super
117
64
  end
118
65
 
119
- # Instantiates a new connection with current connection params.
120
- def connect
121
- return self.class.get_connection(*@connection_params)
122
- #Spider::Logger.debug("#{self.class.name} in thread #{Thread.current} acquired connection #{@conn}")
123
- end
124
-
125
- # True if currently connected.
126
- def connected?
127
- curr[:conn] != nil
128
- end
129
-
130
-
131
- # Returns the current connection, or creates a new one.
132
- # If a block is given, will release the connection after yielding.
133
- def connection
134
- # is_connected = connected?
135
- # Spider.logger.debug("#{self} already connected with conn #{@conn}") if is_connected
136
- # connect unless is_connected
137
- curr[:conn] = connect
138
- if block_given?
139
- yield curr[:conn]
140
- release # unless is_connected
141
- return true
142
- else
143
- #debugger unless @conn
144
- return curr[:conn]
145
- end
146
- end
147
-
148
- def self.connection_attributes
149
- @connection_attributes ||= {}
150
- end
151
-
152
- def connection_attributes
153
- self.class.connection_attributes[connection] ||= {}
154
- end
155
-
156
- # Releases the current connection to the pool.
157
- def release
158
- # The subclass should check if the connection is alive, and if it is not call remove_connection instead
159
- c = curr[:conn]
160
- #Spider.logger.debug("#{self} in thread #{Thread.current} releasing #{curr[:conn]}")
161
- curr[:conn] = nil
162
- self.class.release_connection(c, @connection_params)
163
- #Spider.logger.debug("#{self} in thread #{Thread.current} released #{curr[:conn]}")
164
- return nil
165
- #@conn = nil
166
- end
167
66
 
168
67
  # Returns the default mapper for the storage.
169
68
  # If the storage subclass contains a MapperExtension module, it will be mixed-in with the mapper.
@@ -175,106 +74,6 @@ module Spider; module Model; module Storage; module Db
175
74
  return mapper
176
75
  end
177
76
 
178
- # True if given named capability is supported by the DB.
179
- def supports?(capability)
180
- self.class.capabilities[capability]
181
- end
182
-
183
- def supports_transactions?
184
- return self.class.capabilities[:transactions]
185
- end
186
-
187
- def transactions_enabled?
188
- @configuration['enable_transactions'] && supports_transactions?
189
- end
190
-
191
- def start_transaction
192
- return unless transactions_enabled?
193
- return savepoint("point#{curr[:savepoints].length}") if in_transaction?
194
- curr[:transaction_nesting] += 1
195
- Spider.logger.debug("#{self.class.name} starting transaction for connection #{connection.object_id}")
196
- do_start_transaction
197
- return true
198
- end
199
-
200
- # May be implemented by subclasses.
201
- def do_start_transaction
202
- raise StorageException, "The current storage does not support transactions"
203
- end
204
-
205
- def in_transaction
206
- if in_transaction?
207
- curr[:transaction_nesting] += 1
208
- return true
209
- else
210
- start_transaction
211
- return false
212
- end
213
- end
214
-
215
- def in_transaction?
216
- return false
217
- end
218
-
219
- def commit
220
- return false unless transactions_enabled?
221
- raise StorageException, "Commit without a transaction" unless in_transaction?
222
- return curr[:savepoints].pop unless curr[:savepoints].empty?
223
- commit!
224
- end
225
-
226
- def commit_or_continue
227
- return false unless transactions_enabled?
228
- raise StorageException, "Commit without a transaction" unless in_transaction?
229
- if curr[:transaction_nesting] == 1
230
- commit
231
- return true
232
- else
233
- curr[:transaction_nesting] -= 1
234
- end
235
- end
236
-
237
- def commit!
238
- Spider.logger.debug("#{self.class.name} commit connection #{curr[:conn].object_id}")
239
- curr[:transaction_nesting] = 0
240
- do_commit
241
- release
242
- end
243
-
244
- def do_commit
245
- raise StorageException, "The current storage does not support transactions"
246
- end
247
-
248
- def rollback
249
- raise "Can't rollback in a nested transaction" if curr[:transaction_nesting] > 1
250
- return rollback_savepoint(curr[:savepoints].last) unless curr[:savepoints].empty?
251
- rollback!
252
- end
253
-
254
- def rollback!
255
- curr[:transaction_nesting] = 0
256
- Spider.logger.debug("#{self.class.name} rollback")
257
- do_rollback
258
- curr[:savepoints] = []
259
- release
260
- end
261
-
262
- def do_rollback
263
- raise StorageException, "The current storage does not support transactions"
264
- end
265
-
266
- def savepoint(name)
267
- curr[:savepoints] << name
268
- end
269
-
270
- def rollback_savepoint(name=nil)
271
- if name
272
- curr[:savepoints] = curr[:savepoints][0,(curr[:savepoints].index(name))]
273
- name
274
- else
275
- curr[:savepoints].pop
276
- end
277
- end
278
77
 
279
78
  def lock(table, mode=:exclusive)
280
79
  lockmode = case(mode)
@@ -340,6 +139,9 @@ module Spider; module Model; module Storage; module Db
340
139
  def column_attributes(type, attributes)
341
140
  db_attributes = {}
342
141
  case type.name
142
+ when 'Spider::DataTypes::PK'
143
+ db_attributes[:autoincrement] = true if supports?(:autoincrement)
144
+ db_attributes[:length] = 11
343
145
  when 'String', 'Spider::DataTypes::Text'
344
146
  db_attributes[:length] = attributes[:length] if (attributes[:length])
345
147
  when 'Float'
@@ -379,6 +181,8 @@ module Spider; module Model; module Storage; module Db
379
181
  return "SUBSTR(#{fields.join(', ')}, #{arguments})"
380
182
  when :subtract
381
183
  return "(#{fields[0]} - #{fields[1]})"
184
+ when :rownum
185
+ return "ROWNUM()"
382
186
  end
383
187
  raise NotImplementedError, "#{self.class} does not support function #{func.func_name}"
384
188
  end
@@ -387,15 +191,6 @@ module Spider; module Model; module Storage; module Db
387
191
  # Preparing values #
388
192
  ##################################################################
389
193
 
390
- # Prepares a value for saving.
391
- def value_for_save(type, value, save_mode)
392
- return prepare_value(type, value)
393
- end
394
-
395
- # Prepares a value that will be used in a condition.
396
- def value_for_condition(type, value)
397
- return prepare_value(type, value)
398
- end
399
194
 
400
195
  # Converts a value loaded from the DB to return it to the mapper.
401
196
  def value_to_mapper(type, value)
@@ -669,6 +464,10 @@ module Spider; module Model; module Storage; module Db
669
464
  return [sql, bind_vars]
670
465
  end
671
466
 
467
+ def sql_truncate(table)
468
+ "TRUNCATE #{table}"
469
+ end
470
+
672
471
  # Returns an array of SQL statements for a create structured description.
673
472
  def sql_create_table(create)
674
473
  name = create[:table]
@@ -0,0 +1,307 @@
1
+ require 'spiderfw/model/storage/document/document_storage'
2
+ require 'mongo'
3
+
4
+ module Spider; module Model; module Storage; module Document
5
+
6
+ class Mongodb < DocumentStorage
7
+ CONDITION_OPS = {
8
+ '>' => '$gt', '<' => '$lt', '>=' => '$gte', '<=' => '$lte', 'not' => '$e', '<>' => '$ne'
9
+ }
10
+
11
+ def self.parse_url(url)
12
+ # doc:mongodb://<username:password>@<host>:<port>/<database>
13
+ if (url =~ /.+:\/\/(?:(.+):(.+)@)?(.+)?\/(.+)/)
14
+ user = $1
15
+ pass = $2
16
+ location = $3
17
+ db_name = $4
18
+ else
19
+ raise ArgumentError, "Mongodb url '#{url}' is invalid"
20
+ end
21
+ location =~ /(.+)(?::(\d+))/
22
+ host = $1
23
+ port = $2
24
+ return [host, user, pass, db_name, port]
25
+ end
26
+
27
+ def parse_url(url)
28
+ @host, @user, @pass, @db_name, @port = self.class.parse_url(url)
29
+ @connection_params = [@host, @user, @pass, @db_name, @port]
30
+ end
31
+
32
+ def self.new_connection(host=nil, user=nil, passwd=nil, db=nil, port=nil)
33
+ conn = ::Mongo::Connection.new(host, port)
34
+ conn.authenticate(user, passwd) if user
35
+ return conn
36
+ end
37
+
38
+ def self.disconnect(conn)
39
+ conn.close
40
+ end
41
+
42
+ def self.connection_alive?(conn)
43
+ conn.connected?
44
+ end
45
+
46
+ def connect
47
+ conn = super
48
+ curr[:db] = conn.db(@connection_params[3])
49
+ conn
50
+ end
51
+
52
+ def release
53
+ curr[:db] = nil
54
+ super
55
+ end
56
+
57
+ def db
58
+ connection
59
+ curr[:db]
60
+ end
61
+
62
+ def collection(coll)
63
+ db.collection(coll)
64
+ end
65
+
66
+ def insert(collection, doc)
67
+ Spider.logger.debug("Mongodb insert #{collection}:")
68
+ Spider.logger.debug(doc)
69
+ begin
70
+ collection(collection).insert(doc)
71
+ ensure
72
+ release
73
+ end
74
+ end
75
+
76
+ def update(collection, selector, vals)
77
+ Spider.logger.debug("Mongodb update #{collection}, #{selector.inspect}:")
78
+ Spider.logger.debug(vals)
79
+ begin
80
+ collection(collection).update(selector, {'$set' => vals})
81
+ ensure
82
+ release
83
+ end
84
+ end
85
+
86
+ def delete(collection, doc)
87
+ begin
88
+ collection(collection).remove({"_id" => doc["_id"]}, doc)
89
+ ensure
90
+ release
91
+ end
92
+ end
93
+
94
+ def prepare_value(type, value)
95
+ return value if value.nil?
96
+ case type.name
97
+ when 'Time'
98
+ value = value.utc
99
+ when 'DateTime'
100
+ value = value.to_local_time.utc.to_time
101
+ when 'Date'
102
+ value = value.to_gm_time.utc
103
+ when 'BigDecimal'
104
+ # FIXME: should multiply on value.attributes[:scale] and store an integer, converting it back on load
105
+ value = value.to_f
106
+ end
107
+ value
108
+ end
109
+
110
+ def value_to_mapper(type, value)
111
+ if value.class == Time
112
+ if type.name == 'Date'
113
+ value = value.to_date
114
+ elsif type.name == 'DateTime'
115
+ value = value.to_datetime
116
+ end
117
+ return value
118
+ elsif type.name == 'Fixnum'
119
+ return value.to_i
120
+ end
121
+ return super
122
+ end
123
+
124
+ def find(collection, condition, request, options)
125
+ options[:fields] = request
126
+ Spider.logger.debug("Mongodb find #{collection}, #{condition.inspect}")
127
+ begin
128
+ res = collection(collection).find(condition, options).to_a
129
+ ensure
130
+ release
131
+ end
132
+ res = res.map{ |row| keys_to_symbols(row) }
133
+ res.extend(StorageResult)
134
+ res.total_rows = res.length # FIXME
135
+ res
136
+ end
137
+
138
+ def keys_to_symbols(h)
139
+ sh = {}
140
+ h.each do |k, v|
141
+ v = if v.is_a?(Hash)
142
+ keys_to_symbols(v)
143
+ elsif v.is_a?(Array)
144
+ v.map{ |row| keys_to_symbols(row) }
145
+ else
146
+ v
147
+ end
148
+ #name = k == "_id" ? :id : k.to_sym
149
+ name = k.to_sym
150
+ sh[name] = v
151
+ end
152
+ sh
153
+ end
154
+
155
+ def drop_db!
156
+ conn = connection
157
+ begin
158
+ conn.drop_database(@db_name)
159
+ ensure
160
+ release
161
+ end
162
+ end
163
+
164
+ def generate_pk
165
+ ::BSON::ObjectId.new
166
+ end
167
+
168
+ # Mapper extension
169
+
170
+ module MapperExtension
171
+
172
+ def prepare_condition(condition)
173
+ cond_hash = {}
174
+ pks = []
175
+ condition.each_with_comparison do |k, v, comp|
176
+ element = model.elements[k.to_sym]
177
+ name = nil
178
+ if element.primary_key?
179
+ if @model.primary_keys.length == 1
180
+ name = '_id'
181
+ else
182
+ raise "Mongo conditions for multiple primary keys are not supported yet"
183
+ end
184
+ else
185
+ name = element.name.to_s
186
+ end
187
+ #next unless model.mapper.mapped?(element)
188
+ if element.model?
189
+ if element.attributes[:embedded]
190
+ # TODO
191
+ else
192
+ pks = []
193
+ element.model.primary_keys.each do |ek|
194
+ kv = v[ek.name]
195
+ raise "Document mapper can't join #{element.name}: condition #{condition}" unless kv
196
+ pks << element.mapper.map_condition_value(ek.type, kv)
197
+ end
198
+ hash_v = element.model.keys_string(pks)
199
+ hash_v = {Mongodb::CONDITION_OPS[comp] => hash_v} unless comp == '='
200
+ cond_hash[name] = hash_v
201
+ end
202
+ else
203
+ hash_v = map_condition_value(element.type, v)
204
+ comp ||= '='
205
+ if comp != '='
206
+ if comp == 'like' || comp == 'ilike'
207
+ options = comp == 'ilike' ? Regexp::IGNORECASE : nil
208
+ parts = hash_v.split('%')
209
+ parts << "" if hash_v[-1].chr == '%'
210
+ re_str = parts.map{ |p| p.blank? ? '' : Regexp.quote(p)}.join('.+')
211
+ hash_v = Regexp.new(re_str, options)
212
+ else
213
+ hash_v = {Mongodb::CONDITION_OPS[comp] => hash_v}
214
+ end
215
+ end
216
+ cond_hash[name] = hash_v
217
+ end
218
+ end
219
+ or_conds = []
220
+ or_conds << cond_hash if condition.conjunction == :or && condition.subconditions.length > 0
221
+ condition.subconditions.each do |sub|
222
+ sub_res = self.prepare_condition(sub)
223
+ if condition.conjunction == :and
224
+ cond_hash.merge!(sub_res)
225
+ elsif condition.conjunction == :or
226
+ or_conds << sub_res
227
+ end
228
+ end
229
+ unless or_conds.empty?
230
+ cond_hash = { '$or' => or_conds }
231
+ end
232
+ cond_hash
233
+ end
234
+
235
+ def prepare_request(request)
236
+ h = {}
237
+ request.each do |k, v|
238
+ element = @model.elements[k.to_sym]
239
+ next unless element
240
+ name = element.primary_key? ? '_id' : element.name.to_s
241
+ if v.is_a?(Spider::Model::Request)
242
+ sub = prepare_request(v)
243
+ sub.each do |sk, sv|
244
+ h["#{name}.#{sk}"] = sv
245
+ end
246
+ else
247
+ h[name] = 1
248
+ end
249
+ end
250
+ h
251
+ end
252
+
253
+ def fetch(query)
254
+ condition = prepare_condition(query.condition)
255
+ request = prepare_request(query.request)
256
+ options = {}
257
+ options[:limit] = query.limit if query.limit
258
+ options[:skip] = query.offset if query.offset
259
+ if query.order
260
+ order_array = []
261
+ query.order.each do |order|
262
+ order_element, direction = order
263
+ dir_str = direction == :desc ? 'descending' : 'ascending'
264
+ order_array << [order_element.to_s, dir_str]
265
+ end
266
+ options[:sort] = order_array unless order_array.empty?
267
+ end
268
+ res = storage.find(@model.name, condition, request, options)
269
+ r = res.map{ |row| postprocess_result(row) }
270
+ r.extend(Storage::StorageResult) # FIXME: avoid doing this twice
271
+ r.total_rows = res.total_rows
272
+ r
273
+ end
274
+
275
+ def postprocess_result(h, model=nil)
276
+ model ||= @model
277
+ sh = {}
278
+ h.each do |k, v|
279
+ if k == :_id
280
+ pks = model.split_keys_string(v)
281
+ model.primary_keys.each_with_index do |pk, i|
282
+ pkval = pks[i]
283
+ pkval = storage_value_to_mapper(pk.type, pkval)
284
+ sh[pk.name] = pks[i]
285
+ end
286
+ else
287
+ el = model.elements[k]
288
+ v = if v.is_a?(Hash)
289
+ postprocess_result(v, el.model)
290
+ elsif v.is_a?(Array)
291
+ v.map{ |row| postprocess_result(row, el.model) }
292
+ else
293
+ v
294
+ end
295
+ sh[k] = v
296
+ end
297
+ end
298
+ sh
299
+ end
300
+
301
+
302
+
303
+ end
304
+
305
+ end
306
+
307
+ end; end; end; end
@@ -0,0 +1,7 @@
1
+ module Spider; module Model; module Storage
2
+ module Document
3
+ end
4
+
5
+ Document.autoload(:Mongodb, 'spiderfw/model/storage/document/adapters/mongodb')
6
+
7
+ end; end; end
@@ -0,0 +1,34 @@
1
+ require 'spiderfw/model/storage/base_storage'
2
+ require 'spiderfw/model/mappers/document_mapper'
3
+
4
+ module Spider; module Model; module Storage; module Document
5
+
6
+ class DocumentStorage < Storage::BaseStorage
7
+
8
+ @capabilities = {
9
+ :embedding => true,
10
+ :transactions => false
11
+ }
12
+
13
+ def self.storage_type
14
+ :document
15
+ end
16
+
17
+ # Returns the default mapper for the storage.
18
+ # If the storage subclass contains a MapperExtension module, it will be mixed-in with the mapper.
19
+ def get_mapper(model)
20
+ mapper = Spider::Model::Mappers::DocumentMapper.new(model, self)
21
+ if (self.class.const_defined?(:MapperExtension))
22
+ mapper.extend(self.class.const_get(:MapperExtension))
23
+ end
24
+ return mapper
25
+ end
26
+
27
+ def generate_pk
28
+ Spider::DataTypes::UUID.auto_value
29
+ end
30
+
31
+ end
32
+
33
+
34
+ end; end; end; end