fe 0.0.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (456) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +4 -4
  3. data/Rakefile +16 -36
  4. data/app/assets/config/fe/manifest.js +3 -0
  5. data/app/assets/config/manifest.js +3 -0
  6. data/app/assets/javascripts/application.js.erb +1 -1
  7. data/app/assets/javascripts/fe/admin.js +0 -2
  8. data/app/assets/javascripts/fe/fe.admin.js +40 -20
  9. data/app/assets/javascripts/fe/fe.common.js.erb +98 -0
  10. data/app/assets/javascripts/fe/fe.public.js +2 -416
  11. data/app/assets/javascripts/fe/fe.public.nojquery.js.erb +526 -0
  12. data/app/assets/javascripts/fe/jquery.html5_upload.js +258 -0
  13. data/app/assets/javascripts/fe/jquery.validate.pack.js +3 -15
  14. data/app/assets/stylesheets/fe/fe.screen.css.scss.erb +90 -10
  15. data/app/assets/stylesheets/fe/validation.css +5 -1
  16. data/app/controllers/concerns/fe/admin/question_sheets_controller_concern.rb +111 -0
  17. data/app/controllers/concerns/fe/answer_pages_controller_concern.rb +131 -0
  18. data/app/controllers/{fe/concerns → concerns/fe}/answer_sheets_controller_concern.rb +15 -7
  19. data/app/controllers/{fe/concerns → concerns/fe}/application_controller_concern.rb +15 -2
  20. data/app/controllers/fe/admin/elements_controller.rb +102 -64
  21. data/app/controllers/fe/admin/email_templates_controller.rb +7 -7
  22. data/app/controllers/fe/admin/question_pages_controller.rb +9 -9
  23. data/app/controllers/fe/admin/question_sheets_controller.rb +2 -103
  24. data/app/controllers/fe/reference_pages_controller.rb +11 -11
  25. data/app/controllers/fe/reference_sheets_controller.rb +6 -4
  26. data/app/controllers/fe/references_controller.rb +20 -19
  27. data/app/controllers/fe/submit_pages_controller.rb +5 -5
  28. data/app/helpers/fe/answer_pages_helper.rb +1 -1
  29. data/app/helpers/fe/application_helper.rb +8 -3
  30. data/app/jobs/fe/update_reference_sheet_visibility_job.rb +11 -0
  31. data/app/mailers/fe/notifier.rb +12 -5
  32. data/app/models/answer_sheet.rb +2 -0
  33. data/app/models/application_record.rb +3 -0
  34. data/app/models/{fe/concerns → concerns/fe}/answer_concern.rb +2 -2
  35. data/app/models/{fe/concerns → concerns/fe}/answer_pages_presenter_concern.rb +15 -5
  36. data/app/models/concerns/fe/answer_sheet_concern.rb +125 -0
  37. data/app/models/{fe/concerns → concerns/fe}/choice_field_concern.rb +56 -31
  38. data/app/models/fe/address.rb +2 -2
  39. data/app/models/fe/answer.rb +1 -1
  40. data/app/models/fe/answer_sheet.rb +1 -1
  41. data/app/models/fe/answer_sheet_question_sheet.rb +2 -2
  42. data/app/models/fe/application.rb +15 -10
  43. data/app/models/fe/condition.rb +4 -4
  44. data/app/models/fe/date_field.rb +2 -2
  45. data/app/models/fe/element.rb +201 -45
  46. data/app/models/fe/email_address.rb +2 -2
  47. data/app/models/fe/email_template.rb +1 -1
  48. data/app/models/fe/page.rb +138 -31
  49. data/app/models/fe/page_element.rb +8 -3
  50. data/app/models/fe/page_link.rb +6 -3
  51. data/app/models/fe/paragraph.rb +1 -1
  52. data/app/models/fe/person.rb +16 -13
  53. data/app/models/fe/phone_number.rb +1 -1
  54. data/app/models/fe/question.rb +64 -44
  55. data/app/models/fe/question_grid.rb +16 -4
  56. data/app/models/fe/question_grid_with_total.rb +15 -0
  57. data/app/models/fe/question_set.rb +54 -14
  58. data/app/models/fe/question_sheet.rb +54 -19
  59. data/app/models/fe/reference_question.rb +9 -13
  60. data/app/models/fe/reference_sheet.rb +113 -54
  61. data/app/models/fe/state_chooser.rb +2 -2
  62. data/app/models/fe/text_field.rb +2 -2
  63. data/app/models/fe/user.rb +1 -1
  64. data/app/models/staff.rb +8 -6
  65. data/app/validators/email_validator.rb +11 -0
  66. data/app/views/fe/admin/elements/create.js.erb +4 -3
  67. data/app/views/fe/admin/elements/destroy.js.erb +1 -1
  68. data/app/views/fe/admin/elements/drop.js.erb +2 -1
  69. data/app/views/fe/admin/elements/duplicate.js.erb +2 -1
  70. data/app/views/fe/admin/elements/edit.js.erb +1 -1
  71. data/app/views/fe/admin/elements/error.js.erb +1 -1
  72. data/app/views/fe/admin/elements/new.js.erb +13 -6
  73. data/app/views/fe/admin/elements/update.js.erb +1 -1
  74. data/app/views/fe/admin/email_templates/_form.html.erb +3 -3
  75. data/app/views/fe/admin/email_templates/edit.html.erb +3 -3
  76. data/app/views/fe/admin/email_templates/index.html.erb +3 -3
  77. data/app/views/fe/admin/email_templates/new.html.erb +3 -3
  78. data/app/views/fe/admin/panels/_advanced_options.html.erb +16 -10
  79. data/app/views/fe/admin/panels/_common_boolean_fields.html.erb +1 -0
  80. data/app/views/fe/admin/panels/_common_boolean_fields_default.html.erb +11 -0
  81. data/app/views/fe/admin/panels/_common_fields.html.erb +18 -19
  82. data/app/views/fe/admin/panels/_condition.html.erb +1 -1
  83. data/app/views/fe/admin/panels/_insert.html.erb +25 -25
  84. data/app/views/fe/admin/panels/_nav_controls.html.erb +4 -4
  85. data/app/views/fe/admin/panels/_page.html.erb +2 -2
  86. data/app/views/fe/admin/panels/_pages_list.html.erb +3 -3
  87. data/app/views/fe/admin/panels/_prop_attachment_field.html.erb +2 -2
  88. data/app/views/fe/admin/panels/_prop_choice_field.html.erb +52 -24
  89. data/app/views/fe/admin/panels/_prop_date_field.html.erb +1 -1
  90. data/app/views/fe/admin/panels/_prop_element.html.erb +7 -14
  91. data/app/views/fe/admin/panels/_prop_page.html.erb +11 -6
  92. data/app/views/fe/admin/panels/_prop_paragraph.html.erb +38 -24
  93. data/app/views/fe/admin/panels/_prop_question_grid.html.erb +7 -2
  94. data/app/views/fe/admin/panels/_prop_question_grid_with_total.html.erb +2 -2
  95. data/app/views/fe/admin/panels/_prop_reference_question.html.erb +3 -3
  96. data/app/views/fe/admin/panels/_prop_section.html.erb +8 -2
  97. data/app/views/fe/admin/panels/_prop_sheet.html.erb +7 -4
  98. data/app/views/fe/admin/panels/_prop_text_field.html.erb +12 -12
  99. data/app/views/fe/admin/question_pages/_element.html.erb +16 -6
  100. data/app/views/fe/admin/question_pages/_element_show.html.erb +2 -2
  101. data/app/views/fe/admin/question_pages/_question_page.html.erb +4 -4
  102. data/app/views/fe/admin/question_pages/create.js.erb +3 -3
  103. data/app/views/fe/admin/question_pages/destroy.js.erb +3 -3
  104. data/app/views/fe/admin/question_pages/edit.js.erb +1 -1
  105. data/app/views/fe/admin/question_pages/error.js.erb +1 -1
  106. data/app/views/fe/admin/question_pages/show.js.erb +2 -2
  107. data/app/views/fe/admin/question_pages/show_panel.js.erb +1 -1
  108. data/app/views/fe/admin/question_pages/update.js.erb +1 -1
  109. data/app/views/fe/admin/question_sheets/edit.js.erb +1 -1
  110. data/app/views/fe/admin/question_sheets/error.js.erb +1 -1
  111. data/app/views/fe/admin/question_sheets/index.html.erb +8 -8
  112. data/app/views/fe/admin/question_sheets/new.html.erb +3 -3
  113. data/app/views/fe/admin/question_sheets/show.html.erb +5 -5
  114. data/app/views/fe/admin/question_sheets/update.js.erb +1 -1
  115. data/app/views/fe/answer_pages/_answer_page.html.erb +14 -14
  116. data/app/views/fe/answer_pages/_element.html.erb +25 -6
  117. data/app/views/fe/answer_pages/_page_name.html.erb +1 -0
  118. data/app/views/fe/answer_pages/show.html.erb +39 -0
  119. data/app/views/fe/answer_pages/update.js.erb +11 -3
  120. data/app/views/fe/answer_sheets/_answer_sheet.html.erb +6 -6
  121. data/app/views/fe/answer_sheets/_element.html.erb +55 -35
  122. data/app/views/fe/answer_sheets/_incomplete.html.erb +1 -1
  123. data/app/views/fe/answer_sheets/_page_link.html.erb +9 -7
  124. data/app/views/fe/answer_sheets/_pages_list.html.erb +4 -4
  125. data/app/views/fe/answer_sheets/_submit_to.html.erb +1 -0
  126. data/app/views/fe/answer_sheets/_title.html.erb +1 -1
  127. data/app/views/fe/answer_sheets/edit.html.erb +24 -24
  128. data/app/views/fe/answer_sheets/incomplete.js.erb +9 -3
  129. data/app/views/fe/answer_sheets/index.html.erb +3 -3
  130. data/app/views/fe/answer_sheets/show.html.erb +1 -1
  131. data/app/views/fe/applications/_logout.html.erb +1 -0
  132. data/app/views/fe/applications/show.html.erb +1 -0
  133. data/app/views/fe/questions/fe/_acceptance.html.erb +11 -10
  134. data/app/views/fe/questions/fe/_attachment_field.html.erb +133 -10
  135. data/app/views/fe/questions/fe/_checkbox_field.html.erb +34 -30
  136. data/app/views/fe/questions/fe/_country.html.erb +6 -6
  137. data/app/views/fe/questions/fe/_date_field.html.erb +5 -5
  138. data/app/views/fe/questions/fe/_date_field_mmyy.html.erb +8 -8
  139. data/app/views/fe/questions/fe/_drop_down_field.html.erb +7 -6
  140. data/app/views/fe/questions/fe/_paragraph.html.erb +1 -1
  141. data/app/views/fe/questions/fe/_question_grid.html.erb +21 -16
  142. data/app/views/fe/questions/fe/_question_grid_with_total.html.erb +25 -18
  143. data/app/views/fe/questions/fe/_questions.html.erb +11 -5
  144. data/app/views/fe/questions/fe/_radio_button_field.html.erb +42 -25
  145. data/app/views/fe/questions/fe/_rating.html.erb +57 -18
  146. data/app/views/fe/questions/fe/_reference_discipler.html.erb +1 -1
  147. data/app/views/fe/questions/fe/_reference_friend.html.erb +1 -1
  148. data/app/views/fe/questions/fe/_reference_parent.html.erb +1 -1
  149. data/app/views/fe/questions/fe/_reference_peer.html.erb +1 -1
  150. data/app/views/fe/questions/fe/_reference_question.html.erb +44 -21
  151. data/app/views/fe/questions/fe/_reference_roommate.html.erb +1 -1
  152. data/app/views/fe/questions/fe/_reference_spiritual.html.erb +1 -1
  153. data/app/views/fe/questions/fe/_reference_staff.html.erb +1 -1
  154. data/app/views/fe/questions/fe/_section.html.erb +1 -1
  155. data/app/views/fe/questions/fe/_state_chooser.html.erb +6 -6
  156. data/app/views/fe/questions/fe/_text_area_field.html.erb +17 -6
  157. data/app/views/fe/questions/fe/_text_field.html.erb +7 -6
  158. data/app/views/fe/questions/fe/_yes_no.html.erb +8 -8
  159. data/app/views/fe/questions/fe/_yes_no_field.erb +12 -9
  160. data/app/views/fe/reference_pages/_reference.html.erb +15 -15
  161. data/app/views/fe/reference_pages/edit.html.erb +9 -9
  162. data/app/views/fe/reference_sheets/done.html.erb +2 -2
  163. data/app/views/fe/reference_sheets/not_found.html.erb +4 -4
  164. data/app/views/fe/references/edit.html.erb +6 -6
  165. data/app/views/fe/references/show.html.erb +8 -8
  166. data/app/views/fe/references/submit.js.erb +3 -3
  167. data/app/views/fe/submit_pages/_thankyou.html.erb +1 -1
  168. data/app/views/fe/submit_pages/edit.html.erb +12 -12
  169. data/app/views/fe/submit_pages/error.js.erb +1 -1
  170. data/app/views/fe/submit_pages/submit.js.erb +2 -2
  171. data/app/views/layouts/fe/_error_messages_for.html.erb +7 -0
  172. data/app/views/layouts/fe/application.html.erb +4 -5
  173. data/app/views/layouts/fe/fe_admin.html.erb +30 -0
  174. data/app/views.current/fe/admin/elements/_errors.html.erb +11 -0
  175. data/app/views.current/fe/admin/elements/create.js.erb +12 -0
  176. data/app/views.current/fe/admin/elements/destroy.js.erb +4 -0
  177. data/app/views.current/fe/admin/elements/drop.js.erb +3 -0
  178. data/app/views.current/fe/admin/elements/duplicate.js.erb +3 -0
  179. data/app/views.current/fe/admin/elements/edit.js.erb +4 -0
  180. data/app/views.current/fe/admin/elements/error.js.erb +4 -0
  181. data/app/views.current/fe/admin/elements/new.js.erb +17 -0
  182. data/app/views.current/fe/admin/elements/reorder.js.erb +0 -0
  183. data/app/views.current/fe/admin/elements/update.js.erb +9 -0
  184. data/app/views.current/fe/admin/email_templates/_form.html.erb +8 -0
  185. data/app/views.current/fe/admin/email_templates/edit.html.erb +13 -0
  186. data/app/views.current/fe/admin/email_templates/index.html.erb +20 -0
  187. data/app/views.current/fe/admin/email_templates/new.html.erb +11 -0
  188. data/app/views.current/fe/admin/panels/_advanced_options.html.erb +49 -0
  189. data/app/views.current/fe/admin/panels/_common_boolean_fields.html.erb +1 -0
  190. data/app/views.current/fe/admin/panels/_common_boolean_fields_default.html.erb +11 -0
  191. data/app/views.current/fe/admin/panels/_common_fields.html.erb +23 -0
  192. data/app/views.current/fe/admin/panels/_condition.html.erb +6 -0
  193. data/app/views.current/fe/admin/panels/_insert.html.erb +39 -0
  194. data/app/views.current/fe/admin/panels/_nav_controls.html.erb +6 -0
  195. data/app/views.current/fe/admin/panels/_page.html.erb +3 -0
  196. data/app/views.current/fe/admin/panels/_pages_list.html.erb +16 -0
  197. data/app/views.current/fe/admin/panels/_prop_attachment_field.html.erb +2 -0
  198. data/app/views.current/fe/admin/panels/_prop_choice_field.html.erb +74 -0
  199. data/app/views.current/fe/admin/panels/_prop_date_field.html.erb +7 -0
  200. data/app/views.current/fe/admin/panels/_prop_element.html.erb +23 -0
  201. data/app/views.current/fe/admin/panels/_prop_page.html.erb +26 -0
  202. data/app/views.current/fe/admin/panels/_prop_paragraph.html.erb +46 -0
  203. data/app/views.current/fe/admin/panels/_prop_question_grid.html.erb +28 -0
  204. data/app/views.current/fe/admin/panels/_prop_question_grid_with_total.html.erb +14 -0
  205. data/app/views.current/fe/admin/panels/_prop_reference_question.html.erb +12 -0
  206. data/app/views.current/fe/admin/panels/_prop_section.html.erb +8 -0
  207. data/app/views.current/fe/admin/panels/_prop_sheet.html.erb +20 -0
  208. data/app/views.current/fe/admin/panels/_prop_text_field.html.erb +20 -0
  209. data/app/views.current/fe/admin/question_pages/_element.html.erb +28 -0
  210. data/app/views.current/fe/admin/question_pages/_element_show.html.erb +10 -0
  211. data/app/views.current/fe/admin/question_pages/_errors.html.erb +10 -0
  212. data/app/views.current/fe/admin/question_pages/_question_page.html.erb +13 -0
  213. data/app/views.current/fe/admin/question_pages/create.js.erb +11 -0
  214. data/app/views.current/fe/admin/question_pages/destroy.js.erb +5 -0
  215. data/app/views.current/fe/admin/question_pages/edit.js.erb +3 -0
  216. data/app/views.current/fe/admin/question_pages/error.js.erb +4 -0
  217. data/app/views.current/fe/admin/question_pages/show.js.erb +9 -0
  218. data/app/views.current/fe/admin/question_pages/show_panel.js.erb +3 -0
  219. data/app/views.current/fe/admin/question_pages/update.js.erb +2 -0
  220. data/app/views.current/fe/admin/question_sheets/_errors.html.erb +11 -0
  221. data/app/views.current/fe/admin/question_sheets/edit.js.erb +3 -0
  222. data/app/views.current/fe/admin/question_sheets/error.js.erb +5 -0
  223. data/app/views.current/fe/admin/question_sheets/index.html.erb +41 -0
  224. data/app/views.current/fe/admin/question_sheets/new.html.erb +15 -0
  225. data/app/views.current/fe/admin/question_sheets/show.html.erb +27 -0
  226. data/app/views.current/fe/admin/question_sheets/update.js.erb +2 -0
  227. data/app/views.current/fe/answer_pages/_answer_page.html.erb +53 -0
  228. data/app/views.current/fe/answer_pages/_element.html.erb +32 -0
  229. data/app/views.current/fe/answer_pages/_page_name.html.erb +1 -0
  230. data/app/views.current/fe/answer_pages/show.html.erb +39 -0
  231. data/app/views.current/fe/answer_pages/update.js.erb +13 -0
  232. data/app/views.current/fe/answer_sheets/_answer_sheet.html.erb +26 -0
  233. data/app/views.current/fe/answer_sheets/_element.html.erb +74 -0
  234. data/app/views.current/fe/answer_sheets/_incomplete.html.erb +10 -0
  235. data/app/views.current/fe/answer_sheets/_page_link.html.erb +9 -0
  236. data/app/views.current/fe/answer_sheets/_pages_list.html.erb +11 -0
  237. data/app/views.current/fe/answer_sheets/_submit_to.html.erb +1 -0
  238. data/app/views.current/fe/answer_sheets/_title.html.erb +1 -0
  239. data/app/views.current/fe/answer_sheets/edit.html.erb +66 -0
  240. data/app/views.current/fe/answer_sheets/incomplete.js.erb +11 -0
  241. data/app/views.current/fe/answer_sheets/index.html.erb +18 -0
  242. data/app/views.current/fe/answer_sheets/send_reference_invite.js.erb +8 -0
  243. data/app/views.current/fe/answer_sheets/show.html.erb +13 -0
  244. data/app/views.current/fe/applications/_logout.html.erb +1 -0
  245. data/app/views.current/fe/applications/show.html.erb +1 -0
  246. data/app/views.current/fe/help/builder.html +33 -0
  247. data/app/views.current/fe/help/question_grid.html +18 -0
  248. data/app/views.current/fe/questions/fe/_acceptance.html.erb +14 -0
  249. data/app/views.current/fe/questions/fe/_attachment_field.html.erb +165 -0
  250. data/app/views.current/fe/questions/fe/_checkbox_field.html.erb +53 -0
  251. data/app/views.current/fe/questions/fe/_country.html.erb +7 -0
  252. data/app/views.current/fe/questions/fe/_date_field.html.erb +7 -0
  253. data/app/views.current/fe/questions/fe/_date_field_mmyy.html.erb +9 -0
  254. data/app/views.current/fe/questions/fe/_drop_down_field.html.erb +8 -0
  255. data/app/views.current/fe/questions/fe/_paragraph.html.erb +1 -0
  256. data/app/views.current/fe/questions/fe/_question_grid.html.erb +70 -0
  257. data/app/views.current/fe/questions/fe/_question_grid_with_total.html.erb +64 -0
  258. data/app/views.current/fe/questions/fe/_questions.html.erb +15 -0
  259. data/app/views.current/fe/questions/fe/_radio_button_field.html.erb +60 -0
  260. data/app/views.current/fe/questions/fe/_rating.html.erb +64 -0
  261. data/app/views.current/fe/questions/fe/_reference_discipler.html.erb +1 -0
  262. data/app/views.current/fe/questions/fe/_reference_friend.html.erb +1 -0
  263. data/app/views.current/fe/questions/fe/_reference_parent.html.erb +1 -0
  264. data/app/views.current/fe/questions/fe/_reference_peer.html.erb +1 -0
  265. data/app/views.current/fe/questions/fe/_reference_question.html.erb +61 -0
  266. data/app/views.current/fe/questions/fe/_reference_roommate.html.erb +1 -0
  267. data/app/views.current/fe/questions/fe/_reference_spiritual.html.erb +1 -0
  268. data/app/views.current/fe/questions/fe/_reference_staff.html.erb +1 -0
  269. data/app/views.current/fe/questions/fe/_section.html.erb +1 -0
  270. data/app/views.current/fe/questions/fe/_state_chooser.html.erb +7 -0
  271. data/app/views.current/fe/questions/fe/_text_area_field.html.erb +17 -0
  272. data/app/views.current/fe/questions/fe/_text_field.html.erb +9 -0
  273. data/app/views.current/fe/questions/fe/_yes_no.html.erb +17 -0
  274. data/app/views.current/fe/questions/fe/_yes_no_field.erb +20 -0
  275. data/app/views.current/fe/reference_pages/_reference.html.erb +31 -0
  276. data/app/views.current/fe/reference_pages/edit.html.erb +24 -0
  277. data/app/views.current/fe/reference_sheets/done.html.erb +2 -0
  278. data/app/views.current/fe/reference_sheets/not_found.html.erb +5 -0
  279. data/app/views.current/fe/reference_sheets/submitted.js.erb +1 -0
  280. data/app/views.current/fe/references/edit.html.erb +8 -0
  281. data/app/views.current/fe/references/send_invite.js.erb +7 -0
  282. data/app/views.current/fe/references/show.html.erb +18 -0
  283. data/app/views.current/fe/references/submit.js.erb +3 -0
  284. data/app/views.current/fe/submit_pages/_errors.html.erb +1 -0
  285. data/app/views.current/fe/submit_pages/_thankyou.html.erb +2 -0
  286. data/app/views.current/fe/submit_pages/edit.html.erb +36 -0
  287. data/app/views.current/fe/submit_pages/error.js.erb +1 -0
  288. data/app/views.current/fe/submit_pages/submit.js.erb +3 -0
  289. data/app/views.current/layouts/fe/_error_messages_for.html.erb +7 -0
  290. data/app/views.current/layouts/fe/application.html.erb +47 -0
  291. data/app/{views/layouts/fe/fe.admin.html.erb → views.current/layouts/fe/fe_admin.html.erb} +4 -4
  292. data/config/initializers/paper_trail.rb +3 -0
  293. data/config/routes.rb +3 -37
  294. data/db/migrate/20131003041856_core.rb +23 -23
  295. data/db/migrate/20131003044250_create_reference_sheets.rb +2 -1
  296. data/db/migrate/20131003044436_add_element_and_answer_fields.rb +3 -3
  297. data/db/migrate/20131003044518_create_email_templates.rb +2 -2
  298. data/db/migrate/20131003044621_add_max_lengths.rb +1 -1
  299. data/db/migrate/20131003044714_create_join_table.rb +1 -1
  300. data/db/migrate/20131016162128_remove_question_id_from_element.rb +1 -1
  301. data/db/migrate/20140623153424_create_fe_people.rb +2 -2
  302. data/db/migrate/20140624180246_create_fe_addresses.rb +2 -2
  303. data/db/migrate/{20140624182216_create_create_fe_phone_numbers.rb → 20140624182216_create_fe_phone_numbers.rb} +2 -2
  304. data/db/migrate/20140625160545_create_fe_users.rb +2 -2
  305. data/db/migrate/20140808202507_add_conditional_type_to_elements.rb +1 -1
  306. data/db/migrate/20140808203609_add_conditional_answer_to_elements.rb +1 -1
  307. data/db/migrate/20141103204704_remove_short_value_column.rb +1 -1
  308. data/db/migrate/20141109154522_move_conditional_ids_used_for_choice_field_to_their_own_column.rb +1 -1
  309. data/db/migrate/20150504221439_add_all_element_ids_to_pages.rb +5 -0
  310. data/db/migrate/20150713022326_add_locale_columns.rb +9 -0
  311. data/db/migrate/20150714220730_add_locale_to_answer_sheet.rb +5 -0
  312. data/db/migrate/20150925181652_add_share_to_elements.rb +5 -0
  313. data/db/migrate/20150928085325_change_pages_all_element_ids_to_text.rb +5 -0
  314. data/db/migrate/20150930191538_add_locale_to_reference_sheets.rb +5 -0
  315. data/db/migrate/20151021181928_switch_conditional_answer_separator_to_semicolon.rb +7 -0
  316. data/db/migrate/20151021184250_add_question_sheet_id_in_refs.rb +12 -0
  317. data/db/migrate/20160201185838_add_visible_and_visibility_cache_key_to_reference_sheets.rb +6 -0
  318. data/db/migrate/20160805221415_add_rating_extra_labels.rb +10 -0
  319. data/db/migrate/20181108201746_create_versions.rb +80 -0
  320. data/db/migrate/20181218201130_increase_slug_length.rb +5 -0
  321. data/lib/access_key_generator.rb +12 -0
  322. data/lib/distinct_distinct_patch.rb +20 -0
  323. data/lib/fe/engine.rb +26 -14
  324. data/lib/fe/version.rb +1 -1
  325. data/lib/fe.rb +11 -1
  326. data/spec/controllers/fe/admin/elements_controller_spec.rb +211 -1
  327. data/spec/controllers/fe/admin/email_templates_controller_spec.rb +26 -1
  328. data/spec/controllers/fe/admin/question_pages_controller_spec.rb +8 -1
  329. data/spec/controllers/fe/admin/question_sheets_controller_spec.rb +48 -1
  330. data/spec/controllers/fe/answer_pages_controller_spec.rb +129 -1
  331. data/spec/controllers/fe/answer_sheets_controller_spec.rb +136 -1
  332. data/spec/controllers/fe/reference_pages_controller.rb +4 -0
  333. data/spec/controllers/fe/references_controller_spec.rb +4 -0
  334. data/spec/controllers/fe/submit_pages_controller_spec.rb +4 -0
  335. data/spec/dummy/app/assets/config/manifest.js +0 -0
  336. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  337. data/spec/dummy/app/helpers/application_helper.rb +9 -0
  338. data/spec/dummy/app/models/application.rb +3 -0
  339. data/spec/dummy/app/models/person.rb +11 -0
  340. data/spec/dummy/app/models/user.rb +3 -0
  341. data/spec/dummy/app/views/layouts/application.html.erb +2 -2
  342. data/spec/dummy/config/application.rb +3 -1
  343. data/spec/dummy/config/database.yml +20 -17
  344. data/spec/dummy/config/environments/production.rb +1 -5
  345. data/spec/dummy/config/environments/test.rb +4 -2
  346. data/spec/dummy/config/initializers/assets.rb +5 -2
  347. data/spec/dummy/config/initializers/fast_gettext.rb +5 -0
  348. data/spec/dummy/config/initializers/to_unsafe_h.rb +5 -0
  349. data/spec/dummy/config/initializers/to_unsafe_h.rb.new +5 -0
  350. data/spec/dummy/config/secrets.yml +2 -2
  351. data/spec/dummy/db/migrate/20141203214017_core.fe_engine.rb +92 -0
  352. data/spec/dummy/db/migrate/20141203214018_create_reference_sheets.fe_engine.rb +25 -0
  353. data/spec/dummy/db/migrate/20141203214019_add_element_and_answer_fields.fe_engine.rb +11 -0
  354. data/spec/dummy/db/migrate/20141203214020_create_email_templates.fe_engine.rb +18 -0
  355. data/spec/dummy/db/migrate/20141203214021_add_max_lengths.fe_engine.rb +9 -0
  356. data/spec/dummy/db/migrate/20141203214022_create_join_table.fe_engine.rb +12 -0
  357. data/spec/dummy/db/migrate/20141203214023_remove_question_id_from_element.fe_engine.rb +10 -0
  358. data/spec/dummy/db/migrate/20141203214024_create_fe_people.fe_engine.rb +13 -0
  359. data/spec/dummy/db/migrate/20141203214025_create_fe_addresses.fe_engine.rb +21 -0
  360. data/spec/dummy/db/migrate/20141203214027_create_fe_users.fe_engine.rb +13 -0
  361. data/spec/dummy/db/migrate/20141203214028_add_conditional_type_to_elements.fe_engine.rb +6 -0
  362. data/spec/dummy/db/migrate/20141203214029_add_conditional_answer_to_elements.fe_engine.rb +6 -0
  363. data/spec/dummy/db/migrate/20141203214030_remove_short_value_column.fe_engine.rb +6 -0
  364. data/spec/dummy/db/migrate/20141203214031_move_conditional_ids_used_for_choice_field_to_their_own_column.fe_engine.rb +8 -0
  365. data/spec/dummy/db/migrate/20150123215803_create_users.rb +9 -0
  366. data/spec/dummy/db/migrate/20150504222619_add_all_element_ids_to_pages.fe_engine.rb +6 -0
  367. data/spec/dummy/db/migrate/20150925192557_add_share_to_elements.fe_engine.rb +6 -0
  368. data/spec/dummy/db/migrate/20150930190001_create_fe_phone_numbers.fe_engine.rb +20 -0
  369. data/spec/dummy/db/migrate/20150930190002_add_locale_columns.fe_engine.rb +10 -0
  370. data/spec/dummy/db/migrate/20150930190003_add_locale_to_answer_sheet.fe_engine.rb +6 -0
  371. data/spec/dummy/db/migrate/20150930190004_change_pages_all_element_ids_to_text.fe_engine.rb +6 -0
  372. data/spec/dummy/db/migrate/20150930191756_add_locale_to_reference_sheets.fe_engine.rb +6 -0
  373. data/spec/dummy/db/migrate/20151021190027_add_question_sheet_id_in_refs.fe_engine.rb +13 -0
  374. data/spec/dummy/db/migrate/20160204164612_switch_conditional_answer_separator_to_semicolon.fe_engine.rb +8 -0
  375. data/spec/dummy/db/migrate/20160204164613_add_visible_and_visibility_cache_key_to_reference_sheets.fe_engine.rb +7 -0
  376. data/spec/dummy/db/migrate/20181108201746_create_versions.rb +80 -0
  377. data/spec/dummy/db/schema.rb +91 -69
  378. data/spec/dummy/log/test.log +101278 -419
  379. data/spec/factories/answer_sheet_question_sheets.rb +1 -1
  380. data/spec/factories/answer_sheets.rb +2 -2
  381. data/spec/factories/answers.rb +1 -1
  382. data/spec/factories/applications.rb +3 -4
  383. data/spec/factories/dummy_applications.rb +6 -0
  384. data/spec/factories/dummy_people.rb +6 -0
  385. data/spec/factories/dummy_users.rb +6 -0
  386. data/spec/factories/elements.rb +35 -10
  387. data/spec/factories/email_templates.rb +5 -0
  388. data/spec/factories/fe_addresses.rb +10 -10
  389. data/spec/factories/fe_email_addresses.rb +3 -3
  390. data/spec/factories/fe_email_templates.rb +9 -0
  391. data/spec/factories/fe_people.rb +5 -7
  392. data/spec/factories/fe_phone_numbers.rb +3 -3
  393. data/spec/factories/fe_user.rb +6 -0
  394. data/spec/factories/page.rb +1 -1
  395. data/spec/factories/page_elements.rb +1 -1
  396. data/spec/factories/paragraphs.rb +1 -1
  397. data/spec/factories/question_sheet.rb +3 -3
  398. data/spec/factories/reference_questions.rb +1 -1
  399. data/spec/factories/reference_sheets.rb +9 -0
  400. data/spec/jobs/fe/update_reference_sheet_visibility_job_spec.rb +40 -0
  401. data/spec/mailers/fe/notifier_spec.rb +39 -0
  402. data/spec/models/fe/answer_sheet_question_sheet_spec.rb +1 -1
  403. data/spec/models/fe/answer_spec.rb +2 -2
  404. data/spec/models/fe/application_spec.rb +94 -1
  405. data/spec/models/fe/choice_field_spec.rb +66 -0
  406. data/spec/models/fe/condition_spec.rb +2 -2
  407. data/spec/models/fe/element_spec.rb +414 -37
  408. data/spec/models/fe/email_template_spec.rb +1 -1
  409. data/spec/models/fe/page_element_spec.rb +1 -1
  410. data/spec/models/fe/page_spec.rb +168 -11
  411. data/spec/models/fe/person_spec.rb +1 -1
  412. data/spec/models/fe/question_set_spec.rb +91 -0
  413. data/spec/models/fe/question_sheet_spec.rb +103 -1
  414. data/spec/models/fe/question_spec.rb +73 -6
  415. data/spec/models/fe/reference_question_spec.rb +20 -0
  416. data/spec/models/fe/reference_sheet_spec.rb +305 -2
  417. data/spec/models/fe/text_field_spec.rb +22 -0
  418. data/spec/rails_helper.rb +85 -54
  419. data/spec/support/choices.xml +6 -0
  420. metadata +310 -84
  421. data/app/assets/javascripts/fe/fe.common.js +0 -57
  422. data/app/assets/javascripts/fe/jquery.scrollTo-min.js +0 -7
  423. data/app/assets/javascripts/fe/rails.extra.js +0 -6
  424. data/app/controllers/fe/applications_controller.rb +0 -183
  425. data/app/controllers/fe/concerns/answer_pages_controller_concern.rb +0 -83
  426. data/app/controllers/fe/payments_controller.rb +0 -184
  427. data/app/models/fe/concerns/answer_sheet_concern.rb +0 -55
  428. data/app/models/fe/payment.rb +0 -77
  429. data/app/models/fe/payment_question.rb +0 -22
  430. data/app/views/fe/admin/panels/_prop_payment_question.html.erb +0 -1
  431. data/app/views/fe/application/_logout.html.erb +0 -1
  432. data/app/views/fe/payment_pages/_credit.html.erb +0 -47
  433. data/app/views/fe/payment_pages/_mail.html.erb +0 -27
  434. data/app/views/fe/payment_pages/_payment.html.erb +0 -6
  435. data/app/views/fe/payment_pages/_staff.html.erb +0 -25
  436. data/app/views/fe/payment_pages/_staff_results.html.erb +0 -17
  437. data/app/views/fe/payment_pages/edit.html.erb +0 -75
  438. data/app/views/fe/payment_pages/staff_search.js.erb +0 -2
  439. data/app/views/fe/payments/_credit.html.erb +0 -47
  440. data/app/views/fe/payments/_errors.html.erb +0 -1
  441. data/app/views/fe/payments/_payment.html.erb +0 -13
  442. data/app/views/fe/payments/_staff.html.erb +0 -21
  443. data/app/views/fe/payments/_staff_results.html.erb +0 -18
  444. data/app/views/fe/payments/approve.js.erb +0 -3
  445. data/app/views/fe/payments/create.js.erb +0 -19
  446. data/app/views/fe/payments/destroy.js.erb +0 -7
  447. data/app/views/fe/payments/edit.html.erb +0 -56
  448. data/app/views/fe/payments/error.js.erb +0 -3
  449. data/app/views/fe/payments/no_access.html.erb +0 -7
  450. data/app/views/fe/payments/staff_search.js.erb +0 -1
  451. data/app/views/fe/payments/update.html.erb +0 -24
  452. data/app/views/fe/questions/fe/_payment_question.html.erb +0 -70
  453. data/db/migrate/20140828045339_create_payments.rb +0 -13
  454. data/spec/dummy/db/test.sqlite3 +0 -0
  455. data/spec/factories/payments.rb +0 -7
  456. data/spec/models/fe/payment_question_spec.rb +0 -65
