fe 0.0.4 → 1.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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +16 -36
  3. data/app/assets/javascripts/fe/admin.js +0 -1
  4. data/app/assets/javascripts/fe/fe.admin.js +40 -16
  5. data/app/assets/javascripts/fe/fe.common.js +48 -14
  6. data/app/assets/javascripts/fe/fe.public.js +1 -414
  7. data/app/assets/javascripts/fe/fe.public.nojquery.js +450 -0
  8. data/app/assets/javascripts/fe/jquery.validate.pack.js +3 -15
  9. data/app/assets/stylesheets/360front.css +0 -0
  10. data/app/assets/stylesheets/fe/fe.screen.css.scss.erb +69 -10
  11. data/app/controllers/fe/admin/elements_controller.rb +64 -48
  12. data/app/controllers/fe/admin/email_templates_controller.rb +2 -2
  13. data/app/controllers/fe/admin/question_pages_controller.rb +1 -1
  14. data/app/controllers/fe/admin/question_sheets_controller.rb +2 -103
  15. data/app/controllers/fe/concerns/admin/question_sheets_controller_concern.rb +112 -0
  16. data/app/controllers/fe/concerns/answer_pages_controller_concern.rb +2 -1
  17. data/app/controllers/fe/concerns/answer_sheets_controller_concern.rb +1 -1
  18. data/app/controllers/fe/concerns/application_controller_concern.rb +13 -0
  19. data/app/controllers/fe/reference_sheets_controller.rb +2 -0
  20. data/app/controllers/fe/references_controller.rb +1 -0
  21. data/app/helpers/fe/application_helper.rb +5 -0
  22. data/app/mailers/fe/notifier.rb +11 -4
  23. data/app/models/answer_sheet.rb +2 -0
  24. data/app/models/fe/application.rb +2 -1
  25. data/app/models/fe/concerns/answer_pages_presenter_concern.rb +10 -1
  26. data/app/models/fe/concerns/answer_sheet_concern.rb +38 -8
  27. data/app/models/fe/concerns/choice_field_concern.rb +17 -10
  28. data/app/models/fe/date_field.rb +1 -1
  29. data/app/models/fe/element.rb +105 -31
  30. data/app/models/fe/page.rb +52 -20
  31. data/app/models/fe/page_element.rb +6 -1
  32. data/app/models/fe/page_link.rb +6 -3
  33. data/app/models/fe/person.rb +11 -8
  34. data/app/models/fe/question.rb +2 -6
  35. data/app/models/fe/question_grid.rb +1 -1
  36. data/app/models/fe/question_grid_with_total.rb +15 -0
  37. data/app/models/fe/question_set.rb +1 -1
  38. data/app/models/fe/question_sheet.rb +15 -13
  39. data/app/models/fe/reference_question.rb +0 -10
  40. data/app/models/fe/reference_sheet.rb +17 -13
  41. data/app/models/staff.rb +2 -0
  42. data/app/validators/email_validator.rb +11 -0
  43. data/app/views/fe/admin/elements/create.js.erb +1 -0
  44. data/app/views/fe/admin/elements/drop.js.erb +1 -0
  45. data/app/views/fe/admin/elements/duplicate.js.erb +1 -0
  46. data/app/views/fe/admin/panels/_advanced_options.html.erb +9 -3
  47. data/app/views/fe/admin/panels/_common_fields.html.erb +19 -5
  48. data/app/views/fe/admin/panels/_page.html.erb +1 -1
  49. data/app/views/fe/admin/panels/_prop_choice_field.html.erb +20 -11
  50. data/app/views/fe/admin/panels/_prop_element.html.erb +2 -9
  51. data/app/views/fe/admin/panels/_prop_page.html.erb +8 -3
  52. data/app/views/fe/admin/panels/_prop_paragraph.html.erb +38 -24
  53. data/app/views/fe/admin/panels/_prop_section.html.erb +8 -2
  54. data/app/views/fe/admin/panels/_prop_sheet.html.erb +4 -1
  55. data/app/views/fe/admin/question_pages/_element.html.erb +11 -1
  56. data/app/views/fe/answer_pages/_answer_page.html.erb +9 -8
  57. data/app/views/fe/answer_pages/_element.html.erb +6 -7
  58. data/app/views/fe/answer_pages/_page_name.html.erb +1 -0
  59. data/app/views/fe/answer_pages/update.js.erb +3 -3
  60. data/app/views/fe/answer_sheets/_answer_sheet.html.erb +3 -3
  61. data/app/views/fe/answer_sheets/_element.html.erb +52 -34
  62. data/app/views/fe/answer_sheets/_incomplete.html.erb +1 -1
  63. data/app/views/fe/answer_sheets/_page_link.html.erb +2 -2
  64. data/app/views/fe/answer_sheets/_pages_list.html.erb +3 -3
  65. data/app/views/fe/answer_sheets/_submit_to.html.erb +1 -0
  66. data/app/views/fe/answer_sheets/edit.html.erb +14 -14
  67. data/app/views/fe/answer_sheets/incomplete.js.erb +3 -0
  68. data/app/views/fe/answer_sheets/index.html.erb +3 -3
  69. data/app/views/fe/answer_sheets/show.html.erb +1 -1
  70. data/app/views/fe/applications/_logout.html.erb +1 -0
  71. data/app/views/fe/applications/show.html.erb +1 -0
  72. data/app/views/fe/questions/fe/_acceptance.html.erb +3 -3
  73. data/app/views/fe/questions/fe/_attachment_field.html.erb +7 -3
  74. data/app/views/fe/questions/fe/_checkbox_field.html.erb +26 -24
  75. data/app/views/fe/questions/fe/_date_field.html.erb +1 -2
  76. data/app/views/fe/questions/fe/_date_field_mmyy.html.erb +2 -2
  77. data/app/views/fe/questions/fe/_drop_down_field.html.erb +3 -2
  78. data/app/views/fe/questions/fe/_paragraph.html.erb +1 -1
  79. data/app/views/fe/questions/fe/_question_grid.html.erb +14 -9
  80. data/app/views/fe/questions/fe/_question_grid_with_total.html.erb +21 -14
  81. data/app/views/fe/questions/fe/_questions.html.erb +2 -2
  82. data/app/views/fe/questions/fe/_radio_button_field.html.erb +12 -11
  83. data/app/views/fe/questions/fe/_rating.html.erb +9 -8
  84. data/app/views/fe/questions/fe/_reference_discipler.html.erb +1 -1
  85. data/app/views/fe/questions/fe/_reference_friend.html.erb +1 -1
  86. data/app/views/fe/questions/fe/_reference_parent.html.erb +1 -1
  87. data/app/views/fe/questions/fe/_reference_peer.html.erb +1 -1
  88. data/app/views/fe/questions/fe/_reference_question.html.erb +22 -15
  89. data/app/views/fe/questions/fe/_reference_roommate.html.erb +1 -1
  90. data/app/views/fe/questions/fe/_reference_spiritual.html.erb +1 -1
  91. data/app/views/fe/questions/fe/_reference_staff.html.erb +1 -1
  92. data/app/views/fe/questions/fe/_section.html.erb +1 -1
  93. data/app/views/fe/questions/fe/_text_area_field.html.erb +10 -3
  94. data/app/views/fe/questions/fe/_text_field.html.erb +1 -1
  95. data/app/views/fe/questions/fe/_yes_no_field.erb +3 -3
  96. data/app/views/fe/reference_pages/_reference.html.erb +11 -11
  97. data/app/views/fe/reference_pages/edit.html.erb +7 -7
  98. data/app/views/fe/reference_sheets/done.html.erb +2 -2
  99. data/app/views/fe/reference_sheets/not_found.html.erb +4 -4
  100. data/app/views/fe/references/edit.html.erb +6 -6
  101. data/app/views/fe/references/show.html.erb +7 -7
  102. data/app/views/fe/references/submit.js.erb +1 -1
  103. data/app/views/fe/submit_pages/_thankyou.html.erb +1 -1
  104. data/app/views/fe/submit_pages/edit.html.erb +9 -9
  105. data/app/views/layouts/fe/_error_messages_for.html.erb +7 -0
  106. data/app/views/layouts/fe/application.html.erb +1 -1
  107. data/config/routes.rb +0 -36
  108. data/db/migrate/20131003044250_create_reference_sheets.rb +1 -0
  109. data/db/migrate/20140623153424_create_fe_people.rb +1 -1
  110. data/db/migrate/20140624180246_create_fe_addresses.rb +1 -1
  111. data/db/migrate/20140624182216_create_fe_phone_numbers.rb +16 -0
  112. data/db/migrate/20140625160545_create_fe_users.rb +1 -1
  113. data/db/migrate/20150504221439_add_all_element_ids_to_pages.rb +5 -0
  114. data/db/migrate/20150713022326_add_locale_columns.rb +9 -0
  115. data/db/migrate/20150714220730_add_locale_to_answer_sheet.rb +5 -0
  116. data/db/migrate/20150928085325_change_pages_all_element_ids_to_text.rb +5 -0
  117. data/db/migrate/20150930191538_add_locale_to_reference_sheets.rb +5 -0
  118. data/lib/access_key_generator.rb +12 -0
  119. data/lib/distinct_distinct_patch.rb +20 -0
  120. data/lib/fe.rb +4 -0
  121. data/lib/fe/engine.rb +16 -4
  122. data/lib/fe/version.rb +1 -1
  123. data/spec/controllers/fe/admin/elements_controller_spec.rb +201 -1
  124. data/spec/controllers/fe/admin/email_templates_controller_spec.rb +26 -1
  125. data/spec/controllers/fe/admin/question_pages_controller_spec.rb +8 -1
  126. data/spec/controllers/fe/admin/question_sheets_controller_spec.rb +48 -1
  127. data/spec/controllers/fe/answer_pages_controller_spec.rb +73 -1
  128. data/spec/controllers/fe/answer_sheets_controller_spec.rb +80 -1
  129. data/spec/controllers/fe/reference_pages_controller.rb +4 -0
  130. data/spec/controllers/fe/references_controller_spec.rb +4 -0
  131. data/spec/controllers/fe/submit_pages_controller_spec.rb +4 -0
  132. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  133. data/spec/dummy/app/helpers/application_helper.rb +9 -0
  134. data/spec/dummy/app/models/application.rb +3 -0
  135. data/spec/dummy/app/models/person.rb +11 -0
  136. data/spec/dummy/app/models/user.rb +3 -0
  137. data/spec/dummy/config/application.rb +2 -1
  138. data/spec/dummy/config/database.yml +20 -17
  139. data/spec/dummy/config/environments/production.rb +1 -5
  140. data/spec/dummy/config/environments/test.rb +3 -1
  141. data/spec/dummy/config/initializers/fast_gettext.rb +5 -0
  142. data/spec/dummy/config/secrets.yml +2 -2
  143. data/spec/dummy/db/migrate/20141203214017_core.fe_engine.rb +92 -0
  144. data/spec/dummy/db/migrate/20141203214018_create_reference_sheets.fe_engine.rb +25 -0
  145. data/spec/dummy/db/migrate/20141203214019_add_element_and_answer_fields.fe_engine.rb +11 -0
  146. data/spec/dummy/db/migrate/20141203214020_create_email_templates.fe_engine.rb +18 -0
  147. data/spec/dummy/db/migrate/20141203214021_add_max_lengths.fe_engine.rb +9 -0
  148. data/spec/dummy/db/migrate/20141203214022_create_join_table.fe_engine.rb +12 -0
  149. data/spec/dummy/db/migrate/20141203214023_remove_question_id_from_element.fe_engine.rb +10 -0
  150. data/spec/dummy/db/migrate/20141203214024_create_fe_people.fe_engine.rb +13 -0
  151. data/spec/dummy/db/migrate/20141203214025_create_fe_addresses.fe_engine.rb +21 -0
  152. data/{db/migrate/20140624182216_create_create_fe_phone_numbers.rb → spec/dummy/db/migrate/20141203214026_create_create_fe_phone_numbers.fe_engine.rb} +1 -0
  153. data/spec/dummy/db/migrate/20141203214027_create_fe_users.fe_engine.rb +13 -0
  154. data/spec/dummy/db/migrate/20141203214028_add_conditional_type_to_elements.fe_engine.rb +6 -0
  155. data/spec/dummy/db/migrate/20141203214029_add_conditional_answer_to_elements.fe_engine.rb +6 -0
  156. data/spec/dummy/db/migrate/20141203214030_remove_short_value_column.fe_engine.rb +6 -0
  157. data/spec/dummy/db/migrate/20141203214031_move_conditional_ids_used_for_choice_field_to_their_own_column.fe_engine.rb +8 -0
  158. data/spec/dummy/db/migrate/20150123215803_create_users.rb +9 -0
  159. data/spec/dummy/db/migrate/20150504222619_add_all_element_ids_to_pages.fe_engine.rb +6 -0
  160. data/spec/dummy/db/migrate/20150930190001_create_fe_phone_numbers.fe_engine.rb +20 -0
  161. data/spec/dummy/db/migrate/20150930190002_add_locale_columns.fe_engine.rb +10 -0
  162. data/spec/dummy/db/migrate/20150930190003_add_locale_to_answer_sheet.fe_engine.rb +6 -0
  163. data/spec/dummy/db/migrate/20150930190004_change_pages_all_element_ids_to_text.fe_engine.rb +6 -0
  164. data/spec/dummy/db/migrate/20150930191756_add_locale_to_reference_sheets.fe_engine.rb +6 -0
  165. data/spec/dummy/db/schema.rb +50 -20
  166. data/spec/dummy/log/development.log +5 -0
  167. data/spec/factories/applications.rb +0 -1
  168. data/spec/factories/dummy_applications.rb +6 -0
  169. data/spec/factories/dummy_people.rb +6 -0
  170. data/spec/factories/dummy_users.rb +6 -0
  171. data/spec/factories/elements.rb +28 -3
  172. data/spec/factories/email_templates.rb +5 -0
  173. data/spec/factories/fe_email_templates.rb +9 -0
  174. data/spec/factories/fe_people.rb +0 -2
  175. data/spec/factories/fe_user.rb +6 -0
  176. data/spec/factories/question_sheet.rb +1 -1
  177. data/spec/factories/reference_sheets.rb +9 -0
  178. data/spec/mailers/fe/notifier_spec.rb +39 -0
  179. data/spec/models/fe/choice_field_spec.rb +20 -0
  180. data/spec/models/fe/element_spec.rb +185 -0
  181. data/spec/models/fe/page_spec.rb +112 -0
  182. data/spec/models/fe/question_sheet_spec.rb +106 -0
  183. data/spec/models/fe/reference_sheet_spec.rb +20 -0
  184. data/spec/rails_helper.rb +41 -13
  185. data/spec/support/choices.xml +6 -0
  186. metadata +136 -48
  187. data/app/assets/javascripts/fe/rails.extra.js +0 -6
  188. data/app/controllers/fe/applications_controller.rb +0 -183
  189. data/app/controllers/fe/payments_controller.rb +0 -184
  190. data/app/models/fe/payment.rb +0 -77
  191. data/app/models/fe/payment_question.rb +0 -22
  192. data/app/views/fe/admin/panels/_prop_payment_question.html.erb +0 -1
  193. data/app/views/fe/application/_logout.html.erb +0 -1
  194. data/app/views/fe/payment_pages/_credit.html.erb +0 -47
  195. data/app/views/fe/payment_pages/_mail.html.erb +0 -27
  196. data/app/views/fe/payment_pages/_payment.html.erb +0 -6
  197. data/app/views/fe/payment_pages/_staff.html.erb +0 -25
  198. data/app/views/fe/payment_pages/_staff_results.html.erb +0 -17
  199. data/app/views/fe/payment_pages/edit.html.erb +0 -75
  200. data/app/views/fe/payment_pages/staff_search.js.erb +0 -2
  201. data/app/views/fe/payments/_credit.html.erb +0 -47
  202. data/app/views/fe/payments/_errors.html.erb +0 -1
  203. data/app/views/fe/payments/_payment.html.erb +0 -13
  204. data/app/views/fe/payments/_staff.html.erb +0 -21
  205. data/app/views/fe/payments/_staff_results.html.erb +0 -18
  206. data/app/views/fe/payments/approve.js.erb +0 -3
  207. data/app/views/fe/payments/create.js.erb +0 -19
  208. data/app/views/fe/payments/destroy.js.erb +0 -7
  209. data/app/views/fe/payments/edit.html.erb +0 -56
  210. data/app/views/fe/payments/error.js.erb +0 -3
  211. data/app/views/fe/payments/no_access.html.erb +0 -7
  212. data/app/views/fe/payments/staff_search.js.erb +0 -1
  213. data/app/views/fe/payments/update.html.erb +0 -24
  214. data/app/views/fe/questions/fe/_payment_question.html.erb +0 -70
  215. data/db/migrate/20140828045339_create_payments.rb +0 -13
  216. data/spec/dummy/db/test.sqlite3 +0 -0
  217. data/spec/factories/payments.rb +0 -7
  218. data/spec/models/fe/payment_question_spec.rb +0 -65
