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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +20 -0
- data/Rakefile +48 -0
- data/app/assets/images/fe/ajax-loader.gif +0 -0
- data/app/assets/images/fe/butgrad.png +0 -0
- data/app/assets/images/fe/icons/add.png +0 -0
- data/app/assets/images/fe/icons/application_form.png +0 -0
- data/app/assets/images/fe/icons/application_form_add.png +0 -0
- data/app/assets/images/fe/icons/arrow-move.png +0 -0
- data/app/assets/images/fe/icons/arrow_out.png +0 -0
- data/app/assets/images/fe/icons/asterisk_yellow.png +0 -0
- data/app/assets/images/fe/icons/book-open-list.png +0 -0
- data/app/assets/images/fe/icons/book_open.png +0 -0
- data/app/assets/images/fe/icons/briefcase.png +0 -0
- data/app/assets/images/fe/icons/calendar_view_day.png +0 -0
- data/app/assets/images/fe/icons/checkbox.png +0 -0
- data/app/assets/images/fe/icons/copy_paste.gif +0 -0
- data/app/assets/images/fe/icons/disk.png +0 -0
- data/app/assets/images/fe/icons/document--pencil.png +0 -0
- data/app/assets/images/fe/icons/document-copy.png +0 -0
- data/app/assets/images/fe/icons/map_magnify.png +0 -0
- data/app/assets/images/fe/icons/minus-button.png +0 -0
- data/app/assets/images/fe/icons/move.png +0 -0
- data/app/assets/images/fe/icons/page_error.png +0 -0
- data/app/assets/images/fe/icons/page_valid.png +0 -0
- data/app/assets/images/fe/icons/page_white.png +0 -0
- data/app/assets/images/fe/icons/page_white_add.png +0 -0
- data/app/assets/images/fe/icons/page_white_error.png +0 -0
- data/app/assets/images/fe/icons/paper-clip.png +0 -0
- data/app/assets/images/fe/icons/pencil-small.png +0 -0
- data/app/assets/images/fe/icons/pencil.png +0 -0
- data/app/assets/images/fe/icons/question-balloon.png +0 -0
- data/app/assets/images/fe/icons/radio.png +0 -0
- data/app/assets/images/fe/icons/star-small.png +0 -0
- data/app/assets/images/fe/icons/table.png +0 -0
- data/app/assets/images/fe/icons/text_align_left.png +0 -0
- data/app/assets/images/fe/icons/text_horizontalrule.png +0 -0
- data/app/assets/images/fe/icons/textfield.png +0 -0
- data/app/assets/images/fe/indent.png +0 -0
- data/app/assets/images/fe/overlay.png +0 -0
- data/app/assets/images/fe/selected_bg.jpg +0 -0
- data/app/assets/images/fe/status.gif +0 -0
- data/app/assets/images/fe/tooltip/black.png +0 -0
- data/app/assets/images/fe/tooltip/black_arrow.png +0 -0
- data/app/assets/images/fe/tooltip/black_arrow_big.png +0 -0
- data/app/assets/images/fe/tooltip/black_big.png +0 -0
- data/app/assets/images/fe/tooltip/white.png +0 -0
- data/app/assets/images/fe/tooltip/white_arrow.png +0 -0
- data/app/assets/images/fe/tooltip/white_arrow_big.png +0 -0
- data/app/assets/images/fe/tooltip/white_big.png +0 -0
- data/app/assets/images/fe/uploadify/cancel.png +0 -0
- data/app/assets/images/fe/uploadify/uploadify.swf +0 -0
- data/app/assets/javascripts/fe/admin.js +7 -0
- data/app/assets/javascripts/fe/jquery.metadata.js +122 -0
- data/app/assets/javascripts/fe/jquery.scrollTo-min.js +7 -0
- data/app/assets/javascripts/fe/jquery.uploadify.v2.1.0.js +258 -0
- data/app/assets/javascripts/fe/jquery.validate.pack.js +15 -0
- data/app/assets/javascripts/fe/qe.admin.js +115 -0
- data/app/assets/javascripts/fe/qe.common.js +57 -0
- data/app/assets/javascripts/fe/qe.public.js +331 -0
- data/app/assets/javascripts/fe/swfobject.js +4 -0
- data/app/assets/stylesheets/fe/qe.screen.css.scss.erb +552 -0
- data/app/assets/stylesheets/fe/reset.css +55 -0
- data/app/assets/stylesheets/fe/validation.css +91 -0
- data/app/controllers/fe/admin/elements_controller.rb +185 -0
- data/app/controllers/fe/admin/email_templates_controller.rb +61 -0
- data/app/controllers/fe/admin/question_pages_controller.rb +113 -0
- data/app/controllers/fe/admin/question_sheets_controller.rb +106 -0
- data/app/controllers/fe/answer_pages_controller.rb +3 -0
- data/app/controllers/fe/answer_sheets_controller.rb +3 -0
- data/app/controllers/fe/concerns/answer_pages_controller_concern.rb +80 -0
- data/app/controllers/fe/concerns/answer_sheets_controller_concern.rb +84 -0
- data/app/controllers/fe/reference_sheets_controller.rb +29 -0
- data/app/helpers/fe/answer_pages_helper.rb +19 -0
- data/app/helpers/fe/application_helper.rb +49 -0
- data/app/mailers/fe/notifier.rb +22 -0
- data/app/models/fe/answer.rb +13 -0
- data/app/models/fe/answer_pages_presenter.rb +13 -0
- data/app/models/fe/answer_sheet.rb +10 -0
- data/app/models/fe/answer_sheet_question_sheet.rb +7 -0
- data/app/models/fe/attachment_field.rb +7 -0
- data/app/models/fe/choice_field.rb +7 -0
- data/app/models/fe/concerns/answer_concern.rb +36 -0
- data/app/models/fe/concerns/answer_pages_presenter_concern.rb +99 -0
- data/app/models/fe/concerns/answer_sheet_concern.rb +61 -0
- data/app/models/fe/concerns/choice_field_concern.rb +131 -0
- data/app/models/fe/condition.rb +53 -0
- data/app/models/fe/date_field.rb +52 -0
- data/app/models/fe/element.rb +164 -0
- data/app/models/fe/email_template.rb +7 -0
- data/app/models/fe/option.rb +10 -0
- data/app/models/fe/option_group.rb +10 -0
- data/app/models/fe/page.rb +101 -0
- data/app/models/fe/page_element.rb +9 -0
- data/app/models/fe/page_link.rb +15 -0
- data/app/models/fe/paragraph.rb +10 -0
- data/app/models/fe/payment.rb +52 -0
- data/app/models/fe/payment_question.rb +22 -0
- data/app/models/fe/presenter.rb +23 -0
- data/app/models/fe/question.rb +256 -0
- data/app/models/fe/question_grid.rb +26 -0
- data/app/models/fe/question_grid_with_total.rb +11 -0
- data/app/models/fe/question_set.rb +82 -0
- data/app/models/fe/question_sheet.rb +73 -0
- data/app/models/fe/reference_question.rb +42 -0
- data/app/models/fe/reference_sheet.rb +149 -0
- data/app/models/fe/section.rb +12 -0
- data/app/models/fe/state_chooser.rb +10 -0
- data/app/models/fe/text_field.rb +29 -0
- data/app/views/fe/admin/elements/_errors.html.erb +1 -0
- data/app/views/fe/admin/elements/create.js.erb +11 -0
- data/app/views/fe/admin/elements/destroy.js.erb +4 -0
- data/app/views/fe/admin/elements/drop.js.erb +2 -0
- data/app/views/fe/admin/elements/duplicate.js.erb +2 -0
- data/app/views/fe/admin/elements/edit.js.erb +4 -0
- data/app/views/fe/admin/elements/error.js.erb +4 -0
- data/app/views/fe/admin/elements/new.js.erb +10 -0
- data/app/views/fe/admin/elements/reorder.js.erb +0 -0
- data/app/views/fe/admin/elements/update.js.erb +9 -0
- data/app/views/fe/admin/email_templates/_form.html.erb +8 -0
- data/app/views/fe/admin/email_templates/edit.html.erb +13 -0
- data/app/views/fe/admin/email_templates/index.html.erb +20 -0
- data/app/views/fe/admin/email_templates/new.html.erb +11 -0
- data/app/views/fe/admin/panels/_advanced_options.html.erb +16 -0
- data/app/views/fe/admin/panels/_common_fields.html.erb +24 -0
- data/app/views/fe/admin/panels/_condition.html.erb +6 -0
- data/app/views/fe/admin/panels/_insert.html.erb +39 -0
- data/app/views/fe/admin/panels/_nav_controls.html.erb +6 -0
- data/app/views/fe/admin/panels/_page.html.erb +3 -0
- data/app/views/fe/admin/panels/_pages_list.html.erb +16 -0
- data/app/views/fe/admin/panels/_prop_attachment_field.html.erb +2 -0
- data/app/views/fe/admin/panels/_prop_choice_field.html.erb +46 -0
- data/app/views/fe/admin/panels/_prop_date_field.html.erb +7 -0
- data/app/views/fe/admin/panels/_prop_element.html.erb +30 -0
- data/app/views/fe/admin/panels/_prop_page.html.erb +21 -0
- data/app/views/fe/admin/panels/_prop_paragraph.html.erb +32 -0
- data/app/views/fe/admin/panels/_prop_question_grid.html.erb +23 -0
- data/app/views/fe/admin/panels/_prop_question_grid_with_total.html.erb +14 -0
- data/app/views/fe/admin/panels/_prop_reference_question.html.erb +12 -0
- data/app/views/fe/admin/panels/_prop_section.html.erb +2 -0
- data/app/views/fe/admin/panels/_prop_sheet.html.erb +17 -0
- data/app/views/fe/admin/panels/_prop_text_field.html.erb +20 -0
- data/app/views/fe/admin/question_pages/_element.html.erb +18 -0
- data/app/views/fe/admin/question_pages/_element_show.html.erb +10 -0
- data/app/views/fe/admin/question_pages/_errors.html.erb +1 -0
- data/app/views/fe/admin/question_pages/_question_page.html.erb +13 -0
- data/app/views/fe/admin/question_pages/create.js.erb +11 -0
- data/app/views/fe/admin/question_pages/destroy.js.erb +5 -0
- data/app/views/fe/admin/question_pages/edit.js.erb +3 -0
- data/app/views/fe/admin/question_pages/error.js.erb +4 -0
- data/app/views/fe/admin/question_pages/show.js.erb +8 -0
- data/app/views/fe/admin/question_pages/show_panel.js.erb +3 -0
- data/app/views/fe/admin/question_pages/update.js.erb +2 -0
- data/app/views/fe/admin/question_sheets/_errors.html.erb +1 -0
- data/app/views/fe/admin/question_sheets/edit.js.erb +3 -0
- data/app/views/fe/admin/question_sheets/error.js.erb +5 -0
- data/app/views/fe/admin/question_sheets/index.html.erb +41 -0
- data/app/views/fe/admin/question_sheets/new.html.erb +15 -0
- data/app/views/fe/admin/question_sheets/show.html.erb +27 -0
- data/app/views/fe/admin/question_sheets/update.js.erb +2 -0
- data/app/views/fe/answer_pages/_answer_page.html.erb +56 -0
- data/app/views/fe/answer_pages/_element.html.erb +9 -0
- data/app/views/fe/answer_pages/update.js.erb +5 -0
- data/app/views/fe/answer_sheets/_answer_sheet.html.erb +24 -0
- data/app/views/fe/answer_sheets/_element.html.erb +54 -0
- data/app/views/fe/answer_sheets/_incomplete.html.erb +10 -0
- data/app/views/fe/answer_sheets/_page_link.html.erb +7 -0
- data/app/views/fe/answer_sheets/_pages_list.html.erb +11 -0
- data/app/views/fe/answer_sheets/_title.html.erb +1 -0
- data/app/views/fe/answer_sheets/edit.html.erb +60 -0
- data/app/views/fe/answer_sheets/incomplete.js.erb +5 -0
- data/app/views/fe/answer_sheets/index.html.erb +18 -0
- data/app/views/fe/answer_sheets/send_reference_invite.js.erb +8 -0
- data/app/views/fe/answer_sheets/show.html.erb +13 -0
- data/app/views/fe/help/builder.html +33 -0
- data/app/views/fe/help/question_grid.html +18 -0
- data/app/views/fe/questions/_acceptance.html.erb +13 -0
- data/app/views/fe/questions/_attachment_field.html.erb +42 -0
- data/app/views/fe/questions/_checkbox_field.html.erb +49 -0
- data/app/views/fe/questions/_country.html.erb +7 -0
- data/app/views/fe/questions/_date_field.html.erb +7 -0
- data/app/views/fe/questions/_date_field_mmyy.html.erb +9 -0
- data/app/views/fe/questions/_drop_down_field.html.erb +7 -0
- data/app/views/fe/questions/_paragraph.html.erb +1 -0
- data/app/views/fe/questions/_question_grid.html.erb +65 -0
- data/app/views/fe/questions/_question_grid_with_total.html.erb +57 -0
- data/app/views/fe/questions/_questions.html.erb +9 -0
- data/app/views/fe/questions/_radio_button_field.html.erb +41 -0
- data/app/views/fe/questions/_rating.html.erb +25 -0
- data/app/views/fe/questions/_reference_discipler.html.erb +1 -0
- data/app/views/fe/questions/_reference_friend.html.erb +1 -0
- data/app/views/fe/questions/_reference_parent.html.erb +1 -0
- data/app/views/fe/questions/_reference_peer.html.erb +1 -0
- data/app/views/fe/questions/_reference_question.html.erb +38 -0
- data/app/views/fe/questions/_reference_roommate.html.erb +1 -0
- data/app/views/fe/questions/_reference_spiritual.html.erb +1 -0
- data/app/views/fe/questions/_reference_staff.html.erb +1 -0
- data/app/views/fe/questions/_section.html.erb +1 -0
- data/app/views/fe/questions/_state_chooser.html.erb +7 -0
- data/app/views/fe/questions/_text_area_field.html.erb +6 -0
- data/app/views/fe/questions/_text_field.html.erb +8 -0
- data/app/views/fe/questions/_yes_no.html.erb +17 -0
- data/app/views/fe/questions/_yes_no_field.erb +17 -0
- data/app/views/fe/reference_sheets/not_found.html.erb +5 -0
- data/app/views/layouts/fe/application.html.erb +31 -0
- data/app/views/layouts/fe/qe.admin.html.erb +30 -0
- data/config/routes.rb +49 -0
- data/db/migrate/20131003041856_core.rb +91 -0
- data/db/migrate/20131003044250_create_reference_sheets.rb +23 -0
- data/db/migrate/20131003044436_add_element_and_answer_fields.rb +10 -0
- data/db/migrate/20131003044518_create_email_templates.rb +17 -0
- data/db/migrate/20131003044621_add_max_lengths.rb +8 -0
- data/db/migrate/20131003044714_create_join_table.rb +11 -0
- data/db/migrate/20131016162128_remove_question_id_from_element.rb +9 -0
- data/lib/fe.rb +22 -0
- data/lib/fe/engine.rb +19 -0
- data/lib/fe/version.rb +3 -0
- data/lib/generators/fe/install_generator.rb +132 -0
- data/lib/tasks/qe_tasks.rake +4 -0
- data/spec/controllers/fe/admin/elements_controller_spec.rb +4 -0
- data/spec/controllers/fe/admin/email_templates_controller_spec.rb +4 -0
- data/spec/controllers/fe/admin/question_pages_controller_spec.rb +4 -0
- data/spec/controllers/fe/admin/question_sheets_controller_spec.rb +4 -0
- data/spec/controllers/fe/answer_pages_controller_spec.rb +4 -0
- data/spec/controllers/fe/answer_sheets_controller_spec.rb +4 -0
- data/spec/controllers/fe/reference_sheets_controller_spec.rb +4 -0
- data/spec/factories/answer_sheets.rb +5 -0
- data/spec/factories/answers.rb +4 -0
- data/spec/factories/paragraphs.rb +4 -0
- data/spec/factories/question_sheet.rb +5 -0
- data/spec/factories/reference_questions.rb +4 -0
- data/spec/models/fe/answer_sheet_question_sheet_spec.rb +6 -0
- data/spec/models/fe/answer_sheet_spec.rb +8 -0
- data/spec/models/fe/answer_spec.rb +13 -0
- data/spec/models/fe/attachment_field_spec.rb +4 -0
- data/spec/models/fe/choice_field_spec.rb +5 -0
- data/spec/models/fe/condition_spec.rb +8 -0
- data/spec/models/fe/date_field_spec.rb +49 -0
- data/spec/models/fe/element_spec.rb +12 -0
- data/spec/models/fe/email_template_spec.rb +5 -0
- data/spec/models/fe/option_group_spec.rb +4 -0
- data/spec/models/fe/option_spec.rb +4 -0
- data/spec/models/fe/page_element_spec.rb +6 -0
- data/spec/models/fe/page_link_spec.rb +4 -0
- data/spec/models/fe/page_spec.rb +14 -0
- data/spec/models/fe/paragraph_spec.rb +17 -0
- data/spec/models/fe/question_grid_spec.rb +4 -0
- data/spec/models/fe/question_grid_with_total_spec.rb +4 -0
- data/spec/models/fe/question_set_spec.rb +4 -0
- data/spec/models/fe/question_sheet_spec.rb +8 -0
- data/spec/models/fe/question_spec.rb +20 -0
- data/spec/models/fe/reference_question_spec.rb +17 -0
- data/spec/models/fe/reference_sheet_spec.rb +11 -0
- data/spec/models/fe/section_spec.rb +4 -0
- data/spec/models/fe/state_chooser_spec.rb +4 -0
- data/spec/models/fe/text_field_spec.rb +17 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/support/database.txt +28 -0
- 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,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 %>
|