@@ -3,30 +3,24 @@
3
3
  module Fe
4
4
  class QuestionSet
5
5
 
6
- attr_reader :elements
6
+ attr_reader :elements, :questions
7
7
 
8
8
  # associate answers from database with a set of elements
9
9
  def initialize(elements, answer_sheet)
10
10
  @elements = elements
11
11
  @answer_sheet = answer_sheet
12
-
13
12
  @questions = elements.select { |e| e.question? }
14
-
15
- # answers = @answer_sheet.answers_by_question
16
-
17
- @questions.each do |question|
18
- question.answers = question.responses(answer_sheet) #answers[question.id]
19
- end
20
- @questions
21
13
  end
22
14
 
23
15
  # update with responses from form
24
16
  def post(params, answer_sheet)
25
- questions_indexed = @questions.index_by {|q| q.id}
17
+ questions_indexed = @questions.index_by(&:id)
26
18
 
27
19
  # loop over form values
28
20
  params ||= {}
29
- params.each do |question_id, response|
21
+ # we only assign answers to questions from this set, so it's fine to use to_unsafe_h here. If we don't,
22
+ # the kind_of?(Hash) checks will fail as per rails 5
23
+ params.to_unsafe_h.each do |question_id, response|
30
24
  next if questions_indexed[question_id.to_i].nil? # the rare case where a question was removed after the app was opened.