@@ -0,0 +1,112 @@
1
+ module Fe::Admin::QuestionSheetsControllerConcern
2
+ extend ActiveSupport::Concern
3
+
4
+ begin
5
+ included do
6
+ before_filter :check_valid_user
7
+ before_filter :get_question_sheet, :only => [:show, :archive, :unarchive, :destroy, :edit, :update, :duplicate]
8
+ layout 'fe/fe.admin'
9
+ end
10
+ rescue ActiveSupport::Concern::MultipleIncludedBlocks
11
+ end
12
+
13
+ # list of all questionnaires/forms to edit
14
+ # GET /question_sheets
15
+ def index
16
+ @active_question_sheets = Fe::QuestionSheet.active.order('label')
17
+ @archived_question_sheets = Fe::QuestionSheet.archived.order('label')
18
+
19
+ respond_to do |format|
20
+ format.html # index.rhtml
21
+ format.xml { render :xml => @question_sheets.to_xml }
22
+ end
23
+ end
24
+
25
+ def archive
26
+ @question_sheet.update_attribute(:archived, true)
27
+ redirect_to :back
28
+ end
29
+
30
+ def unarchive
31
+ @question_sheet.update_attribute(:archived, false)
32
+ redirect_to :back
33
+ end
34
+
35
+ def duplicate
36
+ @question_sheet.duplicate
37
+ redirect_to :back
38
+ end
39
+
40
+ # entry point: display form designer with page 1 and panels loaded
41
+ # GET /question_sheets/1
42
+ def show
43
+ @all_pages = @question_sheet.pages
44
+ @page = @all_pages[0]
45
+
46
+ respond_to do |format|
47
+ format.html # show.rhtml
48
+ format.xml { render :xml => @question_sheet.to_xml }
49
+ end
50
+ end
51
+
52
+ # create sheet with inital page, redirect to show
53
+ # POST /question_sheets
54
+ def create
55
+ @question_sheet = Fe::QuestionSheet.new_with_page
56
+
57
+ respond_to do |format|
58
+ if @question_sheet.save
59
+ format.html { redirect_to fe_admin_question_sheet_path(@question_sheet) }
60
+ format.xml { head :created, :location => admin_question_sheet_path(@question_sheet) }
61
+ else
62
+ format.html { render :action => "new" }
63
+ format.xml { render :xml => @question_sheet.errors.to_xml }
64
+ end
65
+ end
66
+ end
67
+
68
+
69
+ # display sheet properties panel
70
+ # GET /question_sheets/1/edit
71
+ def edit
72
+
73
+ respond_to do |format|
74
+ format.js
75
+ end
76
+ end
77
+
78
+ # save changes to properties panel (label, language)
79
+ # PUT /question_sheets/1
80
+ def update
81
+ params.require(:fe_question_sheet).permit!
82
+
83
+ respond_to do |format|
84
+ if @question_sheet.update_attributes(params[:fe_question_sheet])
85
+ format.html { redirect_to fe_admin_question_sheet_path(@question_sheet) }
86
+ format.js
87
+ format.xml { head :ok }
88
+ else
89
+ format.html { render :action => "edit" }
90
+ format.js { render :action => "error.rjs"}
91
+ format.xml { render :xml => @question_sheet.errors.to_xml }
92
+ end
93
+ end
94
+ end
95
+
96
+ # mark sheet as destroyed
97
+ # DELETE /question_sheets/1
98
+ def destroy
99
+ @question_sheet.destroy
100
+
101
+ respond_to do |format|
102
+ format.html { redirect_to fe_admin_question_sheets_path }
103
+ format.xml { head :ok }
104
+ end
105
+ end
106
+
107
+ protected
108
+ def get_question_sheet
109
+ @question_sheet = Fe::QuestionSheet.find(params[:id])
110
+ end
111
+ end
112
+
@@ -39,7 +39,8 @@ module Fe::AnswerPagesControllerConcern
39
39
  end
