diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 9aafd2f..3e26fac 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -24,7 +24,7 @@ if user_signed_in? then @plan = Plan.new authorize @plan - @funders = Org.funder.all + @funders = Org.funders.all respond_to do |format| format.html # new.html.erb diff --git a/app/models/exported_plan.rb b/app/models/exported_plan.rb index cc631e4..05fe0e2 100644 --- a/app/models/exported_plan.rb +++ b/app/models/exported_plan.rb @@ -23,58 +23,55 @@ # TODO: Consider removing the accessor methods, they add no value. The view/controller could # just access the value directly from the project/plan: exported_plan.plan.project.title -=begin # Getters to match Settings::Template::VALID_ADMIN_FIELDS def project_name - - name = self.plan.project.title - name += " - #{self.plan.title}" if self.plan.project.template.phases.count > 1 - name + self.plan.title end def project_identifier - self.plan.project.identifier + self.plan.identifier end def grant_title - self.plan.project.grant_number + self.plan.grant_number end def principal_investigator - self.plan.project.principal_investigator + self.plan.principal_investigator end def project_data_contact - self.plan.project.data_contact + self.plan.data_contact end def project_description - self.plan.project.description + self.plan.description end def funder - org = self.plan.project.template.try(:organisation) + org = self.plan.template.try(:org) org.name if org.present? && org.funder? end def institution - plan.project.org.try(:name) + plan.owner.org.try(:name) end def orcid scheme = IdentifierScheme.find_by(name: 'orcid') - if self.user.nil? + if self.owner.nil? '' else - orcid = self.user.user_identifiers.where(identifier_scheme: scheme).first + orcid = self.owner.user_identifiers.where(identifier_scheme: scheme).first (orcid.nil? ? '' : orcid.identifier) end end -=end +# TODO: This looks like it will always return an empty array as questions is undefined # sections taken from fields settings def sections - sections = self.plan.sections + # TODO: How do we know which phase to use here!? + sections = self.template.phases.first.sections return [] if questions.empty? diff --git a/app/models/plan.rb b/app/models/plan.rb index 11dcf68..f0fda60 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -104,11 +104,12 @@ return answer end +# TODO: This just retrieves all of the guidance associated with the themes within the template +# so why are we transferring it here to the plan? ## # returns all of the sections for this version of the plan, and for the project's organisation # # @return [Array
,nil] either a list of sections, or nil if none were found - def set_possible_guidance_groups # find all the themes in this plan # and get the guidance groups they belong to @@ -154,17 +155,19 @@ end # add in the guidance for the user's org - unless self.owner.org.nil? then - self.owner.org.guidance_groups.each do |group| - group.guidances.each do |guidance| - common_themes = guidance.themes.all & question.themes.all - if common_themes.length > 0 - guidances << { orgname: self.template.org.name, theme: common_themes.join(','), guidance: guidance } + unless self.owner.nil? + unless self.owner.org.nil? then + self.owner.org.guidance_groups.each do |group| + group.guidances.each do |guidance| + common_themes = guidance.themes.all & question.themes.all + if common_themes.length > 0 + guidances << { orgname: self.template.org.name, theme: common_themes.join(','), guidance: guidance } + end end end end end - + # Get guidance by theme from any guidance groups currently selected self.plan_guidance_groups.where(selected: true).each do |pgg| group = pgg.guidance_group @@ -307,7 +310,8 @@ return status end - +# TODO: Guessing this isn't in use since it still refers to Project and Version +=begin ## # defines and returns the details for the plan # details consists of a hash of: project_title, phase_title, and for each section, @@ -343,7 +347,10 @@ end return details end +=end +# TODO: commenting this old lock stuff out since PlanSection is gone and we wanted to get rid of it +=begin ## # determines wether or not a specified section of a plan is locked to a specified user and returns a status hash # @@ -436,7 +443,10 @@ lock.delete end end +=end +# TODO: Commenting out because this method appears below as well so this one is overwritten +=begin ## # returns the time of either the latest answer to any question, or the latest update to the model # @@ -453,7 +463,10 @@ return updated_at end end +=end +# TODO: Guessing this isn't in use since it still refers to Project and Version +=begin ## # returns an array of hashes. Each hash contains the question's id, the answer_id, # the answer_text, the answer_timestamp, and the answer_options @@ -488,7 +501,7 @@ end return section_questions end - +=end ## @@ -502,7 +515,9 @@ - +# TODO: commenting these out because they are overriden by private methods below, so this +# is unreachable +=begin ## # Based on the height of the text gathered so far and the available vertical # space of the pdf, estimate a percentage of how much space has been used. @@ -521,7 +536,7 @@ margin_height = @formatting[:margin][:top].to_i + @formatting[:margin][:bottom].to_i page_height = A4_PAGE_HEIGHT - margin_height # 297mm for A4 portrait - available_height = page_height * self.dmptemplate.settings(:export).max_pages + available_height = page_height * self.template.settings(:export).max_pages percentage = (used_height / available_height) * 100 (percentage / ROUNDING).ceil * ROUNDING # round up to nearest five @@ -555,9 +570,10 @@ (num_lines * font_height) + vertical_margin + leading end +=end - - +# TODO: What are these used for? Should just be using self.org and self.org.funder? +=begin ## # sets a new funder for the project # defaults to the first dmptemplate if the current template is nill and the funder has more than one dmptemplate @@ -567,8 +583,8 @@ def funder_id=(new_funder_id) if new_funder_id != "" then new_funder = Org.find(new_funder_id); - if new_funder.dmptemplates.count >= 1 && self.dmptemplate.nil? then - self.dmptemplate = new_funder.dmptemplates.first + if new_funder.templates.count >= 1 && self.template.nil? then + self.template = new_funder.templates.first end end end @@ -589,11 +605,11 @@ # # @return [Organisation, nil] the funder for project, or nil if none exists def funder - if self.dmptemplate.nil? then + if self.template.nil? then return nil end - template_org = self.dmptemplate.organisation - if template_org.organisation_type.name == constant("organisation_types.funder").downcase + template_org = self.template.org + if template_org.funder? return template_org else return nil @@ -677,7 +693,7 @@ return organisation_id end end - +=end ## # assigns the passed user_id as an editor for the project @@ -706,6 +722,8 @@ add_user(user_id, true, true) end +# TODO: ProjectGroup doesn't exist anymore so commenting these out +=begin ## # returns the projects which the user can atleast read # @@ -738,6 +756,7 @@ return false end end +=end ## # the datetime for the latest update of this plan @@ -784,6 +803,8 @@ self.latest_update.to_date end +# TODO: These next 2 reference defunct models so commenting out +=begin ## # whether or not the plan is shared with anybody # @@ -801,7 +822,9 @@ def template_owner self.dmptemplate.try(:organisation).try(:abbreviation) end - +=end + + private ## diff --git a/app/views/api/v0/statistics/plans.json.jbuilder b/app/views/api/v0/statistics/plans.json.jbuilder index 1a05c9b..fe85ca8 100644 --- a/app/views/api/v0/statistics/plans.json.jbuilder +++ b/app/views/api/v0/statistics/plans.json.jbuilder @@ -1,25 +1,25 @@ json.prettify! -json.plans @org_projects.each do |project| - json.id project.id - json.grant_number project.grant_number - json.org_id project.organisation_id +json.plans @org_projects.each do |plan| + json.id plan.id + json.grant_number plan.grant_number + json.org_id plan.creator.org.id json.template do - json.title project.dmptemplate.title - json.id project.dmptemplate.id + json.title plan.template.title + json.id plan.template.id end json.project do - json.title project.title + json.title plan.title end json.funder do - json.name project.funder_name + json.name (plan.template.org.funder? ? plan.org.name : '') end json.principal_investigator do - json.name project.principal_investigator + json.name plan.principal_investigator end json.data_contact do - json.info project.data_contact + json.info plan.data_contact end - json.description project.description + json.description plan.description end \ No newline at end of file diff --git a/app/views/api/v0/statistics/plans_by_template.json.jbuilder b/app/views/api/v0/statistics/plans_by_template.json.jbuilder index 155bbba..d8d5485 100644 --- a/app/views/api/v0/statistics/plans_by_template.json.jbuilder +++ b/app/views/api/v0/statistics/plans_by_template.json.jbuilder @@ -1,14 +1,14 @@ json.prettify! templates = {} -@org_projects.each do |project| +@org_projects.each do |plan| # if hash exists - if templates[project.dmptemplate.title].blank? - templates[project.dmptemplate.title] = {} - templates[project.dmptemplate.title][:title] = project.dmptemplate.title - templates[project.dmptemplate.title][:id] = project.dmptemplate.id - templates[project.dmptemplate.title][:uses] = 1 + if templates[plan.template.title].blank? + templates[plan.template.title] = {} + templates[plan.template.title][:title] = plan.template.title + templates[plan.template.title][:id] = plan.template.id + templates[plan.template.title][:uses] = 1 else - templates[project.dmptemplate.title][:uses] += 1 + templates[plan.template.title][:uses] += 1 end end diff --git a/test/unit/plan_test.rb b/test/unit/plan_test.rb index f620df6..68a9086 100644 --- a/test/unit/plan_test.rb +++ b/test/unit/plan_test.rb @@ -5,11 +5,19 @@ setup do @org = Org.first @template = Template.first + + @creator = User.last + @administrator = User.create!(email: 'administrator@example.com', password: 'password123') + @editor = User.create!(email: 'editor@example.com', password: 'password123') + @reader = User.create!(email: 'reader@example.com', password: 'password123') + @plan = Plan.create(title: 'Test Plan', template: @template, grant_number: 'Plan12345', identifier: '000912', description: 'This is a test plan', principal_investigator: 'John Doe', principal_investigator_identifier: 'ABC', - data_contact: 'john.doe@example.com', visibility: 1, - roles: [Role.new(user: User.last, creator: true)]) + data_contact: 'john.doe@example.com', visibility: 1) + + @plan.assign_creator(User.last) + @plan.save! end # --------------------------------------------------- @@ -26,14 +34,209 @@ end # --------------------------------------------------- - test "a slug is properly generated when creating a record" do - #p = Plan.create(title: 'Testing 123', template: @template, users: [User.last]) - #assert_equal "testing-123", p.slug + test "dmptemplate returns the template" do + assert_equal @plan.template, @plan.dmptemplate end # --------------------------------------------------- - test "has_sections returns false if there are NO published versions with sections" do - # TODO: build out this test if the has_sections method is actually necessary + test "correctly creates a new answer" do + q = @template.phases.first.sections.last.questions.last + q.answers = [] + q.save! + + answer = @plan.answer(q.id) + assert_equal nil, answer.id, "expected a new Answer" + assert_equal q.default_value, answer.text, "expected the new Answer to use the Default Answer for the Question" + end + + # --------------------------------------------------- + test "correctly retrieves the answer for the question" do + q = @template.phases.first.sections.last.questions.last + answer = @plan.answer(q.id) + answer.text = "testing" + answer.save! + + answr = @plan.answer(q.id) + assert_not answer.id.nil?, "expected the latest Answer" + assert_equal "testing", answer.text, "expected the Answer returned to have the correct text" + end + + # --------------------------------------------------- + test "sets the possible guidance groups" do + @plan.set_possible_guidance_groups + assert_equal @plan.template.guidance_groups, @plan.guidance_groups, "expected the plan to have inherited the template's guidance groups" + end + + # --------------------------------------------------- + test "retrieves the guidance for the specified question" do + template_guidance = @template.org.guidance_groups.collect{|gg| gg.guidances.collect{|g| {orgname: @template.org.name, theme: g.themes.join(','), guidance: g} } }.flatten.uniq + org_guidance = @creator.org.guidance_groups.collect{|gg| gg.guidances.collect{|g| {orgname: @template.org.name, theme: g.themes.join(','), guidance: g} } }.flatten.uniq + plan_guidance = @plan.guidance_groups.collect{|gg| gg.guidances.collect{|g| {orgname: @template.org.name, theme: g.themes.join(','), guidance: g} } }.flatten.uniq + + guidances = @plan.guidance_for_question(@template.phases.first.sections.last.questions.last) + + template_guidance.each do |hash| + assert guidances.include?(hash), "expected the guidance to include the following template guidance: #{hash.inspect}" + end + + org_guidance.each do |hash| + assert guidances.include?(hash), "expected the guidance to include the following org guidance: #{hash.inspect}" + end + + plan_guidance.each do |hash| + assert guidances.include?(hash), "expected the guidance to include the following plan guidance: #{hash.inspect}" + end + end + + # --------------------------------------------------- + test "adds the guidance to a guidance array" do + # TODO: Skipping because the add_guidance_to_array method doesn't seem to be called from anywhere + end + + # --------------------------------------------------- + test "checks whether the specified user can edit the plan" do + @plan.assign_administrator(@administrator) + @plan.assign_editor(@editor) + @plan.assign_reader(@reader) + + # TODO: Should the creator be able to edit? + assert_not @plan.editable_by?(@creator), "expected the creator to NOT be able to edit the plan" + assert @plan.editable_by?(@editor), "expected the editor to be able to edit the plan" + assert_not @plan.editable_by?(@administrator), "expected the administrator to NOT be able to edit the plan" + assert_not @plan.editable_by?(@reader), "expected the reader to NOT be able to edit the plan" + end + + # --------------------------------------------------- + test "checks whether the specified user can read the plan" do + @plan.assign_administrator(@administrator) + @plan.assign_editor(@editor) + @plan.assign_reader(@reader) + + # TODO: Should the creator be able to read? + assert_not @plan.readable_by?(@creator), "expected the creator to NOT be able to read the plan" + assert @plan.readable_by?(@editor), "expected the editor to be able to read the plan" + assert @plan.readable_by?(@administrator), "expected the administrator to be able to read the plan" + assert @plan.readable_by?(@reader), "expected the reader to be able to read the plan" + end + + # --------------------------------------------------- + test "checks whether the specified user can administer the plan" do + @plan.assign_administrator(@administrator) + @plan.assign_editor(@editor) + @plan.assign_reader(@reader) + + # TODO: Should the creator be able to administer? + assert_not @plan.administerable_by?(@creator), "expected the creator to NOT be able to administer the plan" + assert_not @plan.administerable_by?(@editor), "expected the editor to NOT be able to administer the plan" + assert @plan.administerable_by?(@administrator), "expected the administrator to be able to administer the plan" + assert_not @plan.administerable_by?(@reader), "expected the reader to NOT be able to administer the plan" + end + + # --------------------------------------------------- + test "checks that status returns the correct information" do + q = 0 + @template.phases.first.sections.map{|s| q += s.questions.count } + + @plan.answers << Answer.new(user: User.last, text: "testing status", + question: @template.phases.first.sections.first.questions.first) + + hash = @plan.status + + # Expecting the hash to look something like this: + # ----------------------------------------------- + #{"num_questions"=>13, + # "num_answers"=>0, + # "sections"=>{ + # 1=>{"questions"=>[1, 2], "num_questions"=>2, "num_answers"=>0}, + # 2=>{"questions"=>[3], "num_questions"=>1, "num_answers"=>0}}, + # "questions"=>{ + # 1=>{"answer_id"=>nil, "answer_created_at"=>nil, "answer_text"=>nil, + # "answer_option_ids"=>nil, "answered_by"=>nil}, + # 2=>{"answer_id"=>nil, "answer_created_at"=>nil, "answer_text"=>nil, + # "answer_option_ids"=>nil, "answered_by"=>nil}, + # 3=>{"answer_id"=>nil, "answer_created_at"=>nil, "answer_text"=>nil, + # "answer_option_ids"=>nil, "answered_by"=>nil}}, + # "space_used"=>30} + + assert_equal q, hash["num_questions"], "expected the number of questions to match" + assert_equal @plan.answers.count, hash["num_answers"], "expected the number of answers to match" + + @template.phases.first.sections.each do |s| + assert_not hash["sections"][s.id].nil?, "expected section #{s.id} to be in sections portion" + s.questions.each do |q| + assert hash["sections"][s.id]["questions"].include?(q.id), "expected section #{s.id}, question #{q.id} to be in section portion" + + assert_not hash["questions"][q.id].nil?, "expected question #{q.id} to appear in the questions portion" + end + end + end + + # --------------------------------------------------- + test "checks that last updated time is correct" do + now = Time.new + @template.phases.last.updated_at = now + assert_equal now, @plan.latest_update.to_s + end + + # --------------------------------------------------- + test "checks that user is a properly assigned as a creator" do + usr = User.first + @plan.assign_creator(usr) + + assert @plan.administerable_by?(usr), "expected the creator to be able to administer" + assert @plan.editable_by?(usr), "expected the creator to be able to edit" + assert @plan.readable_by?(usr), "expected the creator to be able to read" + end + + # --------------------------------------------------- + test "checks that user is a properly assigned as a editor" do + usr = User.first + @plan.assign_editor(usr) + + assert_not @plan.administerable_by?(usr), "expected the editor to NOT be able to administer" + assert @plan.editable_by?(usr), "expected the editor to be able to edit" + assert @plan.readable_by?(usr), "expected the editor to be able to read" + end + + # --------------------------------------------------- + test "checks that user is a properly assigned as a reader" do + usr = User.first + @plan.assign_reader(usr) + + assert_not @plan.administerable_by?(usr), "expected the reader to NOT be able to administer" + assert_not @plan.editable_by?(usr), "expected the reader to NOT be able to edit" + assert @plan.readable_by?(usr), "expected the reader to be able to read" + end + + # --------------------------------------------------- + test "checks that user is a properly assigned as a adminstrator" do + usr = User.first + @plan.assign_administrator(usr) + + assert @plan.administerable_by?(usr), "expected the adminstrator to be able to administer" + assert @plan.editable_by?(usr), "expected the adminstrator to be able to edit" + assert @plan.readable_by?(usr), "expected the adminstrator to be able to read" + end + + # --------------------------------------------------- + test "name returns the title" do + assert_equal @plan.title, @plan.name + end + + # --------------------------------------------------- + test "owner returns the creator" do + @plan.assign_creator(@creator) + assert_equal @creator, @plan.owner, "expected the owner to match the creator" + + plan = Plan.create!(template: Template.last, title: 'Testing no creator') + assert plan.owner.nil?, "expected a new plan with no creator assigned to return nil" + end + + # --------------------------------------------------- + test "checks that last edited matches the latest_update" do + now = Time.new + @template.phases.last.updated_at = now + assert_equal now.to_date, @plan.last_edited end # ---------------------------------------------------