31
25
  # update each question with the posted response
32
26
  questions_indexed[question_id.to_i].set_response(posted_values(response), answer_sheet)
@@ -53,6 +47,51 @@ module Fe
53
47
  end
54
48
  end
55
49
 
50
+ # options should contain:
51
+ #
52
+ # :filter - Array of symbols, ex [ :confidential ]
53
+ #
54
+ # These will be called on each element to determine if they match the filter
55
+ # An element matches the filter using an AND condition, ie. if all the methods
56
+ # in the array return true
57
+ #
58
+ # :filter_default - Either :show or :hide
59
+ #
60
+ # If show, all elements are shown by default and hidden if they match the filter.
61
+ # If hide, all elements are hidden by default and shown if they match the filter.
62
+ #
63
+ def set_filter(options = {})
64
+ return if options.nil? || options.empty?
65
+
66
+ filter = options.delete(:filter)
67
+ unless filter && filter.is_a?(Array)
68
+ raise("expect options[:filter] to be an array")
69
+ end
70
+ filter_default = options.delete(:filter_default)
71
+ unless filter_default && [:show, :hide].include?(filter_default)
72
+ raise("expect options[:filter_default] to be either :show or :hide")
73
+ end
74
+
75
+ @filter = filter
76
+ @filter_default = filter_default
77
+
78
+ matching_ids = []
79
+ @elements.each do |e|
80
+ if e.matches_filter(@filter) && !matching_ids.include?(e.id)
81
+ matching_ids << e.id
82
+ matching_ids += e.all_elements.collect(&:id)
83
+ end
84
+ end
85
+
86
+ case filter_default
87
+ when :show
88
+ @elements = @elements.to_a.reject{ |e| matching_ids.include?(e.id) }
89
+ when :hide
90
+ @elements = @elements.to_a.select{ |e| matching_ids.include?(e.id) }
91
+ end
92
+
93
+ initialize(@elements, @answer_sheet)
94
+ end
56
95
 