40
40
  end
41
41
  @presenter.active_page = nil
42
- @answer_sheet.touch
42
+ @answer_sheet.update(locale: session[:locale])
43
+ @saved_at_timestamp = [@answer_sheet.updated_at, @answer_sheet.answers.maximum(:updated_at)].compact.max
43
44
  respond_to do |format|
44
45
  format.js
45
46
  #format.html
@@ -22,7 +22,7 @@ module Fe::AnswerSheetsControllerConcern
22
22
  @question_sheet = Fe::QuestionSheet.find(params[:question_sheet_id])
23
23
  @answer_sheet = @question_sheet.answer_sheets.create
24
24
 
25
- redirect_to edit_answer_sheet_path(@answer_sheet)
25
+ redirect_to edit_fe_answer_sheet_path(@answer_sheet)
26
26
  end
27
27
 
28
28
  # display answer sheet for data capture (page 1)
@@ -4,6 +4,7 @@ module Fe::ApplicationControllerConcern
4
4
  begin
5
5
  included do
6
6
  helper_method :fe_user
7
+ before_filter :set_locale
7
8
  end
8
9
  rescue ActiveSupport::Concern::MultipleIncludedBlocks
9
10
  end
@@ -18,6 +19,18 @@ module Fe::ApplicationControllerConcern
18
19
  @fe_user
