fe 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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