57
96
  private
58
97
 
@@ -65,11 +104,13 @@ module Fe
65
104
  if month.blank? or year.blank?
66
105
  values = ''
67
106
  else
68
- values = [Date.new(year.to_i, month.to_i, 1).strftime('%m/%d/%Y')] # for mm/yy drop downs
107
+ values = [Date.new(year.to_i, month.to_i, 1).strftime('%Y-%m-%d')] # for mm/yy drop downs
69
108
  end
70
109
  elsif param.kind_of?(Hash)
71
110
  # from Hash with multiple answers per question
72
- values = param.values.map {|v| CGI.unescape(v)}
111
+ # If value is also a hash, use the value hash without escaping or anything,
112
+ # so that custom elements can be implemented by handling set_response.
113
+ values = param.values.map {|v| v.is_a?(Hash) ? v : CGI.unescape(v)}
73
114
  elsif param.kind_of?(String)
74
115
  values = [CGI.unescape(param)]
75
116
  end
@@ -77,6 +118,5 @@ module Fe
77
118
  # Hash may contain empty string to force post for no checkboxes
78
119
  # values = values.reject {|r| r == ''}
79
120
  end
80
-
81
121
  end
82
122
  end
@@ -1,61 +1,96 @@
1
1
  # QuestionSheet represents a particular form
