Commit 81752a5ce130ca0930ed23144f1475c673c6713f
1 parent
76560478
Exists in
master
and in
22 other branches
[custom-forms] Base model and migrations
Showing
22 changed files
with
824 additions
and
0 deletions
Show diff stats
plugins/custom_forms/db/migrate/20120727162444_create_custom_forms_plugin_forms.rb
0 → 100644
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +class CreateCustomFormsPluginForms < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + create_table :custom_forms_plugin_forms do |t| | ||
4 | + t.string :name | ||
5 | + t.string :slug | ||
6 | + t.text :description | ||
7 | + t.references :profile | ||
8 | + t.datetime :begining | ||
9 | + t.datetime :ending | ||
10 | + t.boolean :report_submissions, :default => false | ||
11 | + t.boolean :on_membership, :default => false | ||
12 | + t.string :access | ||
13 | + t.timestamps | ||
14 | + end | ||
15 | + end | ||
16 | + | ||
17 | + def self.down | ||
18 | + drop_table :custom_forms_plugin_forms | ||
19 | + end | ||
20 | +end |
plugins/custom_forms/db/migrate/20120727174506_create_custom_forms_plugin_fields.rb
0 → 100644
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +class CreateCustomFormsPluginFields < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + create_table :custom_forms_plugin_fields do |t| | ||
4 | + t.string :name | ||
5 | + t.string :slug | ||
6 | + t.string :type | ||
7 | + t.string :default_value | ||
8 | + t.string :choices | ||
9 | + t.float :minimum | ||
10 | + t.float :maximum | ||
11 | + t.references :form | ||
12 | + t.boolean :mandatory, :default => false | ||
13 | + t.boolean :multiple | ||
14 | + t.boolean :list | ||
15 | + end | ||
16 | + end | ||
17 | + | ||
18 | + def self.down | ||
19 | + drop_table :custom_forms_plugin_fields | ||
20 | + end | ||
21 | +end |
plugins/custom_forms/db/migrate/20120727175250_create_custom_forms_plugin_answers.rb
0 → 100644
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +class CreateCustomFormsPluginAnswers < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + create_table :custom_forms_plugin_answers do |t| | ||
4 | + t.text :value | ||
5 | + t.references :field | ||
6 | + t.references :submission | ||
7 | + end | ||
8 | + end | ||
9 | + | ||
10 | + def self.down | ||
11 | + drop_table :custom_forms_plugin_answers | ||
12 | + end | ||
13 | +end |
plugins/custom_forms/db/migrate/20120727180512_create_custom_forms_plugin_submissions.rb
0 → 100644
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +class CreateCustomFormsPluginSubmissions < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + create_table :custom_forms_plugin_submissions do |t| | ||
4 | + t.string :author_name | ||
5 | + t.string :author_email | ||
6 | + t.references :profile | ||
7 | + t.references :form | ||
8 | + t.timestamps | ||
9 | + end | ||
10 | + end | ||
11 | + | ||
12 | + def self.down | ||
13 | + drop_table :custom_forms_plugin_submissions | ||
14 | + end | ||
15 | +end |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +require 'ext/role_assignment_trigger' | ||
2 | + | ||
3 | +class CustomFormsPlugin < Noosfero::Plugin | ||
4 | + | ||
5 | + def self.plugin_name | ||
6 | + "Custom Forms" | ||
7 | + end | ||
8 | + | ||
9 | + def self.plugin_description | ||
10 | + _("Enables the creation of forms.") | ||
11 | + end | ||
12 | + | ||
13 | + def stylesheet? | ||
14 | + true | ||
15 | + end | ||
16 | + | ||
17 | + def control_panel_buttons | ||
18 | + {:title => _('Manage Forms'), :icon => 'custom-forms', :url => {:controller => 'custom_forms_plugin_myprofile'}} | ||
19 | + end | ||
20 | + | ||
21 | +end |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +class CustomFormsPlugin::Answer < Noosfero::Plugin::ActiveRecord | ||
2 | + belongs_to :field, :class_name => 'CustomFormsPlugin::Field' | ||
3 | + belongs_to :submission, :class_name => 'CustomFormsPlugin::Submission' | ||
4 | + | ||
5 | + validates_presence_of :field | ||
6 | + validate :value_mandatory, :if => 'field.present?' | ||
7 | + | ||
8 | + def value_mandatory | ||
9 | + if field.mandatory && value.blank? | ||
10 | + errors.add(field.slug.to_sym, _("is mandatory.").fix_i18n) | ||
11 | + end | ||
12 | + end | ||
13 | +end | ||
14 | + |
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +class CustomFormsPlugin::Field < ActiveRecord::Base | ||
2 | + set_table_name :custom_forms_plugin_fields | ||
3 | + | ||
4 | + validates_presence_of :form, :name | ||
5 | + validates_uniqueness_of :slug, :scope => :form_id | ||
6 | + | ||
7 | + belongs_to :form, :class_name => 'CustomFormsPlugin::Form', :dependent => :destroy | ||
8 | + has_many :answers, :class_name => 'CustomFormsPlugin::Answer' | ||
9 | + | ||
10 | + serialize :choices, Hash | ||
11 | + | ||
12 | + before_validation do |field| | ||
13 | + field.slug = field.name.to_slug if field.name.present? | ||
14 | + end | ||
15 | +end | ||
16 | + |
@@ -0,0 +1,70 @@ | @@ -0,0 +1,70 @@ | ||
1 | +class CustomFormsPlugin::Form < Noosfero::Plugin::ActiveRecord | ||
2 | + belongs_to :profile | ||
3 | + | ||
4 | + has_many :fields, :class_name => 'CustomFormsPlugin::Field' | ||
5 | + has_many :submissions, :class_name => 'CustomFormsPlugin::Submission' | ||
6 | + | ||
7 | + serialize :access | ||
8 | + | ||
9 | + validates_presence_of :profile, :name | ||
10 | + validates_uniqueness_of :slug, :scope => :profile_id | ||
11 | + validate :access_format | ||
12 | + | ||
13 | + before_validation do |form| | ||
14 | + form.slug = form.name.to_slug if form.name.present? | ||
15 | + form.access = nil if form.access.blank? | ||
16 | + end | ||
17 | + | ||
18 | + named_scope :from, lambda {|profile| {:conditions => {:profile_id => profile.id}}} | ||
19 | + named_scope :on_memberships, {:conditions => {:on_membership => true}} | ||
20 | +=begin | ||
21 | + named_scope :accessible_to lambda do |profile| | ||
22 | + #TODO should verify is profile is associated with the form owner | ||
23 | + profile_associated = ??? | ||
24 | + {:conditions => [" | ||
25 | + access IS NULL OR | ||
26 | + (access='logged' AND :profile_present) OR | ||
27 | + (access='associated' AND :profile_associated) OR | ||
28 | + :profile_id in access | ||
29 | + ", {:profile_present => profile.present?, :profile_associated => ???, :profile_id => profile.id}]} | ||
30 | + end | ||
31 | +=end | ||
32 | + | ||
33 | + def expired? | ||
34 | + (begining.present? && Time.now < begining) || (ending.present? && Time.now > ending) | ||
35 | + end | ||
36 | + | ||
37 | + def accessible_to(target) | ||
38 | + return true if access.nil? || target == profile | ||
39 | + return false if target.nil? | ||
40 | + return true if access == 'logged' | ||
41 | + return true if access == 'associated' && ((profile.organization? && profile.members.include?(target)) || (profile.person? && profile.friends.include?(target))) | ||
42 | + return true if access.kind_of?(Integer) && target.id == access | ||
43 | + return true if access.kind_of?(Array) && access.include?(target.id) | ||
44 | + end | ||
45 | + | ||
46 | + private | ||
47 | + | ||
48 | + def access_format | ||
49 | + if access.present? | ||
50 | + if access.kind_of?(String) | ||
51 | + if access != 'logged' && access != 'associated' | ||
52 | + errors.add(:access, _('Invalid string format of access.')) | ||
53 | + end | ||
54 | + elsif access.kind_of?(Integer) | ||
55 | + if !Profile.exists?(access) | ||
56 | + errors.add(:access, _('There is no profile with the provided id.')) | ||
57 | + end | ||
58 | + elsif access.kind_of?(Array) | ||
59 | + access.each do |value| | ||
60 | + if !value.kind_of?(Integer) || !Profile.exists?(value) | ||
61 | + errors.add(:access, _('There is no profile with the provided id.')) | ||
62 | + break | ||
63 | + end | ||
64 | + end | ||
65 | + else | ||
66 | + errors.add(:access, _('Invalid type format of access.')) | ||
67 | + end | ||
68 | + end | ||
69 | + end | ||
70 | +end |
@@ -0,0 +1,119 @@ | @@ -0,0 +1,119 @@ | ||
1 | +module CustomFormsPlugin::Helper | ||
2 | + def access_text(form) | ||
3 | + return _('Public') if form.access.nil? | ||
4 | + return _('Logged users') if form.access == 'logged' | ||
5 | + if form.access == 'associated' | ||
6 | + return _('Members') if form.profile.organization? | ||
7 | + return _('Friends') if form.profile.person? | ||
8 | + end | ||
9 | + return _('Custom') | ||
10 | + end | ||
11 | + | ||
12 | + def period_range(form) | ||
13 | + if form.begining.blank? && form.ending.blank? | ||
14 | + _('Always') | ||
15 | + elsif form.begining.present? && form.ending.blank? | ||
16 | + ('From %s') % time_format(form.begining) | ||
17 | + elsif form.begining.blank? && form.ending.present? | ||
18 | + _('Until %s') % time_format(form.ending) | ||
19 | + elsif form.begining.present? && form.ending.present? | ||
20 | + _('From %s until %s') % [time_format(form.begining), time_format(form.ending)] | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + def time_format(time) | ||
25 | + minutes = (time.min == 0) ? '' : ':%M' | ||
26 | + hour = (time.hour == 0 && minutes.blank?) ? '' : ' %H' | ||
27 | + h = hour.blank? ? '' : 'h' | ||
28 | + time.strftime("%Y-%m-%d#{hour+minutes+h}") | ||
29 | + end | ||
30 | + | ||
31 | + # TODO add the custom option that should offer the user the hability to | ||
32 | + # choose the profiles one by one, using something like tokeninput | ||
33 | + def access_options(profile) | ||
34 | + associated = profile.organization? ? _('Members') : _('Friends') | ||
35 | + [ | ||
36 | + [_('Public'), nil ], | ||
37 | + [_('Logged users'), 'logged' ], | ||
38 | + [ associated, 'associated'], | ||
39 | + ] | ||
40 | + end | ||
41 | + | ||
42 | + def type_options | ||
43 | + [ | ||
44 | + [_('Text'), 'text_field' ], | ||
45 | + [_('Select'), 'select_field'] | ||
46 | + ] | ||
47 | + end | ||
48 | + | ||
49 | + def type_to_label(type) | ||
50 | + map = { | ||
51 | + 'text_field' => _('Text'), | ||
52 | + 'select_field' => _('Select') | ||
53 | + } | ||
54 | + map[type_for_options(type)] | ||
55 | + end | ||
56 | + | ||
57 | + def type_for_options(type) | ||
58 | + type.to_s.split(':').last.underscore | ||
59 | + end | ||
60 | + | ||
61 | + def display_custom_field(field, submission, form) | ||
62 | + answer = submission.answers.select{|answer| answer.field == field}.first | ||
63 | + field_tag = send("display_#{type_for_options(field.class)}",field, answer, form) | ||
64 | + if field.mandatory? && !radio_button?(field) && !check_box?(field) && submission.id.nil? | ||
65 | + required(labelled_form_field(field.name, field_tag)) | ||
66 | + else | ||
67 | + labelled_form_field(field.name, field_tag) | ||
68 | + end | ||
69 | + end | ||
70 | + | ||
71 | + def display_text_field(field, answer, form) | ||
72 | + value = answer.present? ? answer.value : field.default_value | ||
73 | + text_field(form, field.name.to_slug, :value => value, :disabled => answer.present?) | ||
74 | + end | ||
75 | + | ||
76 | + def display_select_field(field, answer, form) | ||
77 | + if field.list && field.multiple | ||
78 | + selected = answer.present? ? answer.value.split(',') : [] | ||
79 | + select_tag "#{form}[#{field.name.to_slug}]", options_for_select(field.choices.to_a, selected), :multiple => true, :size => field.choices.size, :disabled => answer.present? | ||
80 | + elsif !field.list && field.multiple | ||
81 | + field.choices.map do |name, value| | ||
82 | + default = answer.present? ? answer.value.split(',').include?(value) : false | ||
83 | + labelled_check_box name, "#{form}[#{field.name.to_slug}][#{value}]", '1', default, :disabled => answer.present? | ||
84 | + end.join("\n") | ||
85 | + elsif field.list && !field.multiple | ||
86 | + selected = answer.present? ? answer.value.split(',') : [] | ||
87 | + select_tag "#{form}[#{field.name.to_slug}]", options_for_select([['','']] + field.choices.to_a, selected), :disabled => answer.present? | ||
88 | + elsif !field.list && !field.multiple | ||
89 | + field.choices.map do |name, value| | ||
90 | + default = answer.present? ? answer.value == value : true | ||
91 | + labelled_radio_button name, "#{form}[#{field.name.to_slug}]", value, default, :disabled => answer.present? | ||
92 | + end.join("\n") | ||
93 | + end | ||
94 | + end | ||
95 | + | ||
96 | + def radio_button?(field) | ||
97 | + type_for_options(field.class) == 'select_field' && !field.list && !field.multiple | ||
98 | + end | ||
99 | + | ||
100 | + def check_box?(field) | ||
101 | + type_for_options(field.class) == 'select_field' && !field.list && field.multiple | ||
102 | + end | ||
103 | + | ||
104 | + def build_answers(submission, form) | ||
105 | + answers = [] | ||
106 | + submission.each do |slug, value| | ||
107 | + field = form.fields.select {|field| field.slug==slug}.first | ||
108 | + if value.kind_of?(String) | ||
109 | + final_value = value | ||
110 | + elsif value.kind_of?(Array) | ||
111 | + final_value = value.join(',') | ||
112 | + elsif value.kind_of?(Hash) | ||
113 | + final_value = value.map {|option, present| present == '1' ? option : nil}.compact.join(',') | ||
114 | + end | ||
115 | + answers << CustomFormsPlugin::Answer.new(:field => field, :value => final_value) | ||
116 | + end | ||
117 | + answers | ||
118 | + end | ||
119 | +end |
plugins/custom_forms/lib/custom_forms_plugin/membership_survey.rb
0 → 100644
@@ -0,0 +1,47 @@ | @@ -0,0 +1,47 @@ | ||
1 | +class CustomFormsPlugin::MembershipSurvey < Task | ||
2 | + | ||
3 | + settings_items :form_id, :submission | ||
4 | + validates_presence_of :form_id | ||
5 | + | ||
6 | + include CustomFormsPlugin::Helper | ||
7 | + | ||
8 | + def perform | ||
9 | + form = CustomFormsPlugin::Form.find(form_id) | ||
10 | + answers = build_answers(submission, form) | ||
11 | + s = CustomFormsPlugin::Submission.create!(:form => form, :profile => target) | ||
12 | + answers.map {|answer| answer.submission = s; answer.save!} | ||
13 | + end | ||
14 | + | ||
15 | + def title | ||
16 | + _("Membership survey") | ||
17 | + end | ||
18 | + | ||
19 | + def subject | ||
20 | + nil | ||
21 | + end | ||
22 | + | ||
23 | + def linked_subject | ||
24 | + nil | ||
25 | + end | ||
26 | + | ||
27 | + def information | ||
28 | + {:message => _('%{requestor} wants you to fill in some information.')} | ||
29 | + end | ||
30 | + | ||
31 | + def accept_details | ||
32 | + true | ||
33 | + end | ||
34 | + | ||
35 | + def icon | ||
36 | + {:type => :profile_image, :profile => requestor, :url => requestor.url} | ||
37 | + end | ||
38 | + | ||
39 | + def target_notification_message | ||
40 | + _('After joining %{requestor}, the administrators of this organization | ||
41 | + wants you to fill in some further information.') % {:requestor => requestor.name} | ||
42 | + end | ||
43 | + | ||
44 | + def target_notification_description | ||
45 | + _('%{requestor} wants to fill in some further information.') % {:requestor => requestor.name} | ||
46 | + end | ||
47 | +end |
plugins/custom_forms/lib/custom_forms_plugin/select_field.rb
0 → 100644
plugins/custom_forms/lib/custom_forms_plugin/submission.rb
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +class CustomFormsPlugin::Submission < Noosfero::Plugin::ActiveRecord | ||
2 | + belongs_to :form, :class_name => 'CustomFormsPlugin::Form' | ||
3 | + belongs_to :profile | ||
4 | + | ||
5 | + has_many :answers, :class_name => 'CustomFormsPlugin::Answer' | ||
6 | + | ||
7 | + validates_presence_of :form | ||
8 | + validates_presence_of :author_name, :author_email, :if => lambda {|submission| submission.profile.nil?} | ||
9 | + validates_uniqueness_of :author_email, :scope => :form_id, :allow_nil => true | ||
10 | + validates_format_of :author_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|submission| !submission.author_email.blank?}) | ||
11 | +end | ||
12 | + |
plugins/custom_forms/lib/custom_forms_plugin/text_field.rb
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +module RoleAssignmentTrigger | ||
2 | + def self.included(base) | ||
3 | + base.class_eval do | ||
4 | + before_create do |ra| | ||
5 | + profile = ra.resource | ||
6 | + person = ra.accessor | ||
7 | + ok = !profile.nil? && !person.nil? && profile.environment.present? | ||
8 | + if ok && profile.environment.plugin_enabled?(CustomFormsPlugin) && !person.is_member_of?(profile) | ||
9 | + CustomFormsPlugin::Form.from(profile).on_memberships.each do |form| | ||
10 | + CustomFormsPlugin::MembershipSurvey.create!(:requestor => profile, :target => person, :form_id => form.id) | ||
11 | + end | ||
12 | + end | ||
13 | + end | ||
14 | + | ||
15 | + after_destroy do |ra| | ||
16 | + profile = ra.resource | ||
17 | + person = ra.accessor | ||
18 | + ok = !profile.nil? && !person.nil? && profile.environment.present? | ||
19 | + if ok && profile.environment.plugin_enabled?(CustomFormsPlugin) && !person.is_member_of?(profile) | ||
20 | + CustomFormsPlugin::Form.from(profile).on_memberships.each do |form| | ||
21 | + task = person.tasks.pending.select {|task| task.kind_of?(CustomFormsPlugin::MembershipSurvey) && task.form_id == form.id}.first | ||
22 | + task.cancel if task | ||
23 | + end | ||
24 | + end | ||
25 | + end | ||
26 | + end | ||
27 | + end | ||
28 | +end | ||
29 | + | ||
30 | +RoleAssignment.send :include, RoleAssignmentTrigger |
plugins/custom_forms/test/unit/custom_forms_plugin/answer_test.rb
0 → 100644
@@ -0,0 +1,38 @@ | @@ -0,0 +1,38 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class CustomFormsPlugin::AnswerTest < ActiveSupport::TestCase | ||
4 | + should 'validates presence of field' do | ||
5 | + answer = CustomFormsPlugin::Answer.new | ||
6 | + answer.valid? | ||
7 | + assert answer.errors.invalid?(:field) | ||
8 | + | ||
9 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
10 | + field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form) | ||
11 | + answer.field = field | ||
12 | + answer.valid? | ||
13 | + assert !answer.errors.invalid?(:field) | ||
14 | + end | ||
15 | + | ||
16 | + should 'belong to a submission' do | ||
17 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
18 | + submission = CustomFormsPlugin::Submission.create!(:form => form, :profile => fast_create(Profile)) | ||
19 | + answer = CustomFormsPlugin::Answer.new | ||
20 | + answer.submission = submission | ||
21 | + | ||
22 | + assert_equal submission, answer.submission | ||
23 | + end | ||
24 | + | ||
25 | + should 'require presence of value if field is mandatory' do | ||
26 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
27 | + field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form, :mandatory => true) | ||
28 | + answer = CustomFormsPlugin::Answer.new(:field => field) | ||
29 | + answer.valid? | ||
30 | + assert answer.errors.invalid?(field.slug.to_sym) | ||
31 | + | ||
32 | + answer.value = "GPL" | ||
33 | + answer.valid? | ||
34 | + assert !answer.errors.invalid?(field.slug.to_sym) | ||
35 | + end | ||
36 | + | ||
37 | +end | ||
38 | + |
plugins/custom_forms/test/unit/custom_forms_plugin/field_test.rb
0 → 100644
@@ -0,0 +1,64 @@ | @@ -0,0 +1,64 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class CustomFormsPlugin::FieldTest < ActiveSupport::TestCase | ||
4 | + should 'validate presence of form' do | ||
5 | + field = CustomFormsPlugin::Field.new | ||
6 | + field.valid? | ||
7 | + assert field.errors.invalid?(:form) | ||
8 | + assert field.errors.invalid?(:name) | ||
9 | + | ||
10 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
11 | + field.form = form | ||
12 | + field.name = 'License' | ||
13 | + field.valid? | ||
14 | + assert !field.errors.invalid?(:form) | ||
15 | + assert !field.errors.invalid?(:name) | ||
16 | + end | ||
17 | + | ||
18 | + should 'set slug before validation based on name' do | ||
19 | + field = CustomFormsPlugin::Field.new(:name => 'Name') | ||
20 | + field.valid? | ||
21 | + assert_equal field.name.to_slug, field.slug | ||
22 | + end | ||
23 | + | ||
24 | + should 'validate uniqueness of slug scoped on the form' do | ||
25 | + form1 = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
26 | + form2 = CustomFormsPlugin::Form.create!(:name => 'Open Source', :profile => fast_create(Profile)) | ||
27 | + f1 = CustomFormsPlugin::Field.create!(:name => 'License', :form => form1) | ||
28 | + f2 = CustomFormsPlugin::Field.new(:name => 'License', :form => form1) | ||
29 | + f3 = CustomFormsPlugin::Field.new(:name => 'License', :form => form2) | ||
30 | + | ||
31 | + f2.valid? | ||
32 | + f3.valid? | ||
33 | + | ||
34 | + assert f2.errors.invalid?(:slug) | ||
35 | + assert !f3.errors.invalid?(:slug) | ||
36 | + end | ||
37 | + | ||
38 | + should 'set mandatory field as false by default' do | ||
39 | + field = CustomFormsPlugin::Field.new | ||
40 | + assert !field.mandatory | ||
41 | + end | ||
42 | + | ||
43 | + should 'have answers' do | ||
44 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
45 | + field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form) | ||
46 | + a1 = CustomFormsPlugin::Answer.create!(:field => field) | ||
47 | + a2 = CustomFormsPlugin::Answer.create!(:field => field) | ||
48 | + | ||
49 | + assert_includes field.answers, a1 | ||
50 | + assert_includes field.answers, a2 | ||
51 | + end | ||
52 | + | ||
53 | + should 'serialize choices into a hash' do | ||
54 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
55 | + field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form) | ||
56 | + field.choices = {'First' => 1, 'Second' => 2, 'Third' => 3} | ||
57 | + field.save! | ||
58 | + | ||
59 | + assert_equal 1, field.choices['First'] | ||
60 | + assert_equal 2, field.choices['Second'] | ||
61 | + assert_equal 3, field.choices['Third'] | ||
62 | + end | ||
63 | +end | ||
64 | + |
plugins/custom_forms/test/unit/custom_forms_plugin/form_test.rb
0 → 100644
@@ -0,0 +1,172 @@ | @@ -0,0 +1,172 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class CustomFormsPlugin::FormTest < ActiveSupport::TestCase | ||
4 | + should 'validates presence of a profile and a name' do | ||
5 | + form = CustomFormsPlugin::Form.new | ||
6 | + form.valid? | ||
7 | + assert form.errors.invalid?(:profile) | ||
8 | + assert form.errors.invalid?(:name) | ||
9 | + | ||
10 | + form.profile = fast_create(Profile) | ||
11 | + form.name = 'Free Software' | ||
12 | + form.valid? | ||
13 | + assert !form.errors.invalid?(:profile) | ||
14 | + assert !form.errors.invalid?(:name) | ||
15 | + end | ||
16 | + | ||
17 | + should 'have many fields including fields subclasses' do | ||
18 | + form = CustomFormsPlugin::Form.create!(:profile => fast_create(Profile), :name => 'Free Software') | ||
19 | + f1 = CustomFormsPlugin::Field.create!(:form => form, :name => 'License') | ||
20 | + f2 = CustomFormsPlugin::Field.create!(:form => form, :name => 'Code') | ||
21 | + f3 = CustomFormsPlugin::TextField.create!(:form => form, :name => 'Developer') | ||
22 | + | ||
23 | + assert_includes form.fields, f1 | ||
24 | + assert_includes form.fields, f2 | ||
25 | + assert_includes form.fields, f3 | ||
26 | + end | ||
27 | + | ||
28 | + should 'have many submissions' do | ||
29 | + form = CustomFormsPlugin::Form.create!(:profile => fast_create(Profile), :name => 'Free Software') | ||
30 | + s1 = CustomFormsPlugin::Submission.create!(:form => form, :profile => fast_create(Profile)) | ||
31 | + s2 = CustomFormsPlugin::Submission.create!(:form => form, :profile => fast_create(Profile)) | ||
32 | + | ||
33 | + assert_includes form.submissions, s1 | ||
34 | + assert_includes form.submissions, s2 | ||
35 | + end | ||
36 | + | ||
37 | + should 'set slug before validation based on name' do | ||
38 | + form = CustomFormsPlugin::Form.new(:name => 'Name') | ||
39 | + form.valid? | ||
40 | + assert_equal form.name.to_slug, form.slug | ||
41 | + end | ||
42 | + | ||
43 | + should 'validates uniqueness of slug scoped on profile' do | ||
44 | + profile = fast_create(Profile) | ||
45 | + another_profile = fast_create(Profile) | ||
46 | + CustomFormsPlugin::Form.create!(:profile => profile, :name => 'Free Software') | ||
47 | + form = CustomFormsPlugin::Form.new(:profile => profile, :name => 'Free Software') | ||
48 | + form.valid? | ||
49 | + assert form.errors.invalid?(:slug) | ||
50 | + | ||
51 | + form.profile = another_profile | ||
52 | + form.valid? | ||
53 | + assert !form.errors.invalid?(:slug) | ||
54 | + end | ||
55 | + | ||
56 | + should 'define form expiration' do | ||
57 | + form = CustomFormsPlugin::Form.new | ||
58 | + assert !form.expired? | ||
59 | + | ||
60 | + form.begining = Time.now + 1.day | ||
61 | + assert form.expired? | ||
62 | + | ||
63 | + form.begining = Time.now - 1.day | ||
64 | + assert !form.expired? | ||
65 | + | ||
66 | + form.begining = nil | ||
67 | + form.ending = Time.now + 1.day | ||
68 | + assert !form.expired? | ||
69 | + | ||
70 | + form.ending = Time.now - 1.day | ||
71 | + assert form.expired? | ||
72 | + | ||
73 | + form.begining = Time.now - 1.day | ||
74 | + form.ending = Time.now + 1.day | ||
75 | + assert !form.expired? | ||
76 | + end | ||
77 | + | ||
78 | + should 'validates format of access' do | ||
79 | + form = CustomFormsPlugin::Form.new | ||
80 | + form.valid? | ||
81 | + assert !form.errors.invalid?(:access) | ||
82 | + | ||
83 | + form.access = 'bli' | ||
84 | + form.valid? | ||
85 | + assert form.errors.invalid?(:access) | ||
86 | + | ||
87 | + form.access = 'logged' | ||
88 | + form.valid? | ||
89 | + assert !form.errors.invalid?(:access) | ||
90 | + | ||
91 | + form.access = 'associated' | ||
92 | + form.valid? | ||
93 | + assert !form.errors.invalid?(:access) | ||
94 | + | ||
95 | + form.access = {:bli => 1} | ||
96 | + form.valid? | ||
97 | + assert form.errors.invalid?(:access) | ||
98 | + | ||
99 | + form.access = 999 | ||
100 | + form.valid? | ||
101 | + assert form.errors.invalid?(:access) | ||
102 | + | ||
103 | + p1 = fast_create(Profile) | ||
104 | + form.access = p1.id | ||
105 | + form.valid? | ||
106 | + assert !form.errors.invalid?(:access) | ||
107 | + | ||
108 | + p2 = fast_create(Profile) | ||
109 | + p3 = fast_create(Profile) | ||
110 | + form.access = [p1,p2,p3].map(&:id) | ||
111 | + form.valid? | ||
112 | + assert !form.errors.invalid?(:access) | ||
113 | + end | ||
114 | + | ||
115 | + should 'defines who is able to access the form' do | ||
116 | + owner = fast_create(Community) | ||
117 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => owner) | ||
118 | + assert form.accessible_to(nil) | ||
119 | + | ||
120 | + form.access = 'logged' | ||
121 | + assert !form.accessible_to(nil) | ||
122 | + person = fast_create(Person) | ||
123 | + assert form.accessible_to(person) | ||
124 | + | ||
125 | + form.access = 'associated' | ||
126 | + assert !form.accessible_to(person) | ||
127 | + owner.add_member(person) | ||
128 | + assert form.accessible_to(person) | ||
129 | + | ||
130 | + p1 = fast_create(Profile) | ||
131 | + form.access = p1.id | ||
132 | + assert !form.accessible_to(person) | ||
133 | + assert form.accessible_to(p1) | ||
134 | + | ||
135 | + p2 = fast_create(Profile) | ||
136 | + form.access = [person.id, p1.id] | ||
137 | + assert form.accessible_to(person) | ||
138 | + assert form.accessible_to(p1) | ||
139 | + assert !form.accessible_to(p2) | ||
140 | + form.access << p2.id | ||
141 | + assert form.accessible_to(p2) | ||
142 | + | ||
143 | + assert form.accessible_to(owner) | ||
144 | + end | ||
145 | + | ||
146 | + should 'have a named_scope that retrieve forms from a profile' do | ||
147 | + profile = fast_create(Profile) | ||
148 | + another_profile = fast_create(Profile) | ||
149 | + f1 = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => profile) | ||
150 | + f2 = CustomFormsPlugin::Form.create!(:name => 'Open Source', :profile => profile) | ||
151 | + f3 = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => another_profile) | ||
152 | + scope = CustomFormsPlugin::Form.from(profile) | ||
153 | + | ||
154 | + assert_equal ActiveRecord::NamedScope::Scope, scope.class | ||
155 | + assert_includes scope, f1 | ||
156 | + assert_includes scope, f2 | ||
157 | + assert_not_includes scope, f3 | ||
158 | + end | ||
159 | + | ||
160 | + should 'have a named_scope that retrieves all forms that are triggered on membership' do | ||
161 | + profile = fast_create(Profile) | ||
162 | + f1 = CustomFormsPlugin::Form.create!(:name => 'On membership 1', :profile => profile, :on_membership => true) | ||
163 | + f2 = CustomFormsPlugin::Form.create!(:name => 'On membership 2', :profile => profile, :on_membership => true) | ||
164 | + f3 = CustomFormsPlugin::Form.create!(:name => 'Not on memberhsip', :profile => profile, :on_membership => false) | ||
165 | + scope = CustomFormsPlugin::Form.from(profile).on_memberships | ||
166 | + | ||
167 | + assert_equal ActiveRecord::NamedScope::Scope, scope.class | ||
168 | + assert_includes scope, f1 | ||
169 | + assert_includes scope, f2 | ||
170 | + assert_not_includes scope, f3 | ||
171 | + end | ||
172 | +end |
plugins/custom_forms/test/unit/custom_forms_plugin/membership_survey_test.rb
0 → 100644
@@ -0,0 +1,31 @@ | @@ -0,0 +1,31 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class CustomFormsPlugin::MembershipSurveyTest < ActiveSupport::TestCase | ||
4 | + should 'validates presence of form_id' do | ||
5 | + task = CustomFormsPlugin::MembershipSurvey.new | ||
6 | + task.valid? | ||
7 | + assert task.errors.invalid?(:form_id) | ||
8 | + | ||
9 | + task.form_id = 1 | ||
10 | + task.valid? | ||
11 | + assert !task.errors.invalid?(:form_id) | ||
12 | + end | ||
13 | + | ||
14 | + should 'create submission with answers on perform' do | ||
15 | + profile = fast_create(Profile) | ||
16 | + person = fast_create(Person) | ||
17 | + form = CustomFormsPlugin::Form.create!(:name => 'Simple Form', :profile => profile) | ||
18 | + field = CustomFormsPlugin::Field.create!(:name => 'Name', :form => form) | ||
19 | + task = CustomFormsPlugin::MembershipSurvey.create!(:form_id => form.id, :submission => {'name' => 'Jack'}, :target => person, :requestor => profile) | ||
20 | + | ||
21 | + assert_difference CustomFormsPlugin::Submission, :count, 1 do | ||
22 | + task.finish | ||
23 | + end | ||
24 | + | ||
25 | + submission = CustomFormsPlugin::Submission.last | ||
26 | + assert_equal submission.answers.count, 1 | ||
27 | + | ||
28 | + answer = submission.answers.first | ||
29 | + assert_equal answer.value, 'Jack' | ||
30 | + end | ||
31 | +end |
plugins/custom_forms/test/unit/custom_forms_plugin/select_field_test.rb
0 → 100644
@@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class CustomFormsPlugin::SelectFieldTest < ActiveSupport::TestCase | ||
4 | + should 'validate presence of choices, multiple and list' do | ||
5 | + select = CustomFormsPlugin::SelectField.new | ||
6 | + select.valid? | ||
7 | + assert select.errors.invalid?(:choices) | ||
8 | + | ||
9 | + select.choices = {'label' => 'value'} | ||
10 | + select.valid? | ||
11 | + assert !select.errors.invalid?(:choices) | ||
12 | + end | ||
13 | +end |
plugins/custom_forms/test/unit/custom_forms_plugin/submission_test.rb
0 → 100644
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class CustomFormsPlugin::SubmissionTest < ActiveSupport::TestCase | ||
4 | + should 'validates presence of form' do | ||
5 | + submission = CustomFormsPlugin::Submission.new | ||
6 | + submission.valid? | ||
7 | + assert submission.errors.invalid?(:form) | ||
8 | + | ||
9 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
10 | + submission.form = form | ||
11 | + submission.valid? | ||
12 | + assert !submission.errors.invalid?(:form) | ||
13 | + end | ||
14 | + | ||
15 | + should 'belong to a profile' do | ||
16 | + profile = fast_create(Profile) | ||
17 | + submission = CustomFormsPlugin::Submission.new | ||
18 | + submission.profile = profile | ||
19 | + assert_equal profile, submission.profile | ||
20 | + end | ||
21 | + | ||
22 | + should 'require presence of author name and email if profile is nil' do | ||
23 | + submission = CustomFormsPlugin::Submission.new | ||
24 | + submission.valid? | ||
25 | + assert submission.errors.invalid?(:author_name) | ||
26 | + assert submission.errors.invalid?(:author_email) | ||
27 | + | ||
28 | + submission.author_name = 'Jack Sparrow' | ||
29 | + submission.author_email = 'jack@black-pearl.com' | ||
30 | + submission.valid? | ||
31 | + assert !submission.errors.invalid?(:author_name) | ||
32 | + assert !submission.errors.invalid?(:author_email) | ||
33 | + end | ||
34 | + | ||
35 | + should 'have answers' do | ||
36 | + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile)) | ||
37 | + field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form) | ||
38 | + submission = CustomFormsPlugin::Submission.create!(:form => form, :profile => fast_create(Profile)) | ||
39 | + a1 = CustomFormsPlugin::Answer.create!(:field => field, :submission => submission) | ||
40 | + a2 = CustomFormsPlugin::Answer.create!(:field => field, :submission => submission) | ||
41 | + | ||
42 | + assert_includes submission.answers, a1 | ||
43 | + assert_includes submission.answers, a2 | ||
44 | + end | ||
45 | +end | ||
46 | + |
plugins/custom_forms/test/unit/ext/role_assingment_test.rb
0 → 100644
@@ -0,0 +1,51 @@ | @@ -0,0 +1,51 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../../test/test_helper' | ||
2 | + | ||
3 | +class RoleAssignmentsTest < ActiveSupport::TestCase | ||
4 | + should 'create membership_surveys on membership creation' do | ||
5 | + environment = Environment.default | ||
6 | + environment.enable_plugin(CustomFormsPlugin) | ||
7 | + organization = fast_create(Organization) | ||
8 | + person = fast_create(Person) | ||
9 | + f1 = CustomFormsPlugin::Form.create!(:profile => organization, :name => 'Form 1', :on_membership => true) | ||
10 | + f2 = CustomFormsPlugin::Form.create!(:profile => organization, :name => 'Form 2', :on_membership => true) | ||
11 | + f3 = CustomFormsPlugin::Form.create!(:profile => organization, :name => 'Form 3', :on_membership => false) | ||
12 | + | ||
13 | + assert_difference CustomFormsPlugin::MembershipSurvey, :count, 2 do | ||
14 | + organization.add_member(person) | ||
15 | + end | ||
16 | + end | ||
17 | + | ||
18 | + should 'create membership_survey on membership creation with form accessible to members only' do | ||
19 | + environment = Environment.default | ||
20 | + environment.enable_plugin(CustomFormsPlugin) | ||
21 | + organization = fast_create(Organization) | ||
22 | + person = fast_create(Person) | ||
23 | + form = CustomFormsPlugin::Form.create!(:profile => organization, :name => 'Form', :on_membership => true, :access => 'associated') | ||
24 | + | ||
25 | + assert_difference CustomFormsPlugin::MembershipSurvey, :count, 1 do | ||
26 | + organization.add_member(person) | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + should 'cancel membership_surveys if membership is undone and task is active' do | ||
31 | + environment = Environment.default | ||
32 | + environment.enable_plugin(CustomFormsPlugin) | ||
33 | + organization = fast_create(Organization) | ||
34 | + person = fast_create(Person) | ||
35 | + form = CustomFormsPlugin::Form.create!(:profile => organization, :name => 'Form', :on_membership => true) | ||
36 | + organization.add_member(person) | ||
37 | + | ||
38 | + assert_difference CustomFormsPlugin::MembershipSurvey.pending, :count, -1 do | ||
39 | + organization.remove_member(person) | ||
40 | + end | ||
41 | + | ||
42 | + organization.add_member(person) | ||
43 | + task = CustomFormsPlugin::MembershipSurvey.last | ||
44 | + task.status = Task::Status::FINISHED | ||
45 | + task.save! | ||
46 | + assert_no_difference CustomFormsPlugin::MembershipSurvey.finished, :count do | ||
47 | + organization.remove_member(person) | ||
48 | + end | ||
49 | + end | ||
50 | +end | ||
51 | + |