19
20
  end
20
21
 
22
+ def extract_locale_from_accept_language_header
23
+ request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first if request.env['HTTP_ACCEPT_LANGUAGE'].present?
24
+ end
25
+
26
+ def set_locale
27
+ session[:locale] = params[:locale] if params[:locale]
28
+ session[:locale] ||= extract_locale_from_accept_language_header || I18n.default_locale
29
+ if @answer_sheet
30
+ session[:locale] = I18n.default_locale unless @answer_sheet.languages.include?(session[:locale])
31
+ end
32
+ end
33
+
21
34
  def current_person
22
35
  #raise "no user" unless current_user
23
36
  return nil unless current_user
@@ -1,6 +1,8 @@
1
+ # TODO determine how this relates to Fe::ReferencesController and if we can delete one of the two
1
2
  class Fe::ReferenceSheetsController < Fe::AnswerSheetsController
2
3
  skip_before_filter :ssm_login_required, :login
3
4
  before_filter :edit_only, :except => [:edit]
5
+
4
6
  def edit
5
7
  @reference_sheet = @answer_sheet
6
8
  unless @answer_sheet
@@ -1,4 +1,5 @@
1
1
  # for Reference completing answer sheet
2
+ # TODO determine how this relates to Fe::ReferenceSheetsController and if we can delete one of the two
2
3
  module Fe