2
2
  module Fe
3
- class QuestionSheet < ActiveRecord::Base
3
+ class QuestionSheet < ApplicationRecord
4
4
  self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
5
5
 
6
- has_many :pages, -> { order('number') },
7
- :dependent => :destroy
6
+ attr_accessor :old_id
7
+ attr_accessor :element_id_mappings
8
8
 
9
- # has_many :elements
10
- # has_many :questions
9
+ has_many :pages, -> { order('number') },
10
+ dependent: :destroy
11
11
 
12
12
  has_many :answer_sheet_question_sheets
13
13
 
14
14
  has_many :answer_sheets,
15
- :through => :answer_sheet_question_sheets
15
+ through: :answer_sheet_question_sheets
16
+ has_many :question_sheets,
17
+ through: :answer_sheet_question_sheets
16
18
 
17
- scope :active, -> { where(:archived => false) }
18
- scope :archived, -> { where(:archived => true) }
19
+ scope :active, -> { where(archived: false) }
20
+ scope :archived, -> { where(archived: true) }
19
21
 
20
22
  validates_presence_of :label
21
- # validates_length_of :label, :maximum => 60, :allow_nil => true
22
- validates_uniqueness_of :label
23
+
24
+ serialize :languages, Array
23
25
 
24
26
  before_destroy :check_for_answers
