fe 0.0.3

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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +20 -0
  4. data/Rakefile +48 -0
  5. data/app/assets/images/fe/ajax-loader.gif +0 -0
  6. data/app/assets/images/fe/butgrad.png +0 -0
  7. data/app/assets/images/fe/icons/add.png +0 -0
  8. data/app/assets/images/fe/icons/application_form.png +0 -0
  9. data/app/assets/images/fe/icons/application_form_add.png +0 -0
  10. data/app/assets/images/fe/icons/arrow-move.png +0 -0
  11. data/app/assets/images/fe/icons/arrow_out.png +0 -0
  12. data/app/assets/images/fe/icons/asterisk_yellow.png +0 -0
  13. data/app/assets/images/fe/icons/book-open-list.png +0 -0
  14. data/app/assets/images/fe/icons/book_open.png +0 -0
  15. data/app/assets/images/fe/icons/briefcase.png +0 -0
  16. data/app/assets/images/fe/icons/calendar_view_day.png +0 -0
  17. data/app/assets/images/fe/icons/checkbox.png +0 -0
  18. data/app/assets/images/fe/icons/copy_paste.gif +0 -0
  19. data/app/assets/images/fe/icons/disk.png +0 -0
  20. data/app/assets/images/fe/icons/document--pencil.png +0 -0
  21. data/app/assets/images/fe/icons/document-copy.png +0 -0
  22. data/app/assets/images/fe/icons/map_magnify.png +0 -0
  23. data/app/assets/images/fe/icons/minus-button.png +0 -0
  24. data/app/assets/images/fe/icons/move.png +0 -0
  25. data/app/assets/images/fe/icons/page_error.png +0 -0
  26. data/app/assets/images/fe/icons/page_valid.png +0 -0
  27. data/app/assets/images/fe/icons/page_white.png +0 -0
  28. data/app/assets/images/fe/icons/page_white_add.png +0 -0
  29. data/app/assets/images/fe/icons/page_white_error.png +0 -0
  30. data/app/assets/images/fe/icons/paper-clip.png +0 -0
  31. data/app/assets/images/fe/icons/pencil-small.png +0 -0
  32. data/app/assets/images/fe/icons/pencil.png +0 -0
  33. data/app/assets/images/fe/icons/question-balloon.png +0 -0
  34. data/app/assets/images/fe/icons/radio.png +0 -0
  35. data/app/assets/images/fe/icons/star-small.png +0 -0
  36. data/app/assets/images/fe/icons/table.png +0 -0
  37. data/app/assets/images/fe/icons/text_align_left.png +0 -0
  38. data/app/assets/images/fe/icons/text_horizontalrule.png +0 -0
  39. data/app/assets/images/fe/icons/textfield.png +0 -0
  40. data/app/assets/images/fe/indent.png +0 -0
  41. data/app/assets/images/fe/overlay.png +0 -0
  42. data/app/assets/images/fe/selected_bg.jpg +0 -0
  43. data/app/assets/images/fe/status.gif +0 -0
  44. data/app/assets/images/fe/tooltip/black.png +0 -0
  45. data/app/assets/images/fe/tooltip/black_arrow.png +0 -0
  46. data/app/assets/images/fe/tooltip/black_arrow_big.png +0 -0
  47. data/app/assets/images/fe/tooltip/black_big.png +0 -0
  48. data/app/assets/images/fe/tooltip/white.png +0 -0
  49. data/app/assets/images/fe/tooltip/white_arrow.png +0 -0
  50. data/app/assets/images/fe/tooltip/white_arrow_big.png +0 -0
  51. data/app/assets/images/fe/tooltip/white_big.png +0 -0
  52. data/app/assets/images/fe/uploadify/cancel.png +0 -0
  53. data/app/assets/images/fe/uploadify/uploadify.swf +0 -0
  54. data/app/assets/javascripts/fe/admin.js +7 -0
  55. data/app/assets/javascripts/fe/jquery.metadata.js +122 -0
  56. data/app/assets/javascripts/fe/jquery.scrollTo-min.js +7 -0
  57. data/app/assets/javascripts/fe/jquery.uploadify.v2.1.0.js +258 -0
  58. data/app/assets/javascripts/fe/jquery.validate.pack.js +15 -0
  59. data/app/assets/javascripts/fe/qe.admin.js +115 -0
  60. data/app/assets/javascripts/fe/qe.common.js +57 -0
  61. data/app/assets/javascripts/fe/qe.public.js +331 -0
  62. data/app/assets/javascripts/fe/swfobject.js +4 -0
  63. data/app/assets/stylesheets/fe/qe.screen.css.scss.erb +552 -0
  64. data/app/assets/stylesheets/fe/reset.css +55 -0
  65. data/app/assets/stylesheets/fe/validation.css +91 -0
  66. data/app/controllers/fe/admin/elements_controller.rb +185 -0
  67. data/app/controllers/fe/admin/email_templates_controller.rb +61 -0
  68. data/app/controllers/fe/admin/question_pages_controller.rb +113 -0
  69. data/app/controllers/fe/admin/question_sheets_controller.rb +106 -0
  70. data/app/controllers/fe/answer_pages_controller.rb +3 -0
  71. data/app/controllers/fe/answer_sheets_controller.rb +3 -0
  72. data/app/controllers/fe/concerns/answer_pages_controller_concern.rb +80 -0
  73. data/app/controllers/fe/concerns/answer_sheets_controller_concern.rb +84 -0
  74. data/app/controllers/fe/reference_sheets_controller.rb +29 -0
  75. data/app/helpers/fe/answer_pages_helper.rb +19 -0
  76. data/app/helpers/fe/application_helper.rb +49 -0
  77. data/app/mailers/fe/notifier.rb +22 -0
  78. data/app/models/fe/answer.rb +13 -0
  79. data/app/models/fe/answer_pages_presenter.rb +13 -0
  80. data/app/models/fe/answer_sheet.rb +10 -0
  81. data/app/models/fe/answer_sheet_question_sheet.rb +7 -0
  82. data/app/models/fe/attachment_field.rb +7 -0
  83. data/app/models/fe/choice_field.rb +7 -0
  84. data/app/models/fe/concerns/answer_concern.rb +36 -0
  85. data/app/models/fe/concerns/answer_pages_presenter_concern.rb +99 -0
  86. data/app/models/fe/concerns/answer_sheet_concern.rb +61 -0
  87. data/app/models/fe/concerns/choice_field_concern.rb +131 -0
  88. data/app/models/fe/condition.rb +53 -0
  89. data/app/models/fe/date_field.rb +52 -0
  90. data/app/models/fe/element.rb +164 -0
  91. data/app/models/fe/email_template.rb +7 -0
  92. data/app/models/fe/option.rb +10 -0
  93. data/app/models/fe/option_group.rb +10 -0
  94. data/app/models/fe/page.rb +101 -0
  95. data/app/models/fe/page_element.rb +9 -0
  96. data/app/models/fe/page_link.rb +15 -0
  97. data/app/models/fe/paragraph.rb +10 -0
  98. data/app/models/fe/payment.rb +52 -0
  99. data/app/models/fe/payment_question.rb +22 -0
  100. data/app/models/fe/presenter.rb +23 -0
  101. data/app/models/fe/question.rb +256 -0
  102. data/app/models/fe/question_grid.rb +26 -0
  103. data/app/models/fe/question_grid_with_total.rb +11 -0
  104. data/app/models/fe/question_set.rb +82 -0
  105. data/app/models/fe/question_sheet.rb +73 -0
  106. data/app/models/fe/reference_question.rb +42 -0
  107. data/app/models/fe/reference_sheet.rb +149 -0
  108. data/app/models/fe/section.rb +12 -0
  109. data/app/models/fe/state_chooser.rb +10 -0
  110. data/app/models/fe/text_field.rb +29 -0
  111. data/app/views/fe/admin/elements/_errors.html.erb +1 -0
  112. data/app/views/fe/admin/elements/create.js.erb +11 -0
  113. data/app/views/fe/admin/elements/destroy.js.erb +4 -0
  114. data/app/views/fe/admin/elements/drop.js.erb +2 -0
  115. data/app/views/fe/admin/elements/duplicate.js.erb +2 -0
  116. data/app/views/fe/admin/elements/edit.js.erb +4 -0
  117. data/app/views/fe/admin/elements/error.js.erb +4 -0
  118. data/app/views/fe/admin/elements/new.js.erb +10 -0
  119. data/app/views/fe/admin/elements/reorder.js.erb +0 -0
  120. data/app/views/fe/admin/elements/update.js.erb +9 -0
  121. data/app/views/fe/admin/email_templates/_form.html.erb +8 -0
  122. data/app/views/fe/admin/email_templates/edit.html.erb +13 -0
  123. data/app/views/fe/admin/email_templates/index.html.erb +20 -0
  124. data/app/views/fe/admin/email_templates/new.html.erb +11 -0
  125. data/app/views/fe/admin/panels/_advanced_options.html.erb +16 -0
  126. data/app/views/fe/admin/panels/_common_fields.html.erb +24 -0
  127. data/app/views/fe/admin/panels/_condition.html.erb +6 -0
  128. data/app/views/fe/admin/panels/_insert.html.erb +39 -0
  129. data/app/views/fe/admin/panels/_nav_controls.html.erb +6 -0
  130. data/app/views/fe/admin/panels/_page.html.erb +3 -0
  131. data/app/views/fe/admin/panels/_pages_list.html.erb +16 -0
  132. data/app/views/fe/admin/panels/_prop_attachment_field.html.erb +2 -0
  133. data/app/views/fe/admin/panels/_prop_choice_field.html.erb +46 -0
  134. data/app/views/fe/admin/panels/_prop_date_field.html.erb +7 -0
  135. data/app/views/fe/admin/panels/_prop_element.html.erb +30 -0
  136. data/app/views/fe/admin/panels/_prop_page.html.erb +21 -0
  137. data/app/views/fe/admin/panels/_prop_paragraph.html.erb +32 -0
  138. data/app/views/fe/admin/panels/_prop_question_grid.html.erb +23 -0
  139. data/app/views/fe/admin/panels/_prop_question_grid_with_total.html.erb +14 -0
  140. data/app/views/fe/admin/panels/_prop_reference_question.html.erb +12 -0
  141. data/app/views/fe/admin/panels/_prop_section.html.erb +2 -0
  142. data/app/views/fe/admin/panels/_prop_sheet.html.erb +17 -0
  143. data/app/views/fe/admin/panels/_prop_text_field.html.erb +20 -0
  144. data/app/views/fe/admin/question_pages/_element.html.erb +18 -0
  145. data/app/views/fe/admin/question_pages/_element_show.html.erb +10 -0
  146. data/app/views/fe/admin/question_pages/_errors.html.erb +1 -0
  147. data/app/views/fe/admin/question_pages/_question_page.html.erb +13 -0
  148. data/app/views/fe/admin/question_pages/create.js.erb +11 -0
  149. data/app/views/fe/admin/question_pages/destroy.js.erb +5 -0
  150. data/app/views/fe/admin/question_pages/edit.js.erb +3 -0
  151. data/app/views/fe/admin/question_pages/error.js.erb +4 -0
  152. data/app/views/fe/admin/question_pages/show.js.erb +8 -0
  153. data/app/views/fe/admin/question_pages/show_panel.js.erb +3 -0
  154. data/app/views/fe/admin/question_pages/update.js.erb +2 -0
  155. data/app/views/fe/admin/question_sheets/_errors.html.erb +1 -0
  156. data/app/views/fe/admin/question_sheets/edit.js.erb +3 -0
  157. data/app/views/fe/admin/question_sheets/error.js.erb +5 -0
  158. data/app/views/fe/admin/question_sheets/index.html.erb +41 -0
  159. data/app/views/fe/admin/question_sheets/new.html.erb +15 -0
  160. data/app/views/fe/admin/question_sheets/show.html.erb +27 -0
  161. data/app/views/fe/admin/question_sheets/update.js.erb +2 -0
  162. data/app/views/fe/answer_pages/_answer_page.html.erb +56 -0
  163. data/app/views/fe/answer_pages/_element.html.erb +9 -0
  164. data/app/views/fe/answer_pages/update.js.erb +5 -0
  165. data/app/views/fe/answer_sheets/_answer_sheet.html.erb +24 -0
  166. data/app/views/fe/answer_sheets/_element.html.erb +54 -0
  167. data/app/views/fe/answer_sheets/_incomplete.html.erb +10 -0
  168. data/app/views/fe/answer_sheets/_page_link.html.erb +7 -0
  169. data/app/views/fe/answer_sheets/_pages_list.html.erb +11 -0
  170. data/app/views/fe/answer_sheets/_title.html.erb +1 -0
  171. data/app/views/fe/answer_sheets/edit.html.erb +60 -0
  172. data/app/views/fe/answer_sheets/incomplete.js.erb +5 -0
  173. data/app/views/fe/answer_sheets/index.html.erb +18 -0
  174. data/app/views/fe/answer_sheets/send_reference_invite.js.erb +8 -0
  175. data/app/views/fe/answer_sheets/show.html.erb +13 -0
  176. data/app/views/fe/help/builder.html +33 -0
  177. data/app/views/fe/help/question_grid.html +18 -0
  178. data/app/views/fe/questions/_acceptance.html.erb +13 -0
  179. data/app/views/fe/questions/_attachment_field.html.erb +42 -0
  180. data/app/views/fe/questions/_checkbox_field.html.erb +49 -0
  181. data/app/views/fe/questions/_country.html.erb +7 -0
  182. data/app/views/fe/questions/_date_field.html.erb +7 -0
  183. data/app/views/fe/questions/_date_field_mmyy.html.erb +9 -0
  184. data/app/views/fe/questions/_drop_down_field.html.erb +7 -0
  185. data/app/views/fe/questions/_paragraph.html.erb +1 -0
  186. data/app/views/fe/questions/_question_grid.html.erb +65 -0
  187. data/app/views/fe/questions/_question_grid_with_total.html.erb +57 -0
  188. data/app/views/fe/questions/_questions.html.erb +9 -0
  189. data/app/views/fe/questions/_radio_button_field.html.erb +41 -0
  190. data/app/views/fe/questions/_rating.html.erb +25 -0
  191. data/app/views/fe/questions/_reference_discipler.html.erb +1 -0
  192. data/app/views/fe/questions/_reference_friend.html.erb +1 -0
  193. data/app/views/fe/questions/_reference_parent.html.erb +1 -0
  194. data/app/views/fe/questions/_reference_peer.html.erb +1 -0
  195. data/app/views/fe/questions/_reference_question.html.erb +38 -0
  196. data/app/views/fe/questions/_reference_roommate.html.erb +1 -0
  197. data/app/views/fe/questions/_reference_spiritual.html.erb +1 -0
  198. data/app/views/fe/questions/_reference_staff.html.erb +1 -0
  199. data/app/views/fe/questions/_section.html.erb +1 -0
  200. data/app/views/fe/questions/_state_chooser.html.erb +7 -0
  201. data/app/views/fe/questions/_text_area_field.html.erb +6 -0
  202. data/app/views/fe/questions/_text_field.html.erb +8 -0
  203. data/app/views/fe/questions/_yes_no.html.erb +17 -0
  204. data/app/views/fe/questions/_yes_no_field.erb +17 -0
  205. data/app/views/fe/reference_sheets/not_found.html.erb +5 -0
  206. data/app/views/layouts/fe/application.html.erb +31 -0
  207. data/app/views/layouts/fe/qe.admin.html.erb +30 -0
  208. data/config/routes.rb +49 -0
  209. data/db/migrate/20131003041856_core.rb +91 -0
  210. data/db/migrate/20131003044250_create_reference_sheets.rb +23 -0
  211. data/db/migrate/20131003044436_add_element_and_answer_fields.rb +10 -0
  212. data/db/migrate/20131003044518_create_email_templates.rb +17 -0
  213. data/db/migrate/20131003044621_add_max_lengths.rb +8 -0
  214. data/db/migrate/20131003044714_create_join_table.rb +11 -0
  215. data/db/migrate/20131016162128_remove_question_id_from_element.rb +9 -0
  216. data/lib/fe.rb +22 -0
  217. data/lib/fe/engine.rb +19 -0
  218. data/lib/fe/version.rb +3 -0
  219. data/lib/generators/fe/install_generator.rb +132 -0
  220. data/lib/tasks/qe_tasks.rake +4 -0
  221. data/spec/controllers/fe/admin/elements_controller_spec.rb +4 -0
  222. data/spec/controllers/fe/admin/email_templates_controller_spec.rb +4 -0
  223. data/spec/controllers/fe/admin/question_pages_controller_spec.rb +4 -0
  224. data/spec/controllers/fe/admin/question_sheets_controller_spec.rb +4 -0
  225. data/spec/controllers/fe/answer_pages_controller_spec.rb +4 -0
  226. data/spec/controllers/fe/answer_sheets_controller_spec.rb +4 -0
  227. data/spec/controllers/fe/reference_sheets_controller_spec.rb +4 -0
  228. data/spec/factories/answer_sheets.rb +5 -0
  229. data/spec/factories/answers.rb +4 -0
  230. data/spec/factories/paragraphs.rb +4 -0
  231. data/spec/factories/question_sheet.rb +5 -0
  232. data/spec/factories/reference_questions.rb +4 -0
  233. data/spec/models/fe/answer_sheet_question_sheet_spec.rb +6 -0
  234. data/spec/models/fe/answer_sheet_spec.rb +8 -0
  235. data/spec/models/fe/answer_spec.rb +13 -0
  236. data/spec/models/fe/attachment_field_spec.rb +4 -0
  237. data/spec/models/fe/choice_field_spec.rb +5 -0
  238. data/spec/models/fe/condition_spec.rb +8 -0
  239. data/spec/models/fe/date_field_spec.rb +49 -0
  240. data/spec/models/fe/element_spec.rb +12 -0
  241. data/spec/models/fe/email_template_spec.rb +5 -0
  242. data/spec/models/fe/option_group_spec.rb +4 -0
  243. data/spec/models/fe/option_spec.rb +4 -0
  244. data/spec/models/fe/page_element_spec.rb +6 -0
  245. data/spec/models/fe/page_link_spec.rb +4 -0
  246. data/spec/models/fe/page_spec.rb +14 -0
  247. data/spec/models/fe/paragraph_spec.rb +17 -0
  248. data/spec/models/fe/question_grid_spec.rb +4 -0
  249. data/spec/models/fe/question_grid_with_total_spec.rb +4 -0
  250. data/spec/models/fe/question_set_spec.rb +4 -0
  251. data/spec/models/fe/question_sheet_spec.rb +8 -0
  252. data/spec/models/fe/question_spec.rb +20 -0
  253. data/spec/models/fe/reference_question_spec.rb +17 -0
  254. data/spec/models/fe/reference_sheet_spec.rb +11 -0
  255. data/spec/models/fe/section_spec.rb +4 -0
  256. data/spec/models/fe/state_chooser_spec.rb +4 -0
  257. data/spec/models/fe/text_field_spec.rb +17 -0
  258. data/spec/spec_helper.rb +66 -0
  259. data/spec/support/database.txt +28 -0
  260. metadata +508 -0
@@ -0,0 +1,26 @@
1
+ # QuestionGrid
2
+ # - Represents a grid layout of a set of questions
3
+ #
4
+ # :kind - 'QuestionGrid' for single table inheritance (STI)
5
+ # :content - questions
6
+
7
+ module Fe
8
+ class QuestionGrid < Element
9
+
10
+ has_many :elements, -> { order('position') },
11
+ :class_name => "Element",
12
+ :foreign_key => "question_grid_id",
13
+ :dependent => :nullify
14
+
15
+ def num_cols
16
+ num = cols.to_s.split(';').length
17
+ num = 1 if num == 0
18
+ num
19
+ end
20
+
21
+ def has_response?(answer_sheet = nil)
22
+ elements.any? {|e| e.has_response?(answer_sheet)}
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ # QuestionGrid
2
+ # - Represents a grid layout of a set of questions, with a total at the bottom
3
+ #
4
+ # :kind - 'QuestionGridWithTotal' for single table inheritance (STI)
5
+ # :content - questions
6
+ # :total_cols - Which column(s) of the grid should be used for totals
7
+
8
+ module Fe
9
+ class QuestionGridWithTotal < QuestionGrid
10
+ end
11
+ end
@@ -0,0 +1,82 @@
1
+ # QuestionSet
2
+ # represents a group of elements, with their answers
3
+ module Fe
4
+ class QuestionSet
5
+
6
+ attr_reader :elements
7
+
8
+ # associate answers from database with a set of elements
9
+ def initialize(elements, answer_sheet)
10
+ @elements = elements
11
+ @answer_sheet = answer_sheet
12
+
13
+ @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
+ end
22
+
23
+ # update with responses from form
24
+ def post(params, answer_sheet)
25
+ questions_indexed = @questions.index_by {|q| q.id}
26
+
27
+ # loop over form values
28
+ params ||= {}
29
+ params.each do |question_id, response|
30
+ next if questions_indexed[question_id.to_i].nil? # the rare case where a question was removed after the app was opened.
31
+ # update each question with the posted response
32
+ questions_indexed[question_id.to_i].set_response(posted_values(response), answer_sheet)
33
+ end
34
+ end
35
+ #
36
+ # def valid?
37
+ # valid = true
38
+ # @questions.each do |question|
39
+ # valid = false unless question.valid_response? # run through ALL questions
40
+ # end
41
+ # valid
42
+ # end
43
+
44
+ def any_questions?
45
+ @questions.length > 0
46
+ end
47
+
48
+ def save
49
+ AnswerSheet.transaction do
50
+ @questions.each do |question|
51
+ question.save_response(@answer_sheet)
52
+ end
53
+ end
54
+ end
55
+
56
+
57
+ private
58
+
59
+ # convert posted response to a question into Array of values
60
+ def posted_values(param)
61
+
62
+ if param.kind_of?(Hash) and param.has_key?('year') and param.has_key?('month')
63
+ year = param['year']
64
+ month = param['month']
65
+ if month.blank? or year.blank?
66
+ values = ''
67
+ else
68
+ values = [Date.new(year.to_i, month.to_i, 1).strftime('%m/%d/%Y')] # for mm/yy drop downs
69
+ end
70
+ elsif param.kind_of?(Hash)
71
+ # from Hash with multiple answers per question
72
+ values = param.values.map {|v| CGI.unescape(v)}
73
+ elsif param.kind_of?(String)
74
+ values = [CGI.unescape(param)]
75
+ end
76
+
77
+ # Hash may contain empty string to force post for no checkboxes
78
+ # values = values.reject {|r| r == ''}
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,73 @@
1
+ # QuestionSheet represents a particular form
2
+ module Fe
3
+ class QuestionSheet < ActiveRecord::Base
4
+ self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
5
+
6
+ has_many :pages, -> { order('number') },
7
+ :dependent => :destroy
8
+
9
+ # has_many :elements
10
+ # has_many :questions
11
+
12
+ has_many :answer_sheet_question_sheets
13
+
14
+ has_many :answer_sheets,
15
+ :through => :answer_sheet_question_sheets
16
+
17
+ scope :active, -> { where(:archived => false) }
18
+ scope :archived, -> { where(:archived => true) }
19
+
20
+ validates_presence_of :label
21
+ # validates_length_of :label, :maximum => 60, :allow_nil => true
22
+ validates_uniqueness_of :label
23
+
24
+ before_destroy :check_for_answers
25
+
26
+ # create a new form with a page already attached
27
+ 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
31
+ end
32
+
33
+ def questions
34
+ pages.collect(&:questions).flatten
35
+ end
36
+
37
+ def elements
38
+ pages.collect(&:elements).flatten
39
+ end
40
+
41
+ # Pages get duplicated
42
+ # Question elements get associated
43
+ # non-question elements get cloned
44
+ def duplicate
45
+ new_sheet = QuestionSheet.new(self.attributes)
46
+ new_sheet.label = self.label + ' - COPY'
47
+ new_sheet.save(:validate => false)
48
+ self.pages.each do |page|
49
+ page.copy_to(new_sheet)
50
+ end
51
+ new_sheet
52
+ end
53
+
54
+
55
+ private
56
+
57
+ # next unused label with "Untitled form" prefix
58
+ def self.next_label
59
+ Fe.next_label("Untitled form", untitled_labels)
60
+ end
61
+
62
+ # returns a list of existing Untitled forms
63
+ # (having a separate method makes it easy to mock in the spec)
64
+ def self.untitled_labels
65
+ QuestionSheet.find(:all, :conditions => %{label like 'Untitled form%'}).map {|s| s.label}
66
+ end
67
+
68
+ def check_for_answers
69
+
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,42 @@
1
+ # ReferenceQuestion
2
+ # - a question that provides a fields to specify a reference
3
+ module Fe
4
+ class ReferenceQuestion < Question
5
+
6
+ def response(app=nil)
7
+ return unless app
8
+ # A reference is the same if the related_question_sheet corresponding to the question is the same
9
+ 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)
21
+ end
22
+
23
+ def has_response?(app = nil)
24
+ if app
25
+ reference = response(app)
26
+ reference && reference.valid?
27
+ else
28
+ Fe::ReferenceSheet.where(:question_id => id).count > 0
29
+ end
30
+ end
31
+
32
+ def display_response(app=nil)
33
+ response(app).to_s
34
+ end
35
+
36
+ # which view to render this element?
37
+ def ptemplate
38
+ "reference_#{style}"
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,149 @@
1
+ require 'aasm'
2
+ module Fe
3
+ class ReferenceSheet < ActiveRecord::Base
4
+ include Fe::AnswerSheetConcern
5
+ include Rails.application.routes.url_helpers
6
+ include AASM
7
+ self.table_name = "#{Fe.table_name_prefix}references"
8
+ self.inheritance_column = 'fake'
9
+
10
+ belongs_to :question,
11
+ :class_name => 'Element',
12
+ :foreign_key => 'question_id'
13
+
14
+ belongs_to :applicant_answer_sheet,
15
+ :class_name => Fe.answer_sheet_class,
16
+ :foreign_key => "applicant_answer_sheet_id"
17
+
18
+ validates_presence_of :first_name, :last_name, :phone, :email, :relationship, :on => :update, :message => "can't be blank"
19
+
20
+ delegate :style, :to => :question
21
+
22
+ before_save :check_email_change
23
+
24
+ after_destroy :notify_reference_of_deletion
25
+
26
+ aasm :initial => :created, :column => :status do
27
+
28
+ state :started, :enter => Proc.new {|ref|
29
+ ref.started_at = Time.now
30
+ }
31
+ state :created
32
+ state :completed, :enter => Proc.new {|ref|
33
+ ref.submitted_at = Time.now
34
+ # SpReferenceMailer.deliver_completed(ref)
35
+ # SpReferenceMailer.deliver_completed_confirmation(ref)
36
+ ref.applicant_answer_sheet.complete(ref)
37
+ }
38
+
39
+ event :start do
40
+ transitions :to => :started, :from => :created
41
+ end
42
+
43
+ event :submit do
44
+ transitions :to => :completed, :from => :started
45
+ transitions :to => :completed, :from => :created
46
+ end
47
+
48
+ event :unsubmit do
49
+ transitions :to => :started, :from => :completed
50
+ end
51
+ end
52
+
53
+ alias_method :applicant, :applicant_answer_sheet
54
+ def generate_access_key
55
+ self.access_key = Digest::MD5.hexdigest(email + Time.now.to_s)
56
+ end
57
+
58
+ def frozen?
59
+ !%w(started created).include?(self.status)
60
+ end
61
+
62
+ def email_sent?() !self.email_sent_at.nil? end
63
+
64
+ # send email invite
65
+ def send_invite
66
+ return if self.email.blank?
67
+
68
+ application = self.applicant_answer_sheet
69
+
70
+ Notifier.notification(self.email,
71
+ application.email,
72
+ "Reference Invite",
73
+ {'reference_full_name' => self.name,
74
+ 'applicant_full_name' => application.name,
75
+ 'applicant_email' => application.email,
76
+ 'applicant_home_phone' => application.phone,
77
+ 'reference_url' => edit_reference_sheet_url(self, :a => self.access_key, :host => ActionMailer::Base.default_url_options[:host])}).deliver
78
+ # Send notification to applicant
79
+ Notifier.notification(applicant_answer_sheet.email, # RECIPIENTS
80
+ Fe.from_email, # FROM
81
+ "Reference Notification to Applicant", # LIQUID TEMPLATE NAME
82
+ {'applicant_full_name' => applicant_answer_sheet.name,
83
+ 'reference_full_name' => self.name,
84
+ 'reference_email' => self.email,
85
+ 'application_url' => edit_answer_sheet_url(applicant_answer_sheet, :host => ActionMailer::Base.default_url_options[:host])}).deliver
86
+
87
+ self.email_sent_at = Time.now
88
+ self.save(:validate => false)
89
+
90
+ true
91
+ end
92
+
93
+ def name
94
+ [first_name, last_name].join(' ')
95
+ end
96
+
97
+ def reference
98
+ self
99
+ end
100
+
101
+ def to_s
102
+ name
103
+ end
104
+
105
+ def required?
106
+ question.required?(applicant_answer_sheet)
107
+ end
108
+
109
+ def reference?
110
+ true
111
+ end
112
+
113
+ # Can't rely on answer_sheet's implementation for old reference's that might have id's that may match an application id
114
+ def question_sheet
115
+ QuestionSheet.find(question.related_question_sheet_id) if question && question.related_question_sheet_id
116
+ end
117
+
118
+ # Can't rely on answer_sheet's implementation for old reference's that might have id's that may match an application id
119
+ def question_sheets
120
+ [question_sheet]
121
+ end
122
+
123
+ def display_type
124
+ question.label.split(/:| \(/).first
125
+ end
126
+
127
+ protected
128
+ # if the email address has changed, we have to trash the old reference answers
129
+ def check_email_change
130
+ if changed.include?('email')
131
+ answers.destroy_all
132
+ # Every time the email address changes, generate a new access_key
133
+ generate_access_key
134
+ self.email_sent_at = nil
135
+ self.status = 'created'
136
+ end
137
+ end
138
+
139
+ def notify_reference_of_deletion
140
+ if email.present?
141
+ Notifier.notification(email,
142
+ Fe.from_email,
143
+ "Reference Deleted",
144
+ {'reference_full_name' => self.name,
145
+ 'applicant_full_name' => applicant_answer_sheet.name}).deliver
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,12 @@
1
+ # Section
2
+ # - Represents a subheading
3
+
4
+ # :kind - 'Section' for single table inheritance (STI)
5
+ # :label - title for this section such as "Contact information"
6
+ # :style - ?
7
+ # :content - ? instructions, agreements, etc. to display
8
+
9
+ module Fe
10
+ class Section < Element
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ require 'carmen'
2
+ # State Dropdown
3
+ # - drop down of states
4
+ module Fe
5
+ class StateChooser < Question
6
+ def choices(country = 'US')
7
+ @states = Carmen.states(country)
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,29 @@
1
+ # TextField
2
+ # - a question that prompts for one or more lines of text
3
+
4
+ module Fe
5
+ class TextField < Question
6
+
7
+ # which view to render this element?
8
+ def ptemplate
9
+ if self.style == 'essay'
10
+ 'text_area_field'
11
+ else
12
+ 'text_field'
13
+ end
14
+ end
15
+
16
+ # css class names for javascript-based validation
17
+ def validation_class(answer_sheet)
18
+ validation = ''
19
+ validation += ' required' if self.required?(answer_sheet)
20
+ # validate-number, etc.
21
+ validate_style = ['number', 'currency-dollar', 'email', 'url', 'phone'].find {|v| v == self.style }
22
+ if validate_style
23
+ validation += ' validate-' + validate_style
24
+ end
25
+ validation
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1 @@
1
+ <%= error_messages_for :element %>