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 | + |