3
4
  class ReferencesController < ApplicationController
4
5
  skip_before_filter :cas_filter
@@ -54,5 +54,10 @@ module Fe
54
54
 
55
55
  content_tag(:a, name, html_options.merge(:href => href, :onclick => onclick))
56
56
  end
57
+
58
+ def error_messages_for(model)
59
+ record = instance_variable_get(:"@#{(model.is_a?(ActiveRecord::Base) ? model.class : model).to_s.underscore}")
60
+ render "layouts/fe/error_messages_for", record: record
61
+ end
57
62
  end
58
63
  end
@@ -6,12 +6,19 @@ module Fe
6
6
  email_template = EmailTemplate.find_by_name(template_name)
7
7
 
8
8
  if email_template.nil?
9
- raise "Email Template #{template_name} could not be found"
9
+ raise "Email Template '#{template_name}' could not be found"
10
10
  else
11
- mail(:to => p_recipients,
11
+ set_format = options.delete(:format)
12
+ mail({:to => p_recipients,
12
13
  :from => p_from,
13
- :subject => Liquid::Template.parse(email_template.subject).render(template_params),
14
- :body => Liquid::Template.parse(email_template.content).render(template_params))
14
+ :subject => Liquid::Template.parse(email_template.subject).render(template_params)}.merge(options)) do |format|
15
+ case set_format.to_s
16
+ when 'html'
17
+ format.html { render html: Liquid::Template.parse(email_template.content).render(template_params) }
18
+ else
19
+ format.text { render text: Liquid::Template.parse(email_template.content).render(template_params) }
20
+ end
21
+ end
15
22
  @recipients = p_recipients
16
23
  @from = p_from
17
24
  @subject = Liquid::Template.parse(email_template.subject).render(template_params)
@@ -0,0 +1,2 @@
1
+ class AnswerSheet < ActiveRecord::Base
2
+ end
@@ -2,9 +2,10 @@ require 'aasm'
2
2
 
3
3
  # a visitor applies to a sleeve (application)
4
4
  class Fe::Application < Fe::AnswerSheet
5
+
5
6
  self.table_name = "#{Fe.table_name_prefix}applications"
6
7
 
7
- belongs_to :applicant, :class_name => "Person", :foreign_key => "applicant_id"
8
+ belongs_to :applicant, foreign_key: 'person_id', class_name: "Person"
8
9
  has_many :references, :class_name => 'ReferenceSheet', :foreign_key => :applicant_answer_sheet_id, :dependent => :destroy
9
10
  has_one :answer_sheet_question_sheet, :foreign_key => "answer_sheet_id"
10
11
  has_many :answer_sheet_question_sheets, :foreign_key => 'answer_sheet_id'
@@ -48,6 +48,15 @@ module Fe
48
48
  link
49
49
  end
50
50
 
51
+ def prev_page
52
+ active_page_dom_id = active_page_link.dom_id
53
+
54
+ this_page = @page_links.find {|p| p.dom_id == active_page_dom_id}
55
+ index = @page_links.index(this_page)
56
+ return nil if index == 0
57
+ @page_links.at( index - 1 ) unless this_page.nil?
58
+ end
59
+
51
60
  def next_page
52
61
  active_page_dom_id = active_page_link.dom_id
53
62
 
@@ -81,7 +90,7 @@ module Fe
81
90
  end
82
91
 
83
92
  def new_page_link(answer_sheet, page, a = nil)
84
- Fe::PageLink.new(page.label, edit_fe_answer_sheet_page_path(answer_sheet, page, :a => a), dom_page(answer_sheet, page), page) if page
93
+ Fe::PageLink.new(edit_fe_answer_sheet_page_path(answer_sheet, page, :a => a), dom_page(answer_sheet, page), page) if page
85
94
  end
86
95
 
87
96
  protected
@@ -4,15 +4,41 @@ module Fe
4
4
 
5
5
  begin
6
6
  included do