25
27
 
26
28
  # create a new form with a page already attached
27
29
  def self.new_with_page
28
- question_sheet = self.new(:label => next_label)
29
- question_sheet.pages.build(:label => 'Page 1', :number => 1)
30
+ question_sheet = self.new(label: next_label)
31
+ question_sheet.pages.build(label: 'Page 1', number: 1)
30
32
  question_sheet
31
33
  end
32
34
 
33
35
  def questions
34
- pages.collect(&:questions).flatten
36
+ all_elements.questions
35
37
  end
36
38
 
37
39
  def elements
38
40
  pages.collect(&:elements).flatten
39
41
  end
40
42
 
43
+ def all_elements
44
+ element_ids = pages.pluck(:all_element_ids).compact.join(',').split(',').find_all(&:present?)
45
+ element_ids.present? ? Element.where(id: element_ids).order(Arel.sql(element_ids.collect{ |id| "id=#{id} DESC" }.join(', '))) : Element.where("1 = 0")
46
+ end
47
+
41
48
  # Pages get duplicated
42
49
  # Question elements get associated
43
50
  # non-question elements get cloned
44
51
  def duplicate
45
52
  new_sheet = QuestionSheet.new(self.attributes.merge(id: nil))
46
53
  new_sheet.label = self.label + ' - COPY'
47
- new_sheet.save(:validate => false)
54
+ new_sheet.save(validate: false)
48
55
  self.pages.each do |page|
49
56
  page.copy_to(new_sheet)
50
57
  end
51
58
  new_sheet
52
59
  end
53
60
 
54
- # pages hidden by a conditional element
55
- def hidden_pages(answer_sheet)
56
- elements.find_all{ |e|
57
- e.conditional.is_a?(Fe::Page) && !e.conditional_match(answer_sheet)
58
- }.collect(&:conditional)
61
+ def export_to_yaml
62
+ atts = attributes.to_hash
63
+ atts[:pages] = pages.collect(&:export_hash)
64
+ atts.to_yaml
65
+ end
66
+
67
+ def self.create_from_yaml(filename)
68
+ # NOTE: yaml will break if some classes aren't loaded before YAML::load, strange
69
+ Fe::Element.distinct.where.not(kind: 'Fe::Style').pluck(:kind).each(&:constantize)
70
+
71
+ sheet_data = YAML::load(File.read(filename))
72
+ sheet_data[:old_id] = sheet_data.delete("id")
73
+ pages = sheet_data.delete(:pages)
74
+ puts("Create import by data #{sheet_data}")
75
+ question_sheet = Fe::QuestionSheet.create!(sheet_data)
76
+ question_sheet.element_id_mappings = []
77
+ pages.each do |page_atts|
78
+ page = Page.create_from_import(page_atts, question_sheet)
79
+ question_sheet.pages << page
80
+ end
81
+ # set page conditional_id values to new ids based on old_id
82
+ question_sheet.all_elements.each do |el|
83
+ if el.conditional_type != "Fe::Page" && el.conditional_id.present?
84
+ # noop
85
+ end
86
+
87
+ # note that conditional elements are already translated to new ids in the element import so no need to do it here
88
+ if el.conditional_type == "Fe::Page" && el.conditional_id
89
+ el.update(conditional_id: question_sheet.pages.detect{ |el2| el2.old_id == el.conditional_id }&.id)
90
+ end
91
+ end
92
+
93
+ question_sheet
59
94
  end
60
95
 
61
96
  private
@@ -2,22 +2,15 @@
2
2
  # - a question that provides a fields to specify a reference
3
3
  module Fe
4
4
  class ReferenceQuestion < Question
5
+ has_many :reference_sheets, foreign_key: :question_id
6
+
7
+ after_save :update_references_question_sheet_ids
5
8
 
6
9
  def response(app=nil)
7
10
  return unless app
8
11
  # A reference is the same if the related_question_sheet corresponding to the question is the same
9
12
  reference = Fe::ReferenceSheet.find_by_applicant_answer_sheet_id_and_question_id(app.id, id)
10
- # if references.present?
11
- # reference = references.detect {|r| r.question_id == id }
12
- # # If they have another reference that matches this question id, don't go fishing for another one
13
- # unless reference
14
- # # If the question_id doesn't match, but the reference question is based on the same reference template (question sheet)
15
- # # update the reference with the new question_id
16
- # reference = references.detect {|r| r.question.related_question_sheet_id == related_question_sheet_id}
17
- # reference.update_attribute(:question_id, id) if reference
18
- # end
19
- # end
20
- reference || Fe::ReferenceSheet.create(:applicant_answer_sheet_id => app.id, :question_id => id)
13
+ reference || Fe::ReferenceSheet.create(applicant_answer_sheet_id: app.id, question_id: id)
21
14
  end
22
15
 
23
16
  def has_response?(app = nil)
@@ -25,11 +18,11 @@ module Fe
25
18
  reference = response(app)
26
19
  reference && reference.valid?
27
20
  else
28
- Fe::ReferenceSheet.where(:question_id => id).count > 0
21
+ Fe::ReferenceSheet.where(question_id: id).count > 0
29
22
  end
30
23
  end
31
24
 
32
- def display_response(app=nil)
25
+ def display_response(app = nil, humanize = false)
33
26
  response(app).to_s
34
27
  end
35
28
 
@@ -38,5 +31,8 @@ module Fe
38
31
  "fe/reference_#{style}"
39
32
  end
40
33
 
34
+ def update_references_question_sheet_ids
35
+ reference_sheets.where(status: :created).update_all(question_sheet_id: related_question_sheet_id, updated_at: Time.now)
36
+ end
41
37
  end
42
38
  end
@@ -1,38 +1,49 @@
1
1
  require 'validates_email_format_of'
2
2
  require 'aasm'
3
3
  module Fe
4
- class ReferenceSheet < ActiveRecord::Base
4
+ class ReferenceSheet < ApplicationRecord
5
5
  include Fe::AnswerSheetConcern
6
6
  include Rails.application.routes.url_helpers
7
7
  include AASM
8
+ include AccessKeyGenerator
9
+
10
+ attr_accessor :allow_quiet_reference_email_changes
11
+
8
12
  self.table_name = "#{Fe.table_name_prefix}references"
9
13
  self.inheritance_column = 'fake'
10
14
 
15
+ scope :visible, -> { where(visible: true) }
16
+
11
17
  belongs_to :question,
12
- :class_name => 'Element',
13
- :foreign_key => 'question_id'
18
+ class_name: 'Fe::ReferenceQuestion',
19
+ foreign_key: 'question_id'
14
20
 
15
21
  belongs_to :applicant_answer_sheet,
16
- :class_name => Fe.answer_sheet_class,
17
- :foreign_key => "applicant_answer_sheet_id"
22
+ class_name: "::#{Fe.answer_sheet_class}",
23
+ foreign_key: "applicant_answer_sheet_id"
18
24
 
19
- validates_presence_of :first_name, :last_name, :phone, :email, :relationship, :on => :update, :message => "can't be blank"
20
- validates :email, :email_format => { :message => "doesn't look right." }
25
+ # using belongs_to :question_sheet doesn't work, it uses the Fe::AnswerSheetConcern#question_sheet implementation
26
+ belongs_to :question_sheet_ref, optional: true, class_name: 'Fe::QuestionSheet', foreign_key: :question_sheet_id
21
27
 
22
- delegate :style, :to => :question
28
+ validates_presence_of :first_name, :last_name, :phone, :email, :relationship, on: :update, message: "can't be blank"
29
+ validates :email, email_format: { on: :update, message: "doesn't look right." }
23
30
 
24
- before_save :check_email_change
31
+ delegate :style, to: :question
25
32
 
33
+ before_save :reset_reference, if: :new_reference_requested?
34
+ after_save :notify_old_reference_not_needed, if: :new_reference_requested?
35
+ before_create :set_question_sheet
26
36
  after_destroy :notify_reference_of_deletion
37
+ after_create :update_visible
27
38
 
28
- aasm :initial => :created, :column => :status do
39
+ aasm column: :status do
29
40
 
30
- state :started, :enter => Proc.new {|ref|
31
- ref.started_at = Time.now
41
+ state :started, enter: Proc.new {
42
+ update(started_at: Time.now)
32
43
  }
33
- state :created
34
- state :completed, :enter => Proc.new {|ref|
35
- ref.submitted_at = Time.now
44
+ state :created, initial: true
45
+ state :completed, enter: Proc.new {
46
+ update(submitted_at: Time.now)
36
47
  # SpReferenceMailer.deliver_completed(ref)
37
48
  =begin
38
49
  Fe::Notifier.notification(ref.email, # RECIPIENTS
@@ -57,26 +68,44 @@ module Fe
57
68
  'password' => person.user.password_plain}).deliver
58
69
  =end
59
70
 
60
- ref.applicant_answer_sheet.complete(ref)
71
+ applicant_answer_sheet.complete(self)
61
72
  }
62
73
 
63
74
  event :start do
64
- transitions :to => :started, :from => :created
75
+ transitions to: :started, from: :created
65
76
  end
66
77
 
67
78
  event :submit do
68
- transitions :to => :completed, :from => :started
69
- transitions :to => :completed, :from => :created
79
+ transitions to: :completed, from: :started
80
+ transitions to: :completed, from: :created
70
81
  end
71
82
 
72
83
  event :unsubmit do
73
- transitions :to => :started, :from => :completed
84
+ transitions to: :started, from: :completed
74
85
  end
75
86
  end
76
87
 
77
- alias_method :applicant, :applicant_answer_sheet
78
- def generate_access_key
79
- self.access_key = Digest::MD5.hexdigest(email + Time.now.to_s)
88
+ alias_method :application, :applicant_answer_sheet
89
+ delegate :applicant, to: :application
90
+
91
+ def computed_visibility_cache_key
92
+ return @computed_visibility_cache_key if @computed_visibility_cache_key
93
+ return nil unless question # keep from crashing for tests
94
+ answers = Fe::Answer.where(question_id: question.visibility_affecting_element_ids,
95
+ answer_sheet_id: applicant_answer_sheet)
96
+ answers.collect(&:cache_key_with_version).join('/')
97
+ end
98
+
99
+ def update_visible(page = nil)
100
+ if visibility_cache_key == computed_visibility_cache_key
101
+ visible
102
+ else
103
+ self.visible = question.visible?(applicant_answer_sheet, page)
104
+ self.visibility_cache_key = computed_visibility_cache_key
105
+ # save only these columns and don't check validations, but do record updated_at
106
+ # as it is significant enough of an event that we probably want that to set updated_at
107
+ Fe::ReferenceSheet.where(id: id).update_all(visibility_cache_key: self.computed_visibility_cache_key, visible: self.visible, updated_at: Time.now)
108
+ end
80
109
  end
81
110
 
82
111
  def frozen?
@@ -86,7 +115,7 @@ module Fe
86
115
  def email_sent?() !self.email_sent_at.nil? end
87
116
 
88
117
  # send email invite
89
- def send_invite
118
+ def send_invite(host)
90
119
  return if self.email.blank?
91
120
 
92
121
  application = self.applicant_answer_sheet
@@ -95,21 +124,21 @@ module Fe
95
124
  Fe.from_email,
96
125
  "Reference Invite",
97
126
  {'reference_full_name' => self.name,
98
- 'applicant_full_name' => application.name,
99
- 'applicant_email' => application.email,
100
- 'applicant_home_phone' => application.phone,
101
- 'reference_url' => edit_fe_reference_sheet_url(self, :a => self.access_key, :host => ActionMailer::Base.default_url_options[:host])}).deliver
127
+ 'applicant_full_name' => application.applicant.name,
128
+ 'applicant_email' => application.applicant.email,
129
+ 'applicant_home_phone' => application.applicant.phone,
130
+ 'reference_url' => edit_fe_reference_sheet_url(self, a: self.access_key, host: host)}).deliver_now
102
131
  # Send notification to applicant
103
- Notifier.notification(applicant_answer_sheet.email, # RECIPIENTS
132
+ Notifier.notification(applicant_answer_sheet.applicant.email, # RECIPIENTS
104
133
  Fe.from_email, # FROM
105
134
  "Reference Notification to Applicant", # LIQUID TEMPLATE NAME
106
- {'applicant_full_name' => applicant_answer_sheet.name,
135
+ {'applicant_full_name' => applicant_answer_sheet.applicant.name,
107
136
  'reference_full_name' => self.name,
108
137
  'reference_email' => self.email,
109
- 'application_url' => edit_fe_answer_sheet_url(applicant_answer_sheet, :host => ActionMailer::Base.default_url_options[:host])}).deliver
138
+ 'application_url' => edit_fe_answer_sheet_url(applicant_answer_sheet, host: host)}).deliver_now
110
139
 
111
140
  self.email_sent_at = Time.now
112
- self.save(:validate => false)
141
+ self.save(validate: false)
113
142
 
114
143
  true
115
144
  end
@@ -126,48 +155,78 @@ module Fe
126
155
  name
127
156
  end
128
157
 
129
- def required?
130
- question.required?(applicant_answer_sheet)
131
- end
132
-
133
158
  def reference?
134
159
  true
135
160
  end
136
161
 
137
162
  # Can't rely on answer_sheet's implementation for old reference's that might have id's that may match an application id
138
163
  def question_sheet
139
- QuestionSheet.find(question.related_question_sheet_id) if question && question.related_question_sheet_id
164
+ question_sheet_ref
140
165
  end
141
166
 
142
- # Can't rely on answer_sheet's implementation for old reference's that might have id's that may match an application id
143
167
  def question_sheets
144
- [question_sheet]
168
+ [question_sheet_ref]
169
+ end
170
+
171
+ def question_sheet_ids
172
+ [question_sheet_id].compact
145
173
  end
146
174
 
147
175
  def display_type
148
176
  question.label.split(/:| \(/).first
149
177
  end
150
178
 
179
+ def optional?
180
+ question.try(:hidden?, applicant_answer_sheet)
181
+ end
182
+
183
+ def required?
184
+ question.required?(applicant_answer_sheet) && !optional?
185
+ end
186
+
187
+ def all_affecting_questions_answered
188
+ return false unless question
189
+ question.visibility_affecting_questions.all? { |q| q.has_response?(applicant_answer_sheet) }
190
+ end
191
+
151
192
  protected
193
+
194
+ def set_question_sheet
195
+ self.question_sheet_id = question.try(:related_question_sheet_id)
196
+ end
197
+
152
198
  # if the email address has changed, we have to trash the old reference answers
153
- def check_email_change
154
- if changed.include?('email')
155
- answers.destroy_all
156
- # Every time the email address changes, generate a new access_key
157
- generate_access_key
158
- self.email_sent_at = nil
159
- self.status = 'created'
160
- end
199
+ def reset_reference
200
+ answers.destroy_all
201
+ # Every time the email address changes, generate a new access_key
202
+ generate_access_key
203
+ self.email_sent_at = nil
204
+ self.status = 'created'
205
+ end
206
+
207
+ def notify_old_reference_not_needed
208
+ return unless email_sent_at_was.present? && email_was.present?
209
+ notify_reference_not_needed(self, email_was, first_name_was, last_name_was)
161
210
  end
162
211
 
163
212
  def notify_reference_of_deletion
164
- if email.present?
165
- Notifier.notification(email,
166
- Fe.from_email,
167
- "Reference Deleted",
168
- {'reference_full_name' => self.name,
169
- 'applicant_full_name' => applicant_answer_sheet.name}).deliver
170
- end
213
+ return unless email_sent_at.present? && email.present?
214
+ notify_reference_not_needed(self, email, first_name, last_name)
215
+ end
216
+
217
+ def notify_reference_not_needed(ref, ref_email, ref_first_name, ref_last_name)
218
+ # inform referrer that they no longer need to fill out reference
219
+ Fe::Notifier.notification(
220
+ ref_email, # RECIPIENTS
221
+ Fe.from_email, # FROM
222
+ 'Reference Deleted',
223
+ { 'reference_full_name' => "#{ref_first_name} #{ref_last_name}",
224
+ 'applicant_full_name' => applicant_answer_sheet.applicant.name }
225
+ ).deliver_now
226
+ end
227
+
228
+ def new_reference_requested?
229
+ !allow_quiet_reference_email_changes && !new_record? && !completed? && email_changed?
171
230
  end
172
231
  end
173
232
  end
@@ -3,8 +3,8 @@ require 'carmen'
3
3
  # - drop down of states
4
4
  module Fe
5
5
  class StateChooser < Question
6
- def choices(country = 'US')
7
- @states = Carmen.states(country)
6
+ def choices(locale = nil, country = 'US')
7
+ @states = _(Carmen.states(country))
8
8
  end
9
9
  end
10
10
  end
@@ -14,9 +14,9 @@ module Fe
14
14
  end
15
15
 
16
16
  # css class names for javascript-based validation
17
- def validation_class(answer_sheet)
17
+ def validation_class(answer_sheet, page = nil)
18
18
  validation = ''
19
- validation += ' required' if self.required?(answer_sheet)
19
+ validation += ' required' if self.required?(answer_sheet, page)
20
20
  # validate-number, etc.
21
21
  validate_style = ['number', 'currency-dollar', 'email', 'url', 'phone'].find {|v| v == self.style }
22
22
  if validate_style
@@ -1,3 +1,3 @@
1
- class Fe::User < ActiveRecord::Base
1
+ class Fe::User < ApplicationRecord
2
2
  belongs_to :user
3
3
  end
data/app/models/staff.rb CHANGED
@@ -1,10 +1,12 @@
1
- class Staff < ActiveRecord::Base
1
+ class Staff < ApplicationRecord
2
2
  self.table_name = "ministry_staff"
3
3
  belongs_to :person
4
4
 
5
- belongs_to :primary_address, :class_name => "StaffAddress", :foreign_key => :fk_primaryAddress
6
- belongs_to :secondary_address, :class_name => "StaffAddress", :foreign_key => :fk_secondaryAddress
5
+ belongs_to :primary_address, class_name: "StaffAddress", foreign_key: :fk_primaryAddress
6
+ belongs_to :secondary_address, class_name: "StaffAddress", foreign_key: :fk_secondaryAddress
7
7
 
8
+ alias_attribute :preferred_name, :preferredName
9
+
8
10
  def self.get_staff(ssm_id)
9
11
  if ssm_id.nil? then raise "nil ssm_id!" end
10
12
  ssm_user = User.find_by(userID: ssm_id)
@@ -70,13 +72,13 @@ class Staff < ActiveRecord::Base
70
72
  ]
71
73
  end
72
74
 
73
- scope :specialty_roles, -> { where(:jobStatus => "Staff Full Time").where(:ministry => "Campus Ministry").
74
- where(:removedFromPeopleSoft => "N").where("jobTitle NOT IN (?)", field_roles).order(:jobTitle).order(:lastName) }
75
+ scope :specialty_roles, -> { where(jobStatus: "Staff Full Time").where(ministry: "Campus Ministry").
76
+ where(removedFromPeopleSoft: "N").where("jobTitle NOT IN (?)", field_roles).order(:jobTitle).order(:lastName) }
75
77
 
76
78
  def self.get_roles(region)
77
79
  result = {}
78
80
  Staff.strategy_order.each do |strategy|
79
- result[strategy] = specialty_roles.where(:strategy => strategy).where(:region => region)
81
+ result[strategy] = specialty_roles.where(strategy: strategy).where(region: region)
80
82
  end
81
83
  result
82
84
  end
@@ -0,0 +1,11 @@
1
+ require 'mail'
2
+
3
+ class EmailValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ begin
6
+ parsed = Mail::Address.new(value)
7
+ rescue Mail::Field::ParseError => e
8
+ end
9
+ record.errors.add attribute, "is not valid" unless !parsed.nil? && parsed.address == value && parsed.local != value #cannot be a local address
10
+ end
11
+ end
@@ -1,11 +1,12 @@
1
1
  <% if @page_element %>
2
2
  $('#question_modal').dialog('close');
3
- $('#page-preview').html('<%= escape_javascript(render('fe/admin/question_pages/question_page')) %>');
3
+ $('#page-preview').html('<%= escape_javascript(render("fe/admin/question_pages/question_page")) %>');
4
4
  $('#element_<%= dom_id(@element) %>').hide();
5
- $('#element_form_<%= dom_id(@element) %>').html('<%= escape_javascript(render('fe/admin/panels/prop_element',:element => @element)) %>');
5
+ $('#element_form_<%= dom_id(@element) %>').html('<%= escape_javascript(render("fe/admin/panels/prop_element", element: @element)) %>');
6
6
  $('#element_form_<%= dom_id(@element) %>').show();
7
7
  selectElement("#element_<%= @element.id %>");
8
- $.scrollTo("#element_<%= @element.id %>");
8
+ scrollTo("#element_<%= @element.id %>");
9
+ setUpSortables();
9
10
  <% else %>
10
11
  alert('That question already exists on this question sheet')
11
12
  <% end %>
@@ -1,4 +1,4 @@
1
1
  $('#element_<%= @element.id %>').remove()
2
- $('#panel').html('<%= escape_javascript(render('fe/admin/panels/insert')) %>')
2
+ $('#panel').html('<%= escape_javascript(render("fe/admin/panels/insert")) %>')
3
3
  activeElement = ''
4
4
  switchTab('insert')
@@ -1,2 +1,3 @@
1
- $('#page-preview').html('<%= escape_javascript(render('fe/admin/question_pages/question_page', :page => @page)) %>')
1
+ $('#page-preview').html('<%= escape_javascript(render("fe/admin/question_pages/question_page", page: @page)) %>')
2
2
  $('#list-pages li').removeClass('active')
3
+ setUpJsHelpers();
@@ -1,2 +1,3 @@
1
- $('#page-preview').html('<%= escape_javascript(render('fe/admin/question_pages/question_page')) %>')
1
+ $('#page-preview').html('<%= escape_javascript(render("fe/admin/question_pages/question_page")) %>')
2
2
  selectElement("#element_<%= @element.id %>")
3
+ setUpSortables();
@@ -1,4 +1,4 @@
1
1
  $('#element_<%= dom_id(@element) %>').hide()
2
- $('#element_form_<%= dom_id(@element) %>').html('<%= escape_javascript(render('fe/admin/panels/prop_element',:element => @element)) %>')
2
+ $('#element_form_<%= dom_id(@element) %>').html('<%= escape_javascript(render("fe/admin/panels/prop_element", element: @element)) %>')
3
3
  $('#element_form_<%= dom_id(@element) %>').show();
4
4
  selectElement("#element_<%= @element.id %>")
@@ -1,4 +1,4 @@
1
- $('#errors').html('<%= escape_javascript(render('errors', :element => @element)) %>')
1
+ $('#errors').html('<%= escape_javascript(render("errors", element: @element)) %>')
2
2
  <% @element.errors.each do |attr_name, message| %>
3
3
  addError('element_<%= attr_name %>')
4
4
  <% end %>