7
- has_many :answer_sheet_question_sheets, :foreign_key => 'answer_sheet_id'
8
- has_many :question_sheets, :through => :answer_sheet_question_sheets
9
- has_many :answers, :foreign_key => 'answer_sheet_id'
10
- has_many :reference_sheets, :foreign_key => "applicant_answer_sheet_id"
11
- has_many :payments, :foreign_key => "application_id"
7
+ has_many :answer_sheet_question_sheets, foreign_key: 'answer_sheet_id', class_name: '::Fe::AnswerSheetQuestionSheet'
8
+ has_many :question_sheets, through: :answer_sheet_question_sheets, class_name: 'Fe::QuestionSheet'
9
+ has_many :answers, ->(answer_sheet) {
10
+ question_sheet_ids = answer_sheet.question_sheet_ids
11
+
12
+ if question_sheet_ids.any?
13
+ element_ids = Fe::Page.joins(:question_sheet).where(question_sheet_id: question_sheet_ids).pluck(:all_element_ids).compact
14
+ element_ids = element_ids.collect{ |e| e.split(',') }.flatten
15
+ end
16
+
17
+ unless question_sheet_ids.any? && element_ids.any?
18
+ # an answer sheet not assigned to a question sheet, or assigned to
19
+ # a question sheet with no elements should not return any answers
20
+ return where('false')
21
+ end
22
+
23
+ where('question_id' => element_ids)
24
+
25
+ }, foreign_key: 'answer_sheet_id', class_name: '::Fe::Answer'
26
+ has_many :reference_sheets, :foreign_key => 'applicant_answer_sheet_id', class_name: 'Fe::ReferenceSheet'
27
+ has_many :payments, :foreign_key => 'application_id', class_name: 'Fe::Payment'
12
28
  end
13
29
  rescue ActiveSupport::Concern::MultipleIncludedBlocks
14
30
  end
15
31
 
32
+ def languages
33
+ return [] unless question_sheets.first
34
+
35
+ unless @languages
36
+ @languages = question_sheets.first.languages
37
+ question_sheets[1..-1].each { |qs| @languages &= qs.languages.select(&:present?) }
38
+ end
39
+ @languages
40
+ end
41
+
16
42
  def complete?
17
43
  !completed_at.nil?
18
44
  end
@@ -28,7 +54,7 @@ module Fe
28
54
  end
29
55
 
30
56
  def pages
31
- Page.where(:question_sheet_id => question_sheets.collect(&:id))
57
+ Page.where(:question_sheet_id => question_sheets.collect(&:id)).order('number')
32
58
  end
33
59
 
34
60
  def completely_filled_out?
@@ -44,12 +70,16 @@ module Fe
44
70
  end
45
71
 
46
72
  def percent_complete
47
- num_questions = question_sheets.inject(0.0) { |sum, qs| qs.nil? ? sum : qs.questions.length + sum }
73
+ num_questions = question_sheets.inject(0.0) { |sum, qs| qs.nil? ? sum : qs.questions_count + sum }
48
74
  return 0 if num_questions == 0
49
- num_answers = answers.where("value IS NOT NULL && value != ''").select("DISTINCT question_id").count
75
+ num_answers = answers.where("(value IS NOT NULL) AND (value != '')").select("DISTINCT question_id").count
50
76
  [ [ (num_answers.to_f / num_questions.to_f * 100.0).to_i, 100 ].min, 0 ].max
51
77
  end
52
78
 
53
79
  def collat_title() "" end
80
+
81
+ def question_sheet_ids
82
+ question_sheets.collect(&:id)
83
+ end
54
84
  end
55
85
  end
@@ -1,9 +1,11 @@
1
1
  require 'net/http'
2
+ # :nocov:
2
3
  begin
3
4
  require 'xml/libxml'
4
5
  rescue LoadError
5
6
  require 'rexml/document'
6
7
  end
8
+ # :nocov:
7
9
 
8
10
  module Fe
9
11
  module ChoiceFieldConcern
@@ -17,22 +19,23 @@ module Fe
17
19
  end
18
20
 
19
21
  # Returns choices stored one per line in content field
20
- def choices
22
+ def choices(locale = nil)
21
23
  retVal = Array.new
22
24
  if ['yes-no', 'acceptance'].include?(self.style)
23
- return [["Yes",1],["No",0]]
24
- elsif !source.blank?
25
+ return [[_('Yes'),1],[_('No'),0]]
26
+ elsif source.present?
25
27
  begin
26
28
  doc = XML::Document.file(source)
27
29
  options = doc.find(text_xpath).collect { |n| n.content }
28
30
  values = doc.find(value_xpath).collect { |n| n.content }
29
31
  retVal = [options, values].transpose
30
- rescue NameError
32
+ rescue NameError, LibXML::XML::Error
31
33
  doc = REXML::Document.new Net::HTTP.get_response(URI.parse(source)).body
32
- retVal = [ doc.elements.collect(text_xpath){|c|c.text}, doc.elements.collect(value_xpath){|c|c.text} ].transpose.sort
34
+ retVal = [ doc.elements.collect(text_xpath){|c|c.text}, doc.elements.collect(value_xpath){|c|c.text} ].transpose
33
35
  end
34
- elsif !content.nil?
35
- content.split("\n").each do |opt|
36
+ elsif content.present?
37
+ choices = content_translations[locale] || content
38
+ choices.split("\n").each do |opt|
36
39
  pair = opt.strip.split(";").reverse!
37
40
  pair[1] ||= pair[0]
38
41
  retVal << pair
@@ -124,18 +127,22 @@ module Fe
124
127
  def conditional_match(answer_sheet)
125
128
  displayed_response = display_response(answer_sheet)
126
129
  (is_true(displayed_response) && is_true(conditional_answer)) ||
127
- (is_false(displayed_response) && is_false(conditional_answer)) ||
130
+ (is_response_false(answer_sheet) && is_false(conditional_answer)) ||
128
131
  (displayed_response == conditional_answer)
129
132
  end
130
133
 
134
+ def is_response_false(answer_sheet)
135
+ is_false(display_response(answer_sheet))
136
+ end
137
+
131
138
  protected
132
139
  def is_true(val)
133
- [1,'1',true,'true','Yes','yes'].include?(val) # note: true = anything but false | nil
140
+ ['1','true','yes'].include?(val.to_s.downcase)
134
141
  end
135
142
 
136
143
  def is_false(val)
137
144
  # returns false if false (a bit odd)
138
- [0,'0',false,'false','No','no'].include?(val)
145
+ ['0','false','no'].include?(val.to_s.downcase)
139
146
  end
140
147
 
141
148
  end
@@ -35,7 +35,7 @@ module Fe
35
35
 
36
36
  def format_date_response(answer_sheet = nil)
37
37
  r = response(answer_sheet)
38
- r = r.strftime("%m/%d/%Y") unless r.blank?
38
+ r = r.strftime("%Y-%m-%d") unless r.blank?
39
39
  r
40
40
  end
41
41
 
@@ -4,23 +4,29 @@ module Fe
4
4
  self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
5
5
 
6
6
  belongs_to :question_grid,
7
- :class_name => "Fe::QuestionGrid",
8
- :foreign_key => "question_grid_id"
7
+ class_name: "Fe::QuestionGrid"
8
+
9
+ belongs_to :question_grid_with_total,
10
+ class_name: "Fe::QuestionGridWithTotal",
11
+ foreign_key: "question_grid_id"
9
12
 
10
13
  belongs_to :choice_field,
11
- :class_name => "Fe::ChoiceField",
12
- :foreign_key => "choice_field_id"
14
+ class_name: "Fe::ChoiceField"
15
+
16
+ has_many :choice_field_children, foreign_key: 'choice_field_id',
17
+ class_name: 'Fe::Element'
13
18
 
14
19
  belongs_to :question_sheet, :foreign_key => "related_question_sheet_id"
15
20
 
16
- belongs_to :conditional, :polymorphic => true
21
+ belongs_to :conditional, polymorphic: true
17
22
 
18
23
  self.inheritance_column = :kind
19
24
 
20
- has_many :page_elements, :dependent => :destroy
21
- has_many :pages, :through => :page_elements
25
+ has_many :page_elements, dependent: :destroy
26
+ has_many :pages, through: :page_elements
22
27
 
23
28
  scope :active, -> { select("distinct(#{Fe::Element.table_name}.id), #{Fe::Element.table_name}.*").where(Fe::QuestionSheet.table_name + '.archived' => false).joins({:pages => :question_sheet}) }
29
+ scope :questions, -> { where("kind NOT IN('Fe::Paragraph', 'Fe::Section', 'Fe::QuestionGrid', 'Fe::QuestionGridWithTotal')") }
24
30
 
25
31
  validates_presence_of :kind
26
32
  validates_presence_of :style
@@ -32,8 +38,13 @@ module Fe
32
38
 
33
39
  before_validation :set_defaults, :on => :create
34
40
  before_save :set_conditional_element
41
+ after_save :update_page_all_element_ids
35
42
  after_save :update_any_previous_conditional_elements
36
43
 
44
+ serialize :label_translations, Hash
45
+ serialize :tip_translations, Hash
46
+ serialize :content_translations, Hash
47
+
37
48
  # HUMANIZED_ATTRIBUTES = {
38
49
  # :slug => "Variable"
39
50
  # }changed.include?('address1')
@@ -41,6 +52,23 @@ module Fe
41
52
  # def self.human_attrib_name(attr)
42
53
  # HUMANIZED_ATTRIBUTES[attr.to_sym] || super
43
54
  # end
55
+ def label(locale = nil)
56
+ label_translations[locale] || self[:label]
57
+ end
58
+
59
+ def content(locale = nil)
60
+ content_translations[locale] || self[:content]
61
+ end
62
+
63
+ def tooltip(locale = nil)
64
+ tip_translations[locale] || self[:tooltip]
65
+ end
66
+
67
+ # returns all pages this element is on, whether that be directly, through a grid, or as a choice field conditional option
68
+ def pages_on
69
+ all_pages = pages.reload + [question_grid, question_grid_with_total, choice_field].compact.collect(&:pages_on)
70
+ all_pages.flatten.uniq
71
+ end
44
72
 
45
73
  def has_response?(answer_sheet = nil)
46
74
  false
@@ -52,7 +80,7 @@ module Fe
52
80
  unless eval("answer_sheet." + self.object_name + ".nil?")
53
81
  klass = eval("answer_sheet." + self.object_name + ".class")
54
82
  column = klass.columns_hash[self.attribute_name]
55
- column.limit
83
+ return column.limit
56
84
  end
57
85
  rescue
58
86
  nil
@@ -61,24 +89,54 @@ module Fe
61
89
  end
62
90
 
63
91
  # assume each element is on a question sheet only once to make things simpler. if not, just take the first one
64
- def previous_element(question_sheet)
65
- page_element = page_elements.joins(page: :question_sheet).where("#{Fe::QuestionSheet.table_name}.id" => question_sheet.id).first
66
- #binding.pry if page_element.nil?
67
- return unless page_element
68
- index = page_element.page.elements.index(self)
69
- if index > 0 && prev_el = page_element.page.elements[index-1]
70
- return prev_el
92
+ def previous_element(question_sheet, page = nil)
93
+ unless page
94
+ page_element = page_elements.joins(page: :question_sheet).where("#{Fe::QuestionSheet.table_name}.id" => question_sheet.id).first
95
+ return unless page_element
96
+ page = page_element.page
97
+ end
98
+
99
+ index = page.all_element_ids_arr.index(self.id)
100
+ unless index
101
+ # this can happen for yesno options, since they're rendered as elements but aren't on the page or in a grid
102
+ # but just in case self is an element on the page and the element_ids got out of sync, rebuild the all_element_ids
103
+ # and try again
104
+ page.rebuild_all_element_ids
105
+ index = page.all_element_ids_arr.index(self.id)
106
+ end
107
+ if index && index > 0 && prev_el_id = page.all_element_ids_arr[index-1]
108
+ return Fe::Element.find(prev_el_id)
71
109
  end
72
110
  end
73
111
 
74
- def required?(answer_sheet = nil)
75
- if answer_sheet &&
76
- self.question_grid.nil? &&
77
- (prev_el = previous_element(answer_sheet.question_sheet)) &&
78
- prev_el.is_a?(Fe::Question) &&
79
- prev_el.class != Fe::QuestionGrid &&
80
- prev_el.conditional_match(answer_sheet)
112
+ def hidden_by_conditional?(answer_sheet, page, prev_el)
113
+ (prev_el ||= previous_element(answer_sheet.question_sheet, page)) &&
114
+ prev_el.is_a?(Fe::Question) &&
115
+ prev_el.conditional == self &&
116
+ !prev_el.conditional_match(answer_sheet)
117
+ end
118
+
119
+ def hidden_by_choice_field?(answer_sheet)
120
+ choice_field.present? &&
121
+ choice_field.is_a?(Fe::ChoiceField) &&
122
+ choice_field.is_response_false(answer_sheet)
123
+ end
124
+
125
+ # use prev_el directly if it's passed in; otherwise, pass page to previous_element to find the prev_el faster
126
+ def visible?(answer_sheet = nil, page = nil, prev_el = nil)
127
+ !hidden?(answer_sheet, page, prev_el)
128
+ end
129
+
130
+ # use prev_el directly if it's passed in; otherwise, pass page to previous_element to find the prev_el faster
131
+ def hidden?(answer_sheet = nil, page = nil, prev_el = nil)
132
+ @hidden ||= answer_sheet &&
133
+ (hidden_by_choice_field?(answer_sheet) ||
134
+ hidden_by_conditional?(answer_sheet, page, prev_el))
135
+ end
81
136
 
137
+ # use prev_el directly if it's passed in; otherwise, pass page to previous_element to find the prev_el faster
138
+ def required?(answer_sheet = nil, page = nil, prev_el = nil)
139
+ if hidden?(answer_sheet, page, prev_el)
82
140
  return false
83
141
  else
84
142
  required == true
@@ -130,7 +188,8 @@ module Fe
130
188
  when "Fe::ChoiceField"
131
189
  new_element.choice_field_id = parent.id
132
190
  end
133
- new_element.save(:validate => false)
191
+ new_element.position = parent.elements.maximum(:position).to_i + 1 if parent
192
+ new_element.save!(:validate => false)
134
193
  Fe::PageElement.create(:element => new_element, :page => page) unless parent
135
194
 
136
195
  # duplicate children
@@ -144,6 +203,7 @@ module Fe
144
203
  # include nested elements
145
204
  def all_elements
146
205
  if respond_to?(:elements)
206
+ elements.reload
147
207
  (elements + elements.collect(&:all_elements)).flatten
148
208
  else
149
209
  []
@@ -151,6 +211,7 @@ module Fe
151
211
  end
152
212
 
153
213
  def reuseable?
214
+ return false if Fe.never_reuse_elements
154
215
  (self.is_a?(Fe::Question) || self.is_a?(Fe::QuestionGrid) || self.is_a?(Fe::QuestionGridWithTotal))
155
216
  end
156
217
 
@@ -167,27 +228,40 @@ module Fe
167
228
  def set_conditional_element
168
229
  case conditional_type
169
230
  when "Fe::Element"
170
- pages.reload.each do |page|
171
- index = page.elements.index(self)
172
- if index && index < page.elements.length - 1
173
- self.conditional_id = page.elements[index+1].id
231
+ pages_on.each do |page|
232
+
233
+ if index = page.all_element_ids_arr.index(self.id)
234
+ self.conditional_id = page.all_element_ids_arr[index+1]
235
+ else
236
+ self.conditional_id = nil
174
237
  end
175
238
  end
239
+ when ""
240
+ # keep conditional_type nil instead of empty to be consistent
241
+ self.conditional_type = nil
176
242
  end
177
243
  end
178
244
 
179
245
  def update_any_previous_conditional_elements
180
- pages.reload.each do |page|
181
- index = page.elements.index(self)
246
+ pages_on.each do |page|
247
+ index = page.all_element_ids_arr.index(self.id)
182
248
  if index && index > 0
183
- prev_el = page.elements[index-1]
249
+ prev_el = Fe::Element.find(page.all_element_ids_arr[index-1])
184
250
  if prev_el.conditional_type == "Fe::Element"
185
- prev_el.update_attribute(:conditional_id, id)
251
+ prev_el.update_column(:conditional_id, id)
186
252
  end
187
253
  end
188
254
  end
189
255
  end
190
256
 
257
+ def update_page_all_element_ids
258
+ [question_grid, question_grid_with_total].compact.each do |field|
259
+ field.update_page_all_element_ids
260
+ end
261
+
262
+ pages.reload.each do |p| p.rebuild_all_element_ids end
263
+ end
264
+
191
265
  protected
192
266
 
193
267
  def set_defaults