diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..43d23b3 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,3 @@ +inherit_gem: + rubocop-dmp_roadmap: + - config/default.yml diff --git a/Gemfile b/Gemfile index 74904ab..109bd9c 100644 --- a/Gemfile +++ b/Gemfile @@ -181,15 +181,12 @@ gem 'chromedriver-helper', ">= 1.2.0" end -group :ci do +group :ci, :development do # Security vulnerability scanner for Ruby on Rails. (http://brakemanscanner.org) gem "brakeman" # Automatic Ruby code style checking tool. (https://github.com/rubocop-hq/rubocop) - gem "rubocop" - - # Code style checking for RSpec files (https://github.com/rubocop-hq/rubocop-rspec) - gem "rubocop-rspec" + gem "rubocop-dmp_roadmap" # Helper gem to require bundler-audit (http://github.com/stewartmckee/bundle-audit) gem "bundle-audit" @@ -216,4 +213,8 @@ # help to kill N+1 queries and unused eager loading. (https://github.com/flyerhzm/bullet) gem "bullet" + + gem "yard" + + gem "yard-tomdoc" end diff --git a/Gemfile.lock b/Gemfile.lock index 0a1f14d..827f65f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -315,6 +315,13 @@ rainbow (>= 2.2.2, < 4.0) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) + rubocop-dmp_roadmap (1.0.0) + rubocop (>= 0.58.2) + rubocop-rails_config (>= 0.2.2) + rubocop-rspec (>= 1.27.0) + rubocop-rails_config (0.2.2) + railties (>= 3.0) + rubocop (~> 0.56) rubocop-rspec (1.27.0) rubocop (>= 0.56.0) ruby-progressbar (1.9.0) @@ -356,6 +363,7 @@ rack (>= 1, < 3) thor (0.20.0) thread_safe (0.3.6) + tomparse (0.4.2) tzinfo (1.2.5) thread_safe (~> 0.1) unicode-display_width (1.4.0) @@ -374,6 +382,10 @@ wkhtmltopdf-binary (0.12.3.1) xpath (3.1.0) nokogiri (~> 1.8) + yard (0.9.14) + yard-tomdoc (0.7.1) + tomparse (>= 0.4.0) + yard PLATFORMS ruby @@ -423,7 +435,7 @@ responders (~> 2.0) rspec-collection_matchers rspec-rails - rubocop + rubocop-dmp_roadmap rubocop-rspec ruby_dig selenium-webdriver (>= 3.13.1) @@ -436,6 +448,8 @@ webmock wicked_pdf wkhtmltopdf-binary + yard + yard-tomdoc RUBY VERSION ruby 2.4.4p296 diff --git a/app/controllers/api/v0/base_controller.rb b/app/controllers/api/v0/base_controller.rb index c8edddd..a3c3490 100644 --- a/app/controllers/api/v0/base_controller.rb +++ b/app/controllers/api/v0/base_controller.rb @@ -49,34 +49,39 @@ end private - # returns the resource from the created instance variable - # @return [Object] + + # The resource from the created instance variable + # + # Returns Object def get_resource instance_variable_get("@#{resource_name}") end - # Returns the allowed parameters for searching - # Override this method in each API controller - # to permit additional parameters to search on - # @return [Hash] + # The allowed parameters for searching. Override this method in each API + # controller to permit additional parameters to search on + # + # Returns Hash def query_params {} end - # Returns the allowed parameters for pagination - # @return [Hash] + # The allowed parameters for pagination + # + # Returns Hash def page_params params.permit(:page, :page_size) end # The resource class based on the controller - # @return [Class] + # + # Returns Object def resource_class @resource_class ||= resource_name.classify.constantize end # The singular name for the resource class based on the controller - # @return [String] + # + # Returns String def resource_name @resource_name ||= self.controller_name.singularize end diff --git a/app/controllers/api/v0/statistics_controller.rb b/app/controllers/api/v0/statistics_controller.rb index 8d84bd4..1223121 100644 --- a/app/controllers/api/v0/statistics_controller.rb +++ b/app/controllers/api/v0/statistics_controller.rb @@ -4,11 +4,12 @@ before_action :authenticate # GET /api/v0/statistics/users_joined?start_date=&end_date=&org_id= + # # Returns the number of users joined for the user's org. # If start_date is passed, only counts those with created_at is >= than start_date # If end_date is passed, only counts those with created_at is <= than end_date are - # If org_id is passed and user has super_admin privileges that counter is performed against org_id param instead of user's org - # @return + # If org_id is passed and user has super_admin privileges that counter is performed + # against org_id param instead of user's org def users_joined raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, :statistics).users_joined? @@ -124,9 +125,9 @@ end ## - # GET - # @return the number of DMPs using the specified template between the optional specified dates - # ensures that the template is owned/created by the caller's organisation + # Displays the number of DMPs using the specified template between the optional + # specified dates ensures that the template is owned/created by the caller's + # organisation def using_template org_templates = @user.org.templates.where(customization_of: nil) raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, org_templates.first).using_template? @@ -152,9 +153,9 @@ ## # GET - # @return a list of templates with their titles, ids, and uses between the optional specified dates - # the uses are restricted to DMPs created by users of the same organisation - # as the user who ititiated the call + # Renders a list of templates with their titles, ids, and uses between the optional + # specified dates the uses are restricted to DMPs created by users of the same + # organisation as the user who ititiated the call. def plans_by_template raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans_by_template? org_projects = [] @@ -181,11 +182,11 @@ respond_with @templates end - ## # GET - # @return a list of DMPs metadata, provided the DMPs were created between the optional specified dates - # DMPs must be owned by a user who's organisation is the same as the user - # who generates the call + # + # Renders a list of DMPs metadata, provided the DMPs were created between the + # optional specified dates DMPs must be owned by a user who's organisation is the + # same as the user who generates the call. def plans raise Pundit::NotAuthorizedError unless Api::V0::StatisticsPolicy.new(@user, :statistics).plans? @org_plans = [] @@ -202,32 +203,34 @@ private - ## - # takes in an array of active_reccords and restricts the range of dates - # to those specified in the params - # - # @param objects [Array] any active_reccord reccords which - # have the "created_at" field specified - # @return [Array] filtered list of objects - def restrict_date_range( objects ) - # set start_date to either passed param, or beginning of time - start_date = params[:start_date].blank? ? Date.new(0) : Date.strptime(params[:start_date], "%Y-%m-%d") - # set end_date to either passed param or now - end_date = params[:end_date].blank? ? Date.today : Date.strptime(params[:end_date], "%Y-%m-%d") - filtered = [] - objects.each do |obj| - # apperantly things can have nil created_at - if obj.created_at.blank? - if params[:start_date].blank? && params[:end_date].blank? - filtered += [obj] - end - elsif start_date <= obj.created_at.to_date && end_date >= obj.created_at.to_date + ## + # Takes in an array of active_reccords and restricts the range of dates + # to those specified in the params + # + # objects - any active_reccord reccords which have the "created_at" field specified + # + # Returns Array + def restrict_date_range( objects ) + # set start_date to either passed param, or beginning of time + start_date = params[:start_date].blank? ? Date.new(0) : Date.strptime(params[:start_date], "%Y-%m-%d") + # set end_date to either passed param or now + end_date = params[:end_date].blank? ? Date.today : Date.strptime(params[:end_date], "%Y-%m-%d") + + filtered = [] + objects.each do |obj| + # apperantly things can have nil created_at + if obj.created_at.blank? + if params[:start_date].blank? && params[:end_date].blank? filtered += [obj] end + elsif start_date <= obj.created_at.to_date && end_date >= obj.created_at.to_date + filtered += [obj] end - return filtered end + return filtered + end + end end end diff --git a/app/controllers/api/v0/templates_controller.rb b/app/controllers/api/v0/templates_controller.rb index 03999f8..b1dea9f 100644 --- a/app/controllers/api/v0/templates_controller.rb +++ b/app/controllers/api/v0/templates_controller.rb @@ -4,9 +4,9 @@ before_action :authenticate - ## # GET - # @return a list of templates ordered by organisation + # + # Renders a list of templates ordered by organisation def index # check if the user has permissions to use the templates API raise Pundit::NotAuthorizedError unless Api::V0::TemplatePolicy.new(@user, :guidance_group).index? diff --git a/app/controllers/concerns/conditional_user_mailer.rb b/app/controllers/concerns/conditional_user_mailer.rb index d8bc509..560b93f 100644 --- a/app/controllers/concerns/conditional_user_mailer.rb +++ b/app/controllers/concerns/conditional_user_mailer.rb @@ -5,13 +5,11 @@ # Executes a given block passed if the recipient user has the preference # email key enabled # - # @param recipients {User | Enumerable } User object or any object that - # includes Enumerable class + # recipients - User or Enumerable object or any object that includes Enumerable class + # key - A key (dot notation) whose value is true/false and belongs to + # prefences.email (see config/branding.yml) # - # @param key {String} - A key (dot notation) whose value is true/false and - # belongs to prefences.email (see config/branding.yml) - # - # Returns true or false + # Returns Boolean def deliver_if(recipients: [], key:, &block) return false unless block_given? diff --git a/app/controllers/concerns/versionable.rb b/app/controllers/concerns/versionable.rb index aa633d7..c1893e9 100644 --- a/app/controllers/concerns/versionable.rb +++ b/app/controllers/concerns/versionable.rb @@ -1,11 +1,12 @@ module Versionable - ## # Takes in a Template, phase, Section, Question, or Annotaion # IF the template is published, generates a new template # finds the passed object in the new template - # @param obj - Template, Phase, Section, Question, Annotation - # @return type_of(obj) + # + # obj - Template, Phase, Section, Question, Annotation + # + # Returns ActiveRecord::Base def get_modifiable(obj) if obj.respond_to?(:template) template = obj.template diff --git a/app/controllers/passwords_controller.rb b/app/controllers/passwords_controller.rb index 9116fb1..fc23f4b 100644 --- a/app/controllers/passwords_controller.rb +++ b/app/controllers/passwords_controller.rb @@ -1,17 +1,18 @@ class PasswordsController < Devise::PasswordsController - + protected - + def after_resetting_password_path_for(resource) root_path end - + ## # Override Devise default behaviour by sending user to the home page # after the password reset email has been sent # - # @resource_name [String] The user's email address - # --------------------------------------------------------------------- + # resource_name - The user's email address + # + # Returns String def after_sending_reset_password_instructions_path_for(resource_name) root_path end diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 2a5514e..ad44829 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -162,19 +162,9 @@ plan, phase = Plan.load_for_phase(params[:id], params[:phase_id]) - readonly = !plan.editable_by?(current_user.id) - guidance_groups = GuidanceGroup.where(published: true, id: plan.guidance_group_ids) - # Since the answers have been pre-fetched through plan (see Plan.load_for_phase) - # we create a hash whose keys are question id and value is the answer associated - answers = plan.answers.reduce({}){ |m, a| m[a.question_id] = a; m } - render('/phases/edit', locals: { - base_template_org: phase.template.base_org, - plan: plan, phase: phase, readonly: readonly, - guidance_groups: guidance_groups, - answers: answers, - guidance_service: GuidanceService.new(plan) }) + render_phases_edit(plan, phase, guidance_groups) end # PUT /plans/1 @@ -196,13 +186,13 @@ format.json {render json: {code: 1, msg: success_message(_('plan'), _('saved'))}} else flash[:alert] = failed_update_error(@plan, _('plan')) - format.html { render action: "edit" } + format.html { render_phases_edit(@plan, @plan.phases.first, @plan.guidance_groups) } format.json {render json: {code: 0, msg: flash[:alert]}} end rescue Exception flash[:alert] = failed_update_error(@plan, _('plan')) - format.html { render action: "edit" } + format.html { render_phases_edit(@plan, @plan.phases.first, @plan.guidance_groups) } format.json {render json: {code: 0, msg: flash[:alert]}} end end @@ -263,9 +253,13 @@ @plan = Plan.includes(:answers).find(params[:id]) authorize @plan + @selected_phase = @plan.phases.find(params[:phase_id]) + @show_coversheet = params[:export][:project_details].present? @show_sections_questions = params[:export][:question_headings].present? @show_unanswered = params[:export][:unanswered_questions].present? + @show_custom_sections = params[:export][:custom_sections].present? + @public_plan = false @hash = @plan.as_pdf(@show_coversheet) @@ -275,7 +269,7 @@ respond_to do |format| format.html { render layout: false } - format.csv { send_data @plan.as_csv(@show_sections_questions), filename: "#{file_name}.csv" } + format.csv { send_data @plan.as_csv(@show_sections_questions, @show_unanswered, @selected_phase, @show_custom_sections), filename: "#{file_name}.csv" } format.text { send_data render_to_string(partial: 'shared/export/plan_txt'), filename: "#{file_name}.txt" } format.docx { render docx: "#{file_name}.docx", content: render_to_string(partial: 'shared/export/plan') } format.pdf do @@ -431,7 +425,7 @@ # Flash notice for successful feedback requests # - # @return [String] + # Returns String def request_feedback_flash_notice # Use the generic feedback confirmation message unless the Org has # specified one @@ -439,4 +433,23 @@ feedback_confirmation_default_message feedback_constant_to_text(text, current_user, @plan, current_user.org) end + + private + + # ============================ + # = Private instance methods = + # ============================ + + def render_phases_edit(plan, phase, guidance_groups) + readonly = !plan.editable_by?(current_user.id) + # Since the answers have been pre-fetched through plan (see Plan.load_for_phase) + # we create a hash whose keys are question id and value is the answer associated + answers = plan.answers.reduce({}){ |m, a| m[a.question_id] = a; m } + render('/phases/edit', locals: { + base_template_org: phase.template.base_org, + plan: plan, phase: phase, readonly: readonly, + guidance_groups: guidance_groups, + answers: answers, + guidance_service: GuidanceService.new(plan) }) + end end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index f578bb7..0231a97 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -5,8 +5,8 @@ @user = current_user @prefs = @user.get_preferences(:email) @languages = Language.sorted_by_abbreviation - @orgs = Org.where(parent_id: nil).order("name") - @other_organisations = Org.where(parent_id: nil, is_other: true).pluck(:id) + @orgs = Org.order("name") + @other_organisations = Org.where(is_other: true).pluck(:id) @identifier_schemes = IdentifierScheme.where(active: true).order(:name) @default_org = current_user.org @@ -102,9 +102,9 @@ def update if user_signed_in? then @prefs = @user.get_preferences(:email) - @orgs = Org.where(parent_id: nil).order("name") + @orgs = Org.order("name") @default_org = current_user.org - @other_organisations = Org.where(parent_id: nil, is_other: true).pluck(:id) + @other_organisations = Org.where(is_other: true).pluck(:id) @identifier_schemes = IdentifierScheme.where(active: true).order(:name) @languages = Language.sorted_by_abbreviation if params[:skip_personal_details] == "true" diff --git a/app/controllers/super_admin/users_controller.rb b/app/controllers/super_admin/users_controller.rb index c0640a3..9cddb77 100644 --- a/app/controllers/super_admin/users_controller.rb +++ b/app/controllers/super_admin/users_controller.rb @@ -8,37 +8,37 @@ if user.present? authorize user languages = Language.sorted_by_abbreviation - orgs = Org.where(parent_id: nil).order("name") + orgs = Org.order("name") identifier_schemes = IdentifierScheme.where(active: true).order(:name) - - render 'super_admin/users/edit', - locals: { user: user, + + render 'super_admin/users/edit', + locals: { user: user, languages: languages, - orgs: orgs, - identifier_schemes: identifier_schemes, + orgs: orgs, + identifier_schemes: identifier_schemes, default_org: user.org } else redirect_to admin_index_users_path, alert: _('User not found.') end end - + def update user = User.find(params[:id]) if user.present? authorize user topic = _('%{username}\'s profile') % { username: user.name(false) } if user.update_attributes(user_params) - redirect_to edit_super_admin_user_path(user), + redirect_to edit_super_admin_user_path(user), notice: _('Successfully updated %{username}') % { username: topic } else - redirect_to edit_super_admin_user_path(user), + redirect_to edit_super_admin_user_path(user), alert: _('Unable to update %{username}') % { username: topic } end else redirect_to edit_super_admin_user_path(user), alert: _('User not found.') end end - + private def user_params params.require(:user).permit(:email, :firstname, :surname, :org_id, :language_id, :other_organisation) diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index 38719f9..c9aa43e 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -8,27 +8,26 @@ handle_omniauth(scheme) end end - - ## - # Processes callbacks from an omniauth provider and directs the user to + + # Processes callbacks from an omniauth provider and directs the user to # the appropriate page: # Not logged in and uid had no match ---> Sign Up page # Not logged in and uid had a match ---> Sign In and go to Home Page # Signed in and uid had no match --> Save the uid and go to the Profile Page # Signed in and uid had a match --> Go to the Home Page # - # @scheme [IdentifierScheme] The IdentifierScheme for the provider - # ------------------------------------------------------------- + # scheme - The IdentifierScheme for the provider + # def handle_omniauth(scheme) user = User.from_omniauth(request.env["omniauth.auth"].nil? ? request.env : request.env["omniauth.auth"]) - + # If the user isn't logged in - if current_user.nil? + if current_user.nil? # If the uid didn't have a match in the system send them to register if user.nil? session["devise.#{scheme.name.downcase}_data"] = request.env["omniauth.auth"] redirect_to new_user_registration_url - + # Otherwise sign them in else # Until ORCID becomes supported as a login method @@ -40,20 +39,20 @@ redirect_to new_user_registration_url end end - + # The user is already logged in and just registering the uid with us else # If the user could not be found by that uid then attach it to their record if user.nil? - if UserIdentifier.create(identifier_scheme: scheme, + if UserIdentifier.create(identifier_scheme: scheme, identifier: request.env["omniauth.auth"].uid, user: current_user) - + flash[:notice] = _('Your account has been successfully linked to %{scheme}.') % { scheme: scheme.description } else flash[:alert] = _('Unable to link your account to %{scheme}.') % { scheme: scheme.description } end - + else # If a user was found but does NOT match the current user then the identifier has # already been attached to another account (likely the user has 2 accounts) @@ -61,8 +60,8 @@ if identifier.user.id != current_user.id flash[:alert] = _("The current #{scheme.description} iD has been already linked to a user with email #{identifier.user.email}") end - - # Otherwise, the identifier was found and it matches the one already associated + + # Otherwise, the identifier was found and it matches the one already associated # with the current user so nothing else needs to be done end @@ -71,7 +70,6 @@ end end - # ------------------------------------------------------------- def failure redirect_to root_path end diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 9ee9a66..34d20de 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -1,6 +1,8 @@ module NotificationsHelper - # Return FA html class depending on Notification level - # @return [String] Font Awesome HTML class + + # FA html class depending on Notification level + # + # Returns String def fa_classes(notification) case notification.level when 'warning' diff --git a/app/helpers/orgs_helper.rb b/app/helpers/orgs_helper.rb index f106fa1..a2be874 100644 --- a/app/helpers/orgs_helper.rb +++ b/app/helpers/orgs_helper.rb @@ -1,12 +1,14 @@ +# frozen_string_literal: true + module OrgsHelper - # frozen_string_literal: true DEFAULT_EMAIL = '%{organisation_email}' # Tooltip string for Org feedback form. # - # @param org [Org] The current Org we're updating feedback form for. - # @return [String] The tooltip message + # org - The current Org we're updating feedback form for. + # + # Returns String def tooltip_for_org_feedback_form(org) email = org.contact_email.presence || DEFAULT_EMAIL _("SAMPLE MESSAGE: A data librarian from %{org_name} will respond to your request within 48 diff --git a/app/helpers/plans_helper.rb b/app/helpers/plans_helper.rb index b726508..f761b11 100644 --- a/app/helpers/plans_helper.rb +++ b/app/helpers/plans_helper.rb @@ -42,4 +42,15 @@ return _('Private: restricted to me and people I invite.') end end + + def download_plan_page_title(plan, phase, hash) + # If there is more than one phase show the plan title and phase title + return hash[:phases].many? ? "#{plan.title} - #{phase[:title]}" : plan.title + end + + def display_questions_and_section_headings(section, show_sections_questions, show_custom_sections) + # Return true if show_sections_questions is true and either section not customised, or section is customised + # and show_custom_sections is true + return show_sections_questions && (!section[:modifiable] || (show_custom_sections && section[:modifiable])) + end end diff --git a/app/helpers/sections_helper.rb b/app/helpers/sections_helper.rb index 785b6b1..6b16842 100644 --- a/app/helpers/sections_helper.rb +++ b/app/helpers/sections_helper.rb @@ -2,11 +2,11 @@ # HREF attribute value for headers in the section partials. If the section # is modifiable, returns the section path, otherwise the edit section path. # - # @param section [Section] The section to return a URL for - # @param phase [Phase] The phase that section belongs - # @param template [Template] The template that phase belongs to + # section - The section to return a URL for + # phase - The phase that section belongs + # template - The template that phase belongs to # - # @return String + # Returns String def header_path_for_section(section, phase, template) if section.modifiable? edit_org_admin_template_phase_section_path(template_id: template.id, diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index d459b3e..525773b 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -108,8 +108,8 @@ end end - # @param commenter - User who wrote the comment - # @param plan - Plan for which the comment is associated to + # commenter - User who wrote the comment + # plan - Plan for which the comment is associated to def new_comment(commenter, plan) if commenter.is_a?(User) && plan.is_a?(Plan) owner = plan.owner diff --git a/app/models/annotation.rb b/app/models/annotation.rb index 5cad46d..6c7d7b5 100644 --- a/app/models/annotation.rb +++ b/app/models/annotation.rb @@ -58,11 +58,11 @@ # = Class Methods = # ================= - ## - # deep copy the given annotation and all it's associations + # Deep copy the given annotation and all it's associations # - # @params [Annotation] annotation to be deep copied - # @return [Annotation] the saved, copied annotation + # annotation - To be deep copied + # + # Returns Annotation def self.deep_copy(annotation) annotation_copy = annotation.dup annotation_copy.save! @@ -73,10 +73,9 @@ # = Public instance methods = # =========================== - ## - # returns the text from the annotation + # The text from the annotation # - # @return [String] the text from the annotation + # Returns String def to_s "#{text}" end diff --git a/app/models/answer.rb b/app/models/answer.rb index 22b9a09..738dc5d 100644 --- a/app/models/answer.rb +++ b/app/models/answer.rb @@ -65,8 +65,9 @@ ## # deep copy the given answer # - # @params [Answer] question_option to be deep copied - # @return [Answer] the saved, copied answer + # answer - question_option to be deep copied + # + # Returns Answer def self.deep_copy(answer) answer_copy = answer.dup answer.question_options.each do |opt| @@ -75,14 +76,19 @@ answer_copy end - # This method helps to decide if an answer option (:radiobuttons, :checkbox, etc ) in form views should be checked or not - # Returns true if the given option_id is present in question_options, otherwise returns false + # This method helps to decide if an answer option (:radiobuttons, :checkbox, etc ) in + # form views should be checked or not + # + # Returns Boolean def has_question_option(option_id) self.question_option_ids.include?(option_id) end - # Returns true if the answer is valid and false otherwise. If the answer's question is option_based, it is checked if exist - # any question_option selected. For non option_based (e.g. textarea or textfield), it is checked the presence of text + # If the answer's question is option_based, it is checked if exist any question_option + # selected. For non option_based (e.g. textarea or textfield), it is checked the + # presence of text + # + # Returns Boolean def is_valid? if self.question.present? if self.question.question_format.option_based? @@ -94,16 +100,17 @@ return false end - # Returns answer notes whose archived is blank sorted by updated_at in descending order + # Answer notes whose archived is blank sorted by updated_at in descending order + # + # Returns Array def non_archived_notes return notes.select{ |n| n.archived.blank? }.sort!{ |x,y| y.updated_at <=> x.updated_at } end - ## - # Returns True if answer text is blank, false otherwise - # specificly we want to remove empty hml tags and check + # Returns True if answer text is blank, false otherwise specificly we want to remove + # empty hml tags and check. # - # @return [Boolean] is the answer's text blank + # Returns Boolean def is_blank? if self.text.present? return self.text.gsub(/<\/?p>/, '').gsub(//, '').chomp.blank? @@ -112,14 +119,10 @@ return true end - ## - # Returns the parsed JSON hash for the current answer object - # Generates a new hash if none exists for rda_questions + # The parsed JSON hash for the current answer object. Generates a new hash if none + # exists for rda_questions. # - # @return [Hash] the parsed hash of the answer. - # Should have keys 'standards', 'text' - # 'standards' is a list of : pairs - # 'text' is the text from the comments box + # Returns Hash def answer_hash default = {'standards' => {}, 'text' => ''} begin @@ -131,12 +134,13 @@ end ## - # Given a hash of standards and a comment value, this updates answer - # text for rda_questions + # Given a hash of standards and a comment value, this updates answer text for + # rda_questions # - # @param [standards] a hash of standards - # @param [text] option comment text - # nothing returned, but the status of the text field of the answer is changed + # standards - A Hash of standards + # text - A String with option comment text + # + # Returns String def update_answer_hash(standards={},text="") h = {} h['standards'] = standards diff --git a/app/models/concerns/exportable_plan.rb b/app/models/concerns/exportable_plan.rb index 37af160..6a6fdde 100644 --- a/app/models/concerns/exportable_plan.rb +++ b/app/models/concerns/exportable_plan.rb @@ -4,11 +4,11 @@ prepare(coversheet) end - def as_csv(headings = true, unanswered = true) + def as_csv(headings = true, unanswered = true, selected_phase = nil, show_custom_sections = true) hash = prepare(false) CSV.generate do |csv| - hdrs = (hash[:phases].length > 1 ? [_('Phase')] : []) + hdrs = (hash[:phases].many? ? [_('Phase')] : []) if headings hdrs << [_('Section'),_('Question'),_('Answer')] else @@ -17,23 +17,30 @@ csv << hdrs.flatten hash[:phases].each do |phase| - phase[:sections].each do |section| - section[:questions].each do |question| - answer = self.answer(question[:id], false) - answer_text = answer.present? ? answer.text : (unanswered ? _('Not Answered') : '') - flds = (hash[:phases].length > 1 ? [phase[:title]] : []) - if headings - if question[:text].is_a? String - question_text = question[:text] - else - question_text = (question[:text].length > 1 ? question[:text].join(', ') : question[:text][0]) + if selected_phase.nil? || phase[:title] == selected_phase.title + phase[:sections].each do |section| + # Return true if either section not customised, or section is customised + # and unanswered is true + if !section[:modifiable] || (show_custom_sections && section[:modifiable]) + section[:questions].each do |question| + answer = self.answer(question[:id], false) + if answer.present? || (answer.blank? && unanswered) + answer_text = answer.present? ? answer.text : (unanswered ? _('Not Answered') : '') + flds = (hash[:phases].many? ? [phase[:title]] : []) + if headings + if question[:text].is_a? String + question_text = question[:text] + else + question_text = (question[:text].many? ? question[:text].join(', ') : question[:text][0]) + end + flds << [ section[:title], sanitize_text(question_text), sanitize_text(answer_text) ] + else + flds << [ sanitize_text(answer_text) ] + end + csv << flds.flatten + end end - flds << [ section[:title], sanitize_text(question_text), sanitize_text(answer_text) ] - else - flds << [ sanitize_text(answer_text) ] end - - csv << flds.flatten end end end @@ -56,7 +63,7 @@ template.phases.each do |phase| phs = { title: phase.title, number: phase.number, sections: [] } phase.sections.each do |section| - sctn = { title: section.title, number: section.number, questions: [] } + sctn = { title: section.title, number: section.number, questions: [], modifiable: section.modifiable } section.questions.each do |question| txt = question.text sctn[:questions] << { id: question.id, text: txt, format: question.question_format } diff --git a/app/models/guidance.rb b/app/models/guidance.rb index 4258326..602e7ad 100644 --- a/app/models/guidance.rb +++ b/app/models/guidance.rb @@ -12,7 +12,6 @@ # created_at :datetime not null # updated_at :datetime not null # guidance_group_id :integer -# question_id :integer # # Indexes # @@ -72,17 +71,16 @@ # = Class methods = # ================= - ## # Returns whether or not a given user can view a given guidance # we define guidances viewable to a user by those owned by a guidance group: # owned by the managing curation center # owned by a funder organisation # owned by an organisation, of which the user is a member # - # @param id [Integer] the integer id for a guidance - # @param user [User] a user object - # @return [Boolean] true if the specified user can view the specified - # guidance, false otherwise + # id - The Integer id for a guidance + # user - A User object + # + # Returns Boolean def self.can_view?(user, id) guidance = Guidance.find_by(id: id) viewable = false @@ -109,15 +107,15 @@ return viewable end - ## # Returns a list of all guidances which a specified user can view # we define guidances viewable to a user by those owned by a guidance group: # owned by the Managing Curation Center # owned by a funder organisation # owned by an organisation, of which the user is a member # - # @param user [User] a user object - # @return [Array<Guidance>] a list of all "viewable" guidances to a user + # user - A User object + # + # Returns Array def self.all_viewable(user) managing_groups = Org.includes(guidance_groups: :guidances) .managing_orgs.collect{|o| o.guidance_groups} @@ -138,13 +136,12 @@ return all_viewable_guidances.flatten end - ## # Determine if a guidance is in a group which belongs to a specified # organisation # - # @param org_id [Integer] the integer id for an organisation - # @return [Boolean] true if this guidance is in a group belonging to the - # specified organisation, false otherwise + # org_id - The Integer id for an organisation + # + # Returns Boolean def in_group_belonging_to?(org_id) unless guidance_group.nil? if guidance_group.org.id == org_id diff --git a/app/models/guidance_group.rb b/app/models/guidance_group.rb index 36d780d..3a63430 100644 --- a/app/models/guidance_group.rb +++ b/app/models/guidance_group.rb @@ -21,6 +21,7 @@ # # fk_rails_... (org_id => orgs.id) # + class GuidanceGroup < ActiveRecord::Base include GlobalHelpers include ValidationValues @@ -70,17 +71,16 @@ # = Class methods = # ================= - ## - # Returns whether or not a given user can view a given guidance group + # Whether or not a given user can view a given guidance group # we define guidances viewable to a user by those owned by: # the managing curation center # a funder organisation # an organisation, of which the user is a member # - # @param id [Integer] the integer id for a guidance group - # @param user [User] a user object - # @return [Boolean] true if the specified user can view the specified - # guidance group, false otherwise + # id - The integer id for a guidance group + # user - A User object + # + # Returns Boolean def self.can_view?(user, guidance_group) viewable = false # groups are viewable if they are owned by any of the user's organisations @@ -95,16 +95,16 @@ viewable end - ## - # Returns a list of all guidance groups which a specified user can view + + # A list of all guidance groups which a specified user can view # we define guidance groups viewable to a user by those owned by: # the Managing Curation Center # a funder organisation # an organisation, of which the user is a member # - # @param user [User] a user object - # @return [Array<GuidanceGroup>] a list of all "viewable" guidance groups to - # a user + # user - A User object + # + # Returns Array def self.all_viewable(user) # first find all groups owned by the Managing Curation Center managing_org_groups = Org.includes(guidance_groups: [guidances: :themes]) @@ -118,7 +118,7 @@ organisation_groups = [user.org.guidance_groups] # pass this organisation guidance groups to the view with respond_with - # @all_viewable_groups + # all_viewable_groups all_viewable_groups = managing_org_groups + funder_groups + organisation_groups diff --git a/app/models/notification.rb b/app/models/notification.rb index b5a6962..dd6a17d 100644 --- a/app/models/notification.rb +++ b/app/models/notification.rb @@ -69,7 +69,8 @@ # Has the Notification been acknowledged by the given user ? # If no user is given, currently logged in user (if any) is the default - # @return [Boolean] is the Notification acknowledged ? + # + # Returns Boolean def acknowledged?(user) dismissable? && user.present? && users.include?(user) end diff --git a/app/models/org.rb b/app/models/org.rb index 881f990..f97042c 100644 --- a/app/models/org.rb +++ b/app/models/org.rb @@ -4,7 +4,6 @@ # # id :integer not null, primary key # abbreviation :string -# banner_text :text # contact_email :string # contact_name :string # feedback_email_msg :text @@ -12,18 +11,15 @@ # feedback_enabled :boolean default(FALSE) # is_other :boolean default(FALSE), not null # links :text -# logo_file_name :string # logo_name :string # logo_uid :string # name :string # org_type :integer default(0), not null # sort_name :string # target_url :string -# wayfless_entity :string # created_at :datetime not null # updated_at :datetime not null # language_id :integer -# parent_id :integer # region_id :integer # # Foreign Keys @@ -137,7 +133,9 @@ # What do they do? do they do it efficiently, and do we need them? # Determines the locale set for the organisation - # @return String or nil + # + # Returns String + # Returns nil def get_locale if !self.language.nil? return self.language.abbreviation @@ -146,16 +144,14 @@ end end -# TODO: Should these be hardcoded? Also, an Org can currently be multiple org_types at one time. -# For example you can do: funder = true; project = true; school = true -# Calling type in the above scenario returns "Funder" which is a bit misleading -# Is FlagShihTzu's Bit flag the appropriate structure here or should we use an enum? -# Tests are setup currently to work with this issue. - ## - # returns the name of the type of the organisation as a string - # defaults to none if no org type present + # TODO: Should these be hardcoded? Also, an Org can currently be multiple org_types at + # one time. For example you can do: funder = true; project = true; school = true # - # @return [String] + # Calling type in the above scenario returns "Funder" which is a bit misleading + # Is FlagShihTzu's Bit flag the appropriate structure here or should we use an enum? + # Tests are setup currently to work with this issue. + # + # Returns String def org_type_to_s ret = [] ret << "Institution" if self.institution? @@ -172,17 +168,17 @@ end ## - # returns the name of the organisation + # The name of the organisation # - # @return [String] + # Returns String def to_s name end ## - # returns the abbreviation for the organisation if it exists, or the name if not + # The abbreviation for the organisation if it exists, or the name if not # - # @return [String] name or abbreviation of the organisation + # Returns String def short_name if abbreviation.nil? then return name @@ -192,9 +188,9 @@ end ## - # returns all published templates belonging to the organisation + # All published templates belonging to the organisation # - # @return [Array<Template>] published templates + # Returns ActiveRecord::Relation def published_templates return templates.where("published = ?", true) end diff --git a/app/models/phase.rb b/app/models/phase.rb index 41a985b..58a466d 100644 --- a/app/models/phase.rb +++ b/app/models/phase.rb @@ -6,7 +6,6 @@ # description :text # modifiable :boolean # number :integer -# slug :string # title :string # created_at :datetime # updated_at :datetime diff --git a/app/models/plan.rb b/app/models/plan.rb index 04e7642..434cbbe 100644 --- a/app/models/plan.rb +++ b/app/models/plan.rb @@ -21,7 +21,6 @@ # principal_investigator_email :string # principal_investigator_identifier :string # principal_investigator_phone :string -# slug :string # title :string # visibility :integer default(3), not null # created_at :datetime @@ -36,6 +35,7 @@ # # fk_rails_... (template_id => templates.id) # + class Plan < ActiveRecord::Base include ConditionalUserMailer include ExportablePlan @@ -194,8 +194,9 @@ # deep copy the given plan and all of it's associations # - # @params [Plan] plan to be deep copied - # @return [Plan] saved copied plan + # plan - Plan to be deep copied + # + # Returns Plan def self.deep_copy(plan) plan_copy = plan.dup plan_copy.title = "Copy of " + plan.title @@ -229,15 +230,15 @@ template&.settings(key) end - ## - # returns the most recent answer to the given question id - # optionally can create an answer if none exists + # The most recent answer to the given question id optionally can create an answer if + # none exists. # - # @param qid [Integer] the id for the question to find the answer for - # @param create_if_missing [Boolean] if true, will genereate a default answer - # to the question. - # @return [Answer,nil] the most recent answer to the question, or a new - # question with default value, or nil. + # qid - The id for the question to find the answer for + # create_if_missing - If true, will genereate a default answer + # to the question (defaults: true). + # + # Returns Answer + # Returns nil def answer(qid, create_if_missing = true) answer = answers.where(question_id: qid).order("created_at DESC").first question = Question.find(qid) @@ -331,8 +332,9 @@ ## # determines if the plan is editable by the specified user # - # @param user_id [Integer] the id for a user - # @return [Boolean] true if user can edit the plan + # user_id - The id for a user + # + # Returns Boolean def editable_by?(user_id) user_id = user_id.id if user_id.is_a?(User) role?(user_id, :editor) @@ -341,8 +343,9 @@ ## # determines if the plan is readable by the specified user # - # @param user_id [Integer] the id for a user - # @return [Boolean] true if the user can read the plan + # user_id - The Integer id for a user + # + # Returns Boolean def readable_by?(user_id) user = user_id.is_a?(User) ? user_id : User.find(user_id) owner_orgs = owner_and_coowners.collect(&:org) @@ -363,58 +366,57 @@ false end - ## - # determines if the plan is readable by the specified user + # determines if the plan is readable by the specified user. # - # @param user_id [Integer] the id for a user - # @return [Boolean] true if the user can read the plan + # user_id - The Integer id for a user + # + # Returns Boolean def commentable_by?(user_id) user_id = user_id.id if user_id.is_a?(User) role?(user_id, :commenter) end - ## # determines if the plan is administerable by the specified user # - # @param user_id [Integer] the id for the user - # @return [Boolean] true if the user can administer the plan + # user_id - The Integer id for the user + # + # Returns Boolean def administerable_by?(user_id) user_id = user_id.id if user_id.is_a?(User) role?(user_id, :administrator) end - ## # determines if the plan is reviewable by the specified user # - # @param user_id [Integer] the id for the user - # @return [Boolean] true if the user can administer the plan + # user_id - The Integer id for the user + # + # Returns Boolean def reviewable_by?(user_id) user_id = user_id.id if user_id.is_a?(User) role?(user_id, :reviewer) end - ## # Assigns the passed user_id to the creater_role for the project gives the # user rights to read, edit, administrate, and defines them as creator # - # @param user_id [Integer] the user to be given priveleges' id + # user_id - The Integer user to be given priveleges' id + # def assign_creator(user_id) user_id = user_id.id if user_id.is_a?(User) add_user(user_id, true, true, true) end - ## # the datetime for the latest update of this plan # - # @return [DateTime] the time of latest update + # Returns DateTime def latest_update (phases.pluck(:updated_at) + [updated_at]).max end - ## # the owner of the project # - # @return [User] the creater of the project + # Returns User + # Returns nil def owner vals = Role.access_values_for(:creator) User.joins(:roles) @@ -424,7 +426,7 @@ ## # TODO: Rewrite this description # - # returns the shared roles of a plan, excluding the creator + # Returns Boolean def shared? roles.where(Role.not_creator_condition).any? end @@ -433,10 +435,9 @@ deprecate :shared, deprecator: Cleanup::Deprecators::PredicateDeprecator.new - ## # the owner and co-owners of the project # - # @return [Users] + # Returns ActiveRecord::Relation def owner_and_coowners vals = Role.access_values_for(:creator) .concat(Role.access_values_for(:administrator)) @@ -444,7 +445,9 @@ .where(roles: { plan_id: id, access: vals }) end - # Returns the number of answered questions from the entire plan + # The number of answered questions from the entire plan + # + # Returns Integer def num_answered_questions Answer.where(id: answers.map(&:id)) .includes(:question_options, { question: :question_format }) @@ -452,7 +455,9 @@ .sum { |answer| answer.is_valid? ? 1 : 0 } end - # Returns the number of questions for a plan. + # The number of questions for a plan. + # + # Returns Integer def num_questions questions.count end @@ -460,6 +465,8 @@ # Determines whether or not visibility changes are permitted according to the # percentage of the plan answered in respect to a threshold defined at # application.config + # + # Returns Boolean def visibility_allowed? value=(num_answered_questions.to_f/num_questions*100).round(2) !is_test? && value >= Rails.application @@ -468,12 +475,16 @@ end # Determines whether or not a question (given its id) exists for the self plan + # + # Returns Boolean def question_exists?(question_id) Plan.joins(:questions).exists?(id: id, "questions.id": question_id) end # Checks whether or not the number of questions matches the number of valid # answers + # + # Returns Boolean def no_questions_matches_no_answers? num_questions = question_ids.length pre_fetched_answers = Answer.includes(:question_options, @@ -502,19 +513,18 @@ deprecate :has_role, deprecator: Cleanup::Deprecators::PredicateDeprecator.new - ## - # adds a user to the project - # if no flags are specified, the user is given read privleges - # - # @param user_id [Integer] the user to be given privleges - # @param is_editor [Boolean] whether or not the user can edit the project - # @param is_administrator [Boolean] whether or not the user can administrate - # the project - # @param is_creator [Boolean] wheter or not the user created the project - # @return [Array<ProjectGroup>] - # + # Adds a user to the project if no flags are specified, the user is given read privleges # TODO: change this to specifying uniqueness of user/plan association and - # handle that way + # handle that way. + # + # + # user_id - The Integer user ID to be given privleges + # is_editor - Whether or not the user can edit the project (defaults: false) + # is_administrator - Whether or not the user can administrate the project + # (defaults: false) + # is_creator - Wheter or not the user created the project (defaults: false) + # + # Returns Boolean # def add_user(user_id, is_editor = false, is_administrator = false, @@ -547,7 +557,9 @@ end # Initialize the title for new templates - # -------------------------------------------------------- + # + # Returns nil + # Returns String def set_creation_defaults # Only run this before_validation because rails fires this before # save/create diff --git a/app/models/pref.rb b/app/models/pref.rb index 22d8bfc..c3c4707 100644 --- a/app/models/pref.rb +++ b/app/models/pref.rb @@ -28,10 +28,9 @@ validates :settings, presence: { message: PRESENCE_MESSAGE } - ## - # Returns the hash generated from default preferences + # The default preferences # - # @return [JSON] preferences hash + # Returns Hash def self.default_settings Branding.fetch(:preferences) end diff --git a/app/models/question.rb b/app/models/question.rb index 2a1027d..8b36f9a 100644 --- a/app/models/question.rb +++ b/app/models/question.rb @@ -117,8 +117,9 @@ # This method doesn't even make reference to this class and its returning # a hash that is specific to a view guidance for org # - # @param org [Org] the org to find guidance for - # @return [Hash{String => String}] + # org - The Org to find guidance for + # + # Returns Hash def guidance_for_org(org) # pulls together guidance from various sources for question guidances = {} @@ -138,11 +139,11 @@ return guidances end - ## # get example answer belonging to the currents user for this question # - # @param org_ids [Array<Integer>] the ids for the organisations - # @return [Array<Annotation>] the example answers for this question for the specified orgs + # org_ids - The ids for the organisations + # + # Returns ActiveRecord::Relation def example_answers(org_ids) annotations.where(org_id: Array(org_ids), type: Annotation.types[:example_answer]) @@ -154,13 +155,12 @@ deprecate :get_example_answers, deprecator: Cleanup::Deprecators::GetDeprecator.new - ## # get guidance belonging to the current user's org for this question(need org # to distinguish customizations) # - # @param org_id [Integer] the id for the organisation - # @return [String] the annotation guidance for this question for the - # specified org + # org_id - The id for the organisation + # + # Returns Annotation def guidance_annotation(org_id) annotations.where(org_id: org_id, type: Annotation.types[:guidance]).first end diff --git a/app/models/role.rb b/app/models/role.rb index db4ad6e..321aff3 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -102,9 +102,9 @@ ## # Roles with given FlagShihTzu access flags # - # @param flags [Array] One or more symbols that represent access flags + # flags - One or more symbols that represent access flags # - # @return [ActiveRecord::Relation] + # Return ActiveRecord::Relation scope :with_access_flags, -> (*flags) { bad_flag = flags.detect { |flag| !flag.in?(flag_mapping['access'].keys) } raise ArgumentError, "Unkown access flag '#{bad_flag}'" if bad_flag @@ -118,15 +118,15 @@ # = Public instance methods = # =========================== - ## - # return the access level for the current project group - # 5 if the user is a reviewer - # 3 if the user is an administrator - # 2 if the user is an editor - # 1 if the user can only read + + # The access level for the current project group: + # - 5 if the user is a reviewer + # - 3 if the user is an administrator + # - 2 if the user is an editor + # - 1 if the user can only read # used to facilliatte formtastic # - # @return [Integer] + # Returns Integer def access_level if self.reviewer? return 5 diff --git a/app/models/section.rb b/app/models/section.rb index 0152f52..42cb330 100644 --- a/app/models/section.rb +++ b/app/models/section.rb @@ -74,24 +74,21 @@ # The sections for this Phase that have been added by the admin # - # @!scope class - # @return [ActiveRecord::Relation] Returns the sections that are modifiable + # Returns ActiveRecord::Relation scope :modifiable, -> { where(modifiable: true) } # The sections for this Phase that were part of the original Template # - # @!scope class - # @return [ActiveRecord::Relation] Returns the sections that aren't modifiable + # Returns ActiveRecord::Relation scope :not_modifiable, -> { where(modifiable: false) } # =========================== # = Public instance methods = # =========================== - ## - # return the title of the section + # The title of the Section # - # @return [String] the title of the section + # Returns String def to_s "#{title}" end diff --git a/app/models/theme.rb b/app/models/theme.rb index 857ee30..4e66430 100644 --- a/app/models/theme.rb +++ b/app/models/theme.rb @@ -39,10 +39,9 @@ # = Public instance methods = # =========================== - ## - # returns the title of the theme + # The title of the Theme # - # @return [String] title of the theme + # Returns String def to_s title end diff --git a/app/models/token_permission_type.rb b/app/models/token_permission_type.rb index 8c75ee3..8dd979b 100644 --- a/app/models/token_permission_type.rb +++ b/app/models/token_permission_type.rb @@ -48,10 +48,9 @@ uniqueness: { message: UNIQUENESS_MESSAGE } - ## - # returns the token_type of the token_permission_type + # The token_type of the token_permission_type # - # @return [String] token_type of the token_permission_type + # Returns String def to_s self.token_type end diff --git a/app/models/user.rb b/app/models/user.rb index babd2fd..76882a7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -32,9 +32,7 @@ # updated_at :datetime not null # invited_by_id :integer # language_id :integer -# orcid_id :string # org_id :integer -# shibboleth_id :string # # Indexes # @@ -152,8 +150,9 @@ # = Public instance methods = # =========================== - ## # This method uses Devise's built-in handling for inactive users + # + # Returns Boolean def active_for_authentication? super && active? end @@ -163,7 +162,9 @@ # What do they do? do they do it efficiently, and do we need them? # Determines the locale set for the user or the organisation he/she belongs - # @return String or nil + # + # Returns String + # Returns nil def get_locale if !self.language.nil? return self.language.abbreviation @@ -174,11 +175,11 @@ end end - ## - # gives either the name of the user, or the email if name unspecified + # Gives either the name of the user, or the email if name unspecified # - # @param user_email [Boolean] defaults to true, allows the use of email if there is no firstname or surname - # @return [String] the email or the firstname and surname of the user + # user_email - Use the email if there is no firstname or surname (defaults: true) + # + # Returns String def name(use_email = true) if (firstname.blank? && surname.blank?) || use_email then return email @@ -188,113 +189,103 @@ end end - ## - # Returns the user's identifier for the specified scheme name + # The user's identifier for the specified scheme name # - # @param the identifier scheme name (e.g. ORCID) - # @return [UserIdentifier] the user's identifier for that scheme + # scheme - The identifier scheme name (e.g. ORCID) + # + # Returns UserIdentifier def identifier_for(scheme) user_identifiers.where(identifier_scheme: scheme).first end - ## - # checks if the user is a super admin - # if the user has any privelege which requires them to see the super admin page - # then they are a super admin + # Checks if the user is a super admin. If the user has any privelege which requires + # them to see the super admin page then they are a super admin. # - # @return [Boolean] true if the user is an admin + # Returns Boolean def can_super_admin? return self.can_add_orgs? || self.can_grant_api_to_orgs? || self.can_change_org? end - ## - # checks if the user is an organisation admin - # if the user has any privlege which requires them to see the org-admin pages - # then they are an org admin + # Checks if the user is an organisation admin if the user has any privlege which + # requires them to see the org-admin pages then they are an org admin. # - # @return [Boolean] true if the user is an organisation admin + # Returns Boolean def can_org_admin? return self.can_grant_permissions? || self.can_modify_guidance? || self.can_modify_templates? || self.can_modify_org_details? end - ## - # checks if the user can add new organisations + # Can the User add new organisations? # - # @return [Boolean] true if the user can add new organisations + # Returns Boolean def can_add_orgs? perms.include? Perm.add_orgs end - ## - # checks if the user can change their organisation affiliations + # Can the User change their organisation affiliations? # - # @return [Boolean] true if the user can change their organisation affiliations + # Returns Boolean def can_change_org? perms.include? Perm.change_affiliation end - ## - # checks if the user can grant their permissions to others + # Can the User can grant their permissions to others? # - # @return [Boolean] true if the user can grant their permissions to others + # Returns Boolean def can_grant_permissions? perms.include? Perm.grant_permissions end - ## - # checks if the user can modify organisation templates + # Can the User modify organisation templates? # - # @return [Boolean] true if the user can modify organisation templates + # Returns Boolean def can_modify_templates? self.perms.include? Perm.modify_templates end - ## - # checks if the user can modify organisation guidance + # Can the User modify organisation guidance? # - # @return [Boolean] true if the user can modify organistion guidance + # Returns Boolean def can_modify_guidance? perms.include? Perm.modify_guidance end - ## - # checks if the user can use the api + # Can the User use the API? # - # @return [Boolean] true if the user can use the api + # Returns Boolean def can_use_api? perms.include? Perm.use_api end - ## - # checks if the user can modify their org's details + # Can the User modify their org's details? # - # @return [Boolean] true if the user can modify the org's details + # Returns Boolean def can_modify_org_details? perms.include? Perm.change_org_details end - ## - # checks if the user can grant the api to organisations + # Can the User grant the api to organisations? # - # @return [Boolean] true if the user can grant api permissions to organisations + # Returns Boolean def can_grant_api_to_orgs? perms.include? Perm.grant_api end - ## - # removes the api_token from the user - # modifies the user model + # Removes the api_token from the user + # + # Returns nil + # Returns Boolean def remove_token! unless api_token.blank? update_column(:api_token, "") unless new_record? end end - ## - # generates a new token for the user unless the user already has a token. - # modifies the user's model. + # Generates a new token for the user unless the user already has a token. + # + # Returns nil + # Returns Boolean def keep_or_generate_token! if api_token.nil? || api_token.empty? self.api_token = loop do @@ -305,10 +296,9 @@ end end - ## - # Return the user's preferences for a given base key + # The User's preferences for a given base key # - # @return [JSON] with symbols as keys + # Returns Hash def get_preferences(key) defaults = Pref.default_settings[key.to_sym] || Pref.default_settings[key.to_s] @@ -330,17 +320,19 @@ end end - ## # Override devise_invitable email title - # -------------------------------------------------------------- def deliver_invitation(options = {}) super(options.merge(subject: _('A Data Management Plan in %{application_name} has been shared with you') % {application_name: Rails.configuration.branding[:application][:name]})) end - ## + # Case insensitive search over User model - # @param field [string] The name of the field being queried - # @param val [string] The string to search for, case insensitive. val is duck typed to check whether or not downcase method exist - # @return [ActiveRecord::Relation] The result of the search + # + # field - The name of the field being queried + # val - The String to search for, case insensitive. val is duck typed to check + # whether or not downcase method exist. + # + # Returns ActiveRecord::Relation + # Raises ArgumentError def self.where_case_insensitive(field, val) unless columns.map(&:name).include?(field.to_s) raise ArgumentError, "Field #{field} is not present on users table" @@ -348,8 +340,12 @@ User.where("LOWER(#{field}) = :value", value: val.to_s.downcase) end - # Acknoledge a Notification - # @param notification Notification to acknowledge + # Acknowledge a Notification + # + # notification - Notification to acknowledge + # + # Returns ActiveRecord::Associations::CollectionProxy + # Returns nil def acknowledge(notification) notifications << notification if notification.dismissable? end diff --git a/app/services/guidance_service.rb b/app/services/guidance_service.rb index 0e773d7..947c4ed 100644 --- a/app/services/guidance_service.rb +++ b/app/services/guidance_service.rb @@ -6,6 +6,7 @@ @plan = plan @guidance_groups = plan.guidance_groups.where(published: true) end + # Returns an Array of orgs according to the guidance related to plan # Note the Array is sorted in the following order: # First funder org (if the template from the plan is a customization of another) @@ -80,6 +81,36 @@ return hashified_annotations[org].select{ |annotation| (annotation.question_id == question.id) && (annotation.type == "guidance")} end + + # filters through the orgs with annotations and guidance groups to create a + # set of tabs with display names and any guidance/annotations to show + # + # question - The question to which guidance pretains + # + # Returns an array of tab hashes. These + def tablist(question) + # start with orgs + # filter into hash with annotation_presence, main_group presence, and + display_tabs = [] + orgs.each do |org| + annotations = guidance_annotations(org: org,question: question) + groups = guidance_groups_by_theme(org: org,question: question) + main_groups = groups.select{|group| group.optional_subset == false} + subsets = groups.reject{|group| group.optional_subset == false} + if annotations.present? || main_groups.present? # annotations and main group + # Tab with org.abbreviation + display_tabs << {name: org.abbreviation, groups: main_groups, + annotations: annotations} + end + if subsets.present? + subsets.each_pair do |group,theme| + display_tabs << {name: group.name.truncate(15), groups:{group => theme}} + end + end + end + return display_tabs + end + private def orgs_from_guidance_groups if !defined?(@orgs_from_guidance_groups) diff --git a/app/views/guidance_groups/_index_by_theme.html.erb b/app/views/guidance_groups/_index_by_theme.html.erb index 9afb77e..3c39eff 100644 --- a/app/views/guidance_groups/_index_by_theme.html.erb +++ b/app/views/guidance_groups/_index_by_theme.html.erb @@ -20,7 +20,7 @@ aria-controls="<%= "##{guidances.object_id}" %>"> <div class="panel-heading" role="tab" id="<%= "panel-heading-#{guidances.object_id}" %>"> <h2 class="panel-title"> - <%= _("%{name} on %{title}") % { :name => guidance_group.name, :title => theme.title } %> + <%= theme.title %> <i class="fa fa-plus pull-right" aria-hidden="true"></i> </h2> </div> diff --git a/app/views/org_admin/phases/_phase.html.erb b/app/views/org_admin/phases/_phase.html.erb index 9f10f42..7571d4a 100644 --- a/app/views/org_admin/phases/_phase.html.erb +++ b/app/views/org_admin/phases/_phase.html.erb @@ -37,7 +37,7 @@ </thead> <tbody> <% phase.sections.each do |section| %> - <tr> + <tr id="<%= dom_id(section) %>" data-number="<%= section.number %>"> <td><p><%= section.title %></p></td> <td> <% if section.questions.present? %> diff --git a/app/views/phases/_guidances_notes.html.erb b/app/views/phases/_guidances_notes.html.erb index 45d47de..1eb0959 100644 --- a/app/views/phases/_guidances_notes.html.erb +++ b/app/views/phases/_guidances_notes.html.erb @@ -23,54 +23,52 @@ </ul> <div class="tab-content"> <% if guidances_active %> - <div id="guidances-<%= question.id %>" role="tabpanel" class="tab-pane active"> - <ul class="nav nav-tabs" role="tablist"> - <% guidance_service.orgs.each_with_index do |org, i| %> - <% if guidance_service.any?(org: org, question: question) %> - <% active_nav ||= org.id %> - <li role="presentation" <%= active_nav == org.id ? "class=active" : "" %>> - <a - data-target="<%= "#guidance_per_question_#{question.id}_#{i}" %>" - aria-controls="<%= "#guidance_per_question_#{question.id}_#{i}" %>" - role="tab" - data-toggle="tab" - class="view-plan-guidance"> - <%= org.abbreviation %> - </a> - </li> - <% end %> - <% end %> - </ul> - <div class="tab-content"> - <% guidance_service.orgs.each_with_index do |org, i| %> - <% if guidance_service.any?(org: org, question: question) %> - <div id="<%= "guidance_per_question_#{question.id}_#{i}" %>" role="tabpanel" class="tab-pane <%= active_nav == org.id ? 'active' : '' %>"> - <div class="panel panel-default"> - <div class="panel-body"> - <% guidance_service.guidance_annotations(org: org, question: question).each do |annotation| %> - <%= - render partial: 'org_admin/annotations/show', locals: { - template: template, - example_answer: nil, - guidance: annotation, - for_plan: true } - %> - <% end %> - <% if guidance_service.guidance_annotations?(org: org, question: question) && - guidance_service.guidance_groups_by_theme?(org: org, question: question) %> - <hr /> - <% end %> - <% if guidance_service.guidance_groups_by_theme?(org: org, question: question) %> - <%= render partial: 'guidance_groups/index_by_theme', - locals: { guidance_groups_by_theme: guidance_service.guidance_groups_by_theme(org: org, question: question) } %> - <% end %> + <% tablist = guidance_service.tablist(question) %> + <div id="guidances-<%= question.id %>" role="tabpanel" class="tab-pane active"> + <ul class="nav nav-tabs" role="tablist"> + <% tablist.each_with_index do |tab, i| %> + <% active_nav ||= tab[:name] %> + <li role="presentation" <%= active_nav == tab[:name] ? "class=active" : "" %>> + <a + data-target="<%= "#guidance_per_question_#{question.id}_#{i}" %>" + aria-controls="<%= "#guidance_per_question_#{question.id}_#{i}" %>" + role="tab" + data-toggle="tab" + class="view-plan-guidance"> + <%= tab[:name] %> + </a> + </li> + <% end %> + </ul> + <div class="tab-content"> + <% tablist.each_with_index do |tab, i| %> + <div id="<%= "guidance_per_question_#{question.id}_#{i}" %>" role="tabpanel" class="tab-pane <%= active_nav == tab[:name] ? 'active' : '' %>"> + <div class="panel panel-default"> + <div class="panel-body"> + <% if tab[:annotations].present? %> + <% tab[:annotations].each do |annotation| %> + <%= + render partial: 'org_admin/annotations/show', locals: { + template: template, + example_answer: nil, + guidance: annotation, + for_plan: true } + %> + <% end %> + <% if tab[:groups].present? %> + <hr /> + <% end %> + <% end %> + <% if tab[:groups].present? %> + <%= render partial: 'guidance_groups/index_by_theme', + locals: { guidance_groups_by_theme: tab[:groups] } %> + <% end %> + </div> </div> </div> - </div> <% end %> - <% end %> + </div> </div> - </div> <% end %> <% if plan.present? %> diff --git a/app/views/shared/_create_account_form.html.erb b/app/views/shared/_create_account_form.html.erb index 6bdf261..3ed5abe 100644 --- a/app/views/shared/_create_account_form.html.erb +++ b/app/views/shared/_create_account_form.html.erb @@ -15,7 +15,7 @@ <div class="form-group"> <%= render partial: "shared/my_org", locals: {f: f, default_org: @default_org, - orgs: Org.where("parent_id IS NULL").order("sort_name ASC, name ASC"), + orgs: Org.order("sort_name ASC, name ASC"), allow_other_orgs: true, required: true} %> </div> diff --git a/app/views/shared/export/_plan.erb b/app/views/shared/export/_plan.erb index d6db153..b830166 100644 --- a/app/views/shared/export/_plan.erb +++ b/app/views/shared/export/_plan.erb @@ -32,55 +32,57 @@ <% end %> <% @hash[:phases].each do |phase| %> - <div style="page-break-before:always;"></div> <!-- Page break before each phase --> - <!-- If there is more than one phase show the plan title and phase title --> - <h1><%= (@hash[:phases].length > 1 ? "#{@plan.title} - #{phase[:title]}" : @plan.title) %></h1> - <hr /> - <% phase[:sections].each do |section| %> - <% if @show_sections_questions %> - <h3><%= section[:title] %></h3> - <% end %> + <%# Only render selected phase %> + <% if phase[:title] == @selected_phase.title %> + <div style="page-break-before:always;"></div> <!-- Page break before each phase --> + <h1><%= download_plan_page_title(@plan, phase, @hash) %></h1> + <hr /> + <% phase[:sections].each do |section| %> + <% if display_questions_and_section_headings(section, @show_sections_questions, @show_custom_sections) %> + <h3><%= section[:title] %></h3> - <% section[:questions].each do |question| %> - <div class="question"> - <% if @show_sections_questions && !@public_plan %> - <p><%= raw question[:text].gsub(/<tr>(\s|<td>|<\/td>| )*(<\/tr>|<tr>)/,"") if question[:text].present?%></p> - <br> - <% end %> - <% answer = @plan.answer(question[:id], false) %> - <% blank = answer.present? ? answer.is_blank? : true %> - <% options = answer.present? ? answer.question_options : [] %> - <%# case where question has not been answered sufficiently to display%> - <% if @show_unanswered && (answer.blank? || (options.blank? && blank))%> - <p><%= _('Question not answered.') -%></p> - <% else %> - <%# case where Question has options %> - <% if options.present?%> - <ul> - <% options.each do |opt| %> - <li><%= opt.text %></li> - <% end %> - </ul> - <% end %> - <%# case for RDA answer display %> - <% if question[:format].rda_metadata? && !blank %> - <% ah = answer.answer_hash %> - <% if ah['standards'].present? %> - <ul> - <% ah['standards'].each do |id, title| %> - <li><%= title %></li> - <% end %> - </ul> + <% section[:questions].each do |question| %> + <div class="question"> + <% if !@public_plan %> + <p><%= raw question[:text].gsub(/<tr>(\s|<td>|<\/td>| )*(<\/tr>|<tr>)/,"") if question[:text].present?%></p> + <br> <% end %> - <p><%= raw ah['text'] %></p> - <%# case for displaying comments OR text %> - <% elsif !blank %> - <p><%= raw answer.text %></p> - <% end %> + <% answer = @plan.answer(question[:id], false) %> + <% blank = answer.present? ? answer.is_blank? : true %> + <% options = answer.present? ? answer.question_options : [] %> + <%# case where question has not been answered sufficiently to display%> + <% if @show_unanswered && (answer.blank? || (options.blank? && blank))%> + <p><%= _('Question not answered.') -%></p> + <% else %> + <%# case where Question has options %> + <% if options.any? %> + <ul> + <% options.each do |opt| %> + <li><%= opt.text %></li> + <% end %> + </ul> + <% end %> + <%# case for RDA answer display %> + <% if question[:format].rda_metadata? && !blank %> + <% ah = answer.answer_hash %> + <% if ah['standards'].present? %> + <ul> + <% ah['standards'].each do |id, title| %> + <li><%= title %></li> + <% end %> + </ul> + <% end %> + <p><%= raw ah['text'] %></p> + <%# case for displaying comments OR text %> + <% elsif !blank %> + <p><%= raw answer.text %></p> + <% end %> + <% end %> + </div> <% end %> - </div> - <% end %> - <% end %> <!-- sections.each --> + <% end %> + <% end %> <!-- sections.each --> + <% end %> <% end %> </body> </html> diff --git a/app/views/shared/export/_plan_txt.erb b/app/views/shared/export/_plan_txt.erb index 6b06132..d2be1c2 100644 --- a/app/views/shared/export/_plan_txt.erb +++ b/app/views/shared/export/_plan_txt.erb @@ -22,13 +22,14 @@ <% end %> <% @hash[:phases].each do |phase| %> -<%= (@hash[:phases].length > 1 ? "#{phase[:title]}" : "") %> +<%# Only render selected phase %> +<% if phase[:title] == @selected_phase.title %> + <%= (@hash[:phases].length > 1 ? "#{phase[:title]}" : "") %> <% phase[:sections].each do |section| %> - <% if @show_sections_questions %> + <% if display_questions_and_section_headings(section, @show_sections_questions, @show_custom_sections) %> <%= "#{section[:title]}\n" %> - <% end %> - <% section[:questions].each do |question| %> - <% if @show_sections_questions %> + + <% section[:questions].each do |question| %> <%# text in this case is an array to accomodate for option_based %> <% if question[:text].respond_to?(:each) %> <% question[:text].each do |txt| %> @@ -37,22 +38,22 @@ <% else %> <%= "#{strip_tags(question[:text][0].gsub(/<tr>(\s|<td>|<\/td>| )*(<\/tr>|<tr>)/,""))}\n" if question[:text].present? && question[:text][0].present? %> <% end %> - <% end %> - <% answer = @plan.answer(question[:id], false) %> - <% blank = (answer.present? && answer.is_valid?) ? answer.text.gsub(/<\/?p>/, '').gsub(/<br\s?\/?>/, '\n').chomp.blank? : true %> - <% if blank && @show_unanswered %> + <% answer = @plan.answer(question[:id], false) %> + <% blank = (answer.present? && answer.is_valid?) ? answer.text.gsub(/<\/?p>/, '').gsub(/<br\s?\/?>/, '\n').chomp.blank? : true %> + <% if blank && @show_unanswered %> <%= " #{_("Question not answered.")}\n\n" %> - <% elsif !blank %> - <% if answer.question_options.length > 0 %> - <% answer.question_options.each do |opt| %> + <% elsif !blank %> + <% if answer.question_options.length > 0 %> + <% answer.question_options.each do |opt| %> <%= " #{opt.text}\n" %> + <% end %> + <% end %> +<%= " #{strip_tags(answer.text.gsub(/<\/?p>/, '').gsub(/<br\s?\/?>/, '\n').chomp)}\n\n" if answer.text.present? %> <% end %> <% end %> -<%= " #{strip_tags(answer.text.gsub(/<\/?p>/, '').gsub(/<br\s?\/?>/, '\n').chomp)}\n\n" if answer.text.present? %> <% end %> <% end %> <% end %> <% end %> - <%= "----------------------------------------------------------" %> <%= _("A Data Management Plan created using %{application_name}") % { application_name: Rails.configuration.branding[:application][:name] } %> \ No newline at end of file diff --git a/bin/rubocop_changed b/bin/rubocop_changed new file mode 100755 index 0000000..08c8e49 --- /dev/null +++ b/bin/rubocop_changed @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +# Which branch should we compare HEAD with for changed files? (defaults: 'development') +BRANCH='development' +DIRS='app lib' + +while getopts 'b:d:' optname +do + case "$optname" in + "b") + BRANCH=$OPTARG + ;; + "d") + DIRS=$OPTARG + ;; + esac +done + +# Get a list of all files that have changed on this branch in app and lib directories. +CHANGED_FILES=$(git diff --name-only $BRANCH -- $DIRS) + +# A string with the name of each changed file +EXISTING_FILES="" + +# Iterate over each changed file +for FILEPATH in $CHANGED_FILES +do + # Append this filename if the file still exists (in case the file has been deleted) + if [ -f $FILEPATH ]; then + EXISTING_FILES+=" $FILEPATH" + fi +done + +# If there are no files that have been changed... +if [ -z "$EXISTING_FILES" ] +then + # Print a message and exit + echo "Rubocop changed: No matching files have changed." + exit 0 +else + # Run Rubocop against the files that have chagned + rubocop -p $EXISTING_FILES +fi diff --git a/db/migrate/20130905073232_remove_slug_from_plans.rb b/db/migrate/20130905073232_remove_slug_from_plans.rb deleted file mode 100644 index a06bdee..0000000 --- a/db/migrate/20130905073232_remove_slug_from_plans.rb +++ /dev/null @@ -1,9 +0,0 @@ -class RemoveSlugFromPlans < ActiveRecord::Migration - def up - remove_column :plans, :slug - end - - def down - add_column :plans, :slug, :string - end -end diff --git a/db/migrate/20170303220255_remove_orcid_id_from_users.rb b/db/migrate/20170303220255_remove_orcid_id_from_users.rb deleted file mode 100644 index 7c71213..0000000 --- a/db/migrate/20170303220255_remove_orcid_id_from_users.rb +++ /dev/null @@ -1,5 +0,0 @@ -class RemoveOrcidIdFromUsers < ActiveRecord::Migration - def change - #remove_column :users, :orcid_id - end -end diff --git a/db/migrate/20180813114157_remove_logo_file_name_from_orgs.rb b/db/migrate/20180813114157_remove_logo_file_name_from_orgs.rb new file mode 100644 index 0000000..334fdd7 --- /dev/null +++ b/db/migrate/20180813114157_remove_logo_file_name_from_orgs.rb @@ -0,0 +1,11 @@ +class RemoveLogoFileNameFromOrgs < ActiveRecord::Migration + def up + if column_exists?(:orgs, :logo_file_name) + remove_column :orgs, :logo_file_name + end + end + + def down + add_column :orgs, :logo_file_name, :string + end +end diff --git a/db/migrate/20180813114216_remove_parent_id_from_orgs.rb b/db/migrate/20180813114216_remove_parent_id_from_orgs.rb new file mode 100644 index 0000000..118125b --- /dev/null +++ b/db/migrate/20180813114216_remove_parent_id_from_orgs.rb @@ -0,0 +1,11 @@ +class RemoveParentIdFromOrgs < ActiveRecord::Migration + def up + if column_exists?(:orgs, :parent_id) + remove_column :orgs, :parent_id + end + end + + def down + add_column :orgs, :parent_id, :integer + end +end diff --git a/db/migrate/20180813114234_remove_wayfless_entity_from_orgs.rb b/db/migrate/20180813114234_remove_wayfless_entity_from_orgs.rb new file mode 100644 index 0000000..a19bb0c --- /dev/null +++ b/db/migrate/20180813114234_remove_wayfless_entity_from_orgs.rb @@ -0,0 +1,11 @@ +class RemoveWayflessEntityFromOrgs < ActiveRecord::Migration + def up + if column_exists?(:orgs, :wayfless_entity) + remove_column :orgs, :wayfless_entity + end + end + + def down + add_column :orgs, :wayfless_entity, :string + end +end diff --git a/db/migrate/20180813114348_remove_slug_from_phases.rb b/db/migrate/20180813114348_remove_slug_from_phases.rb new file mode 100644 index 0000000..3520ef6 --- /dev/null +++ b/db/migrate/20180813114348_remove_slug_from_phases.rb @@ -0,0 +1,11 @@ +class RemoveSlugFromPhases < ActiveRecord::Migration + def up + if column_exists?(:phases, :slug) + remove_column :phases, :slug + end + end + + def down + add_column :phases, :slug, :string + end +end diff --git a/db/migrate/20180813114525_remove_slug_from_plans.rb b/db/migrate/20180813114525_remove_slug_from_plans.rb new file mode 100644 index 0000000..11ebb04 --- /dev/null +++ b/db/migrate/20180813114525_remove_slug_from_plans.rb @@ -0,0 +1,11 @@ +class RemoveSlugFromPlans < ActiveRecord::Migration + def up + if column_exists?(:plans, :slug) + remove_column :plans, :slug + end + end + + def down + add_column :plans, :slug, :string + end +end diff --git a/db/migrate/20180813114550_drop_table_friendly_id_slugs.rb b/db/migrate/20180813114550_drop_table_friendly_id_slugs.rb new file mode 100644 index 0000000..8d0ab2e --- /dev/null +++ b/db/migrate/20180813114550_drop_table_friendly_id_slugs.rb @@ -0,0 +1,17 @@ +class DropTableFriendlyIdSlugs < ActiveRecord::Migration + def up + drop_table :friendly_id_slugs if table_exists?(:friendly_id_slugs) + end + + def down + create_table :friendly_id_slugs do |t| + t.string :slug, :null => false + t.integer :sluggable_id, :null => false + t.string :sluggable_type, :limit => 40 + t.datetime :created_at + end + add_index :friendly_id_slugs, :sluggable_id + add_index :friendly_id_slugs, [:slug, :sluggable_type], :unique => true + add_index :friendly_id_slugs, :sluggable_type + end +end diff --git a/db/migrate/20180813114614_drop_table_file_types.rb b/db/migrate/20180813114614_drop_table_file_types.rb new file mode 100644 index 0000000..d0be6f1 --- /dev/null +++ b/db/migrate/20180813114614_drop_table_file_types.rb @@ -0,0 +1,17 @@ +class DropTableFileTypes < ActiveRecord::Migration + + def up + drop_table(:file_types) if table_exists?(:file_types) + end + + def down + create_table "file_types", force: :cascade do |t| + t.string "name" + t.string "icon_name" + t.integer "icon_size" + t.string "icon_location" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + end +end diff --git a/db/migrate/20180813114622_drop_table_file_uploads.rb b/db/migrate/20180813114622_drop_table_file_uploads.rb new file mode 100644 index 0000000..efc1f5c --- /dev/null +++ b/db/migrate/20180813114622_drop_table_file_uploads.rb @@ -0,0 +1,19 @@ +class DropTableFileUploads < ActiveRecord::Migration + def up + drop_table(:file_uploads) if table_exists?(:file_uploads) + end + + def down + create_table "file_uploads", force: :cascade do |t| + t.string "name" + t.string "title" + t.text "description" + t.integer "size" + t.boolean "published" + t.string "location" + t.integer "file_type_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + end +end diff --git a/db/migrate/20180813114628_drop_table_splash_logs.rb b/db/migrate/20180813114628_drop_table_splash_logs.rb new file mode 100644 index 0000000..b09cc0b --- /dev/null +++ b/db/migrate/20180813114628_drop_table_splash_logs.rb @@ -0,0 +1,13 @@ +class DropTableSplashLogs < ActiveRecord::Migration + def up + drop_table(:splash_logs) if table_exists?(:splash_logs) + end + + def down + create_table "splash_logs", force: :cascade do |t| + t.string "destination" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + end +end diff --git a/db/migrate/20180813114649_remove_banner_text_from_orgs.rb b/db/migrate/20180813114649_remove_banner_text_from_orgs.rb new file mode 100644 index 0000000..315e4b4 --- /dev/null +++ b/db/migrate/20180813114649_remove_banner_text_from_orgs.rb @@ -0,0 +1,9 @@ +class RemoveBannerTextFromOrgs < ActiveRecord::Migration + def up + remove_column :orgs, :banner_text + end + + def down + add_column :orgs, :banner_text, :text + end +end diff --git a/db/migrate/20180813114719_remove_question_id_from_guidances.rb b/db/migrate/20180813114719_remove_question_id_from_guidances.rb new file mode 100644 index 0000000..4849d84 --- /dev/null +++ b/db/migrate/20180813114719_remove_question_id_from_guidances.rb @@ -0,0 +1,9 @@ +class RemoveQuestionIdFromGuidances < ActiveRecord::Migration + def up + remove_column :guidances, :question_id + end + + def down + add_column :guidances, :question_id, :integer + end +end diff --git a/db/migrate/20180813114801_remove_orcid_id_from_users.rb b/db/migrate/20180813114801_remove_orcid_id_from_users.rb new file mode 100644 index 0000000..aa89421 --- /dev/null +++ b/db/migrate/20180813114801_remove_orcid_id_from_users.rb @@ -0,0 +1,9 @@ +class RemoveOrcidIdFromUsers < ActiveRecord::Migration + def up + remove_column :users, :orcid_id + end + + def down + add_column :users, :orcid_id, :string + end +end diff --git a/db/migrate/20180813114813_remove_shibboleth_id_from_users.rb b/db/migrate/20180813114813_remove_shibboleth_id_from_users.rb new file mode 100644 index 0000000..51cd451 --- /dev/null +++ b/db/migrate/20180813114813_remove_shibboleth_id_from_users.rb @@ -0,0 +1,9 @@ +class RemoveShibbolethIdFromUsers < ActiveRecord::Migration + def up + remove_column :users, :shibboleth_id + end + + def down + add_column :users, :shibboleth_id, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 422ac3c..41ee2bf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20180807121126) do +ActiveRecord::Schema.define(version: 20180813114813) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -56,27 +56,6 @@ t.integer "phase_id" end - create_table "file_types", force: :cascade do |t| - t.string "name" - t.string "icon_name" - t.integer "icon_size" - t.string "icon_location" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "file_uploads", force: :cascade do |t| - t.string "name" - t.string "title" - t.text "description" - t.integer "size" - t.boolean "published" - t.string "location" - t.integer "file_type_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - create_table "guidance_groups", force: :cascade do |t| t.string "name" t.integer "org_id" @@ -93,7 +72,6 @@ t.integer "guidance_group_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.integer "question_id" t.boolean "published" end @@ -172,14 +150,10 @@ t.string "name" t.string "abbreviation" t.string "target_url" - t.string "wayfless_entity" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.integer "parent_id" t.boolean "is_other", default: false, null: false t.string "sort_name" - t.text "banner_text" - t.string "logo_file_name" t.integer "region_id" t.integer "language_id" t.string "logo_uid" @@ -206,7 +180,6 @@ t.integer "template_id" t.datetime "created_at" t.datetime "updated_at" - t.string "slug" t.boolean "modifiable" end @@ -217,7 +190,6 @@ t.integer "template_id" t.datetime "created_at" t.datetime "updated_at" - t.string "slug" t.string "grant_number" t.string "identifier" t.text "description" @@ -329,12 +301,6 @@ t.datetime "updated_at", null: false end - create_table "splash_logs", force: :cascade do |t| - t.string "destination" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - create_table "templates", force: :cascade do |t| t.string "title" t.text "description" @@ -395,8 +361,6 @@ t.string "firstname" t.string "surname" t.string "email", limit: 80, default: "", null: false - t.string "orcid_id" - t.string "shibboleth_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "encrypted_password", default: "" diff --git a/lib/branding.rb b/lib/branding.rb index 9427e98..2400d5c 100644 --- a/lib/branding.rb +++ b/lib/branding.rb @@ -5,15 +5,18 @@ # Loads branding config from YAML file. # - # @param keys [Array<Object>] A list of the keys to return configs for. + # keys - A list of the keys to return configs for. # - # @example Return a value + # Examples: + # + # # Return a value # Branding.fetch(:settings, :should_work) # => true # Branding.fetch(:settings, :email) # => 'user@example.com' # Branding.fetch(:settings, :missing) # => nil - # @return [Object] The value of the config + # + # Returns Object def fetch(*keys) keys = keys.map(&:to_sym) Rails.configuration.branding.dig(*keys) end -end \ No newline at end of file +end diff --git a/lib/global_helpers.rb b/lib/global_helpers.rb index b630113..8a01937 100644 --- a/lib/global_helpers.rb +++ b/lib/global_helpers.rb @@ -1,14 +1,17 @@ module GlobalHelpers ## - # takes in a string which is meant to be constant, and looks it up in the default - # (en_GB) locale. This should ensure that the back-end remains constant and consistantly called + # Takes in a string which is meant to be constant, and looks it up in the default + # (en_GB) locale. This should ensure that the back-end remains constant and + # consistantly called # - # @param [String] str the string which will be looked up in the localisation - # @return [String] the constant which the string defines + # str - The String which will be looked up in the localisation + # + # Returns String def constant(str) I18n.t("magic_strings.#{str}", locale: I18n.default_locale) end + # overloading the method # came across a wierd issue where the function would refused to be called from # class functions of other classes... but it will work if this is a class function diff --git a/lib/tasks/doc.rake b/lib/tasks/doc.rake new file mode 100644 index 0000000..96a0c4f --- /dev/null +++ b/lib/tasks/doc.rake @@ -0,0 +1,38 @@ +namespace :tomdoc do + desc "Removes the docs from the ./doc directory" + task :clear do + FileUtils.rm_r(Rails.root.join("doc")) + end + + desc "Builds documentation in the ./doc directory" + task :app do + puts "Please wait..." + options = [] + # Parse documentation as Tomdoc (https://tomdoc.org) + options << "--plugin tomdoc" + # Specify which file to use for the main index (README) + options << "--readme README.md" + # Hides return types specified as 'void'. + options << "--hide-void-return" + # Add a custom title to the HTML docs + options << "--title 'DMP Roadmap'" + # Include protected methods + options << "--protected" + # Include private methods + options << "--private" + # Set methods with no Return value to 'void' + options << "--default-return 'void'" + system("yard doc #{options.join(" ")}") + end + + desc "Builds documentation in the ./doc directory" + task :open do + `open doc/index.html` + end +end + +task tomdoc: ["tomdoc:clear", "tomdoc:app", "tomdoc:open"] do +end + +# Clear Rails' default doc tasks first. +task("doc:app").clear.enhance(["tomdoc:app"]) diff --git a/spec/factories/exported_plans.rb b/spec/factories/exported_plans.rb index 110e7ae..d1a1c22 100644 --- a/spec/factories/exported_plans.rb +++ b/spec/factories/exported_plans.rb @@ -3,12 +3,12 @@ # Table name: exported_plans # # id :integer not null, primary key -# plan_id :integer -# user_id :integer # format :string # created_at :datetime not null # updated_at :datetime not null # phase_id :integer +# plan_id :integer +# user_id :integer # FactoryBot.define do diff --git a/spec/factories/guidances.rb b/spec/factories/guidances.rb index d57c1a0..43a8e68 100644 --- a/spec/factories/guidances.rb +++ b/spec/factories/guidances.rb @@ -8,7 +8,6 @@ # created_at :datetime not null # updated_at :datetime not null # guidance_group_id :integer -# question_id :integer # # Indexes # diff --git a/spec/factories/identifier_schemes.rb b/spec/factories/identifier_schemes.rb index 03459e4..2f3deb9 100644 --- a/spec/factories/identifier_schemes.rb +++ b/spec/factories/identifier_schemes.rb @@ -3,13 +3,13 @@ # Table name: identifier_schemes # # id :integer not null, primary key -# name :string -# description :string # active :boolean +# description :string +# logo_url :text +# name :string +# user_landing_url :text # created_at :datetime # updated_at :datetime -# logo_url :text -# user_landing_url :text # FactoryBot.define do diff --git a/spec/factories/languages.rb b/spec/factories/languages.rb index 2350723..70af9db 100644 --- a/spec/factories/languages.rb +++ b/spec/factories/languages.rb @@ -4,9 +4,9 @@ # # id :integer not null, primary key # abbreviation :string +# default_language :boolean # description :string # name :string -# default_language :boolean # FactoryBot.define do diff --git a/spec/factories/notifications.rb b/spec/factories/notifications.rb index 3b5cac6..fd60bc7 100644 --- a/spec/factories/notifications.rb +++ b/spec/factories/notifications.rb @@ -3,13 +3,13 @@ # Table name: notifications # # id :integer not null, primary key -# notification_type :integer -# title :string -# level :integer # body :text # dismissable :boolean -# starts_at :date # expires_at :date +# level :integer +# notification_type :integer +# starts_at :date +# title :string # created_at :datetime not null # updated_at :datetime not null # diff --git a/spec/factories/orgs.rb b/spec/factories/orgs.rb index 2945f18..3d19e1b 100644 --- a/spec/factories/orgs.rb +++ b/spec/factories/orgs.rb @@ -4,7 +4,6 @@ # # id :integer not null, primary key # abbreviation :string -# banner_text :text # contact_email :string # contact_name :string # feedback_email_msg :text @@ -12,18 +11,15 @@ # feedback_enabled :boolean default(FALSE) # is_other :boolean default(FALSE), not null # links :text -# logo_file_name :string # logo_name :string # logo_uid :string # name :string # org_type :integer default(0), not null # sort_name :string # target_url :string -# wayfless_entity :string # created_at :datetime not null # updated_at :datetime not null # language_id :integer -# parent_id :integer # region_id :integer # # Foreign Keys diff --git a/spec/factories/phases.rb b/spec/factories/phases.rb index 9cb7d85..c51c4f2 100644 --- a/spec/factories/phases.rb +++ b/spec/factories/phases.rb @@ -6,7 +6,6 @@ # description :text # modifiable :boolean # number :integer -# slug :string # title :string # created_at :datetime # updated_at :datetime diff --git a/spec/factories/plans.rb b/spec/factories/plans.rb index bbb922b..c91a105 100644 --- a/spec/factories/plans.rb +++ b/spec/factories/plans.rb @@ -16,7 +16,6 @@ # principal_investigator_email :string # principal_investigator_identifier :string # principal_investigator_phone :string -# slug :string # title :string # visibility :integer default(3), not null # created_at :datetime diff --git a/spec/factories/question_formats.rb b/spec/factories/question_formats.rb index 3e84c1a..335fe64 100644 --- a/spec/factories/question_formats.rb +++ b/spec/factories/question_formats.rb @@ -3,12 +3,12 @@ # Table name: question_formats # # id :integer not null, primary key -# title :string # description :text +# formattype :integer default(0) +# option_based :boolean default(FALSE) +# title :string # created_at :datetime not null # updated_at :datetime not null -# option_based :boolean default(FALSE) -# formattype :integer default(0) # FactoryBot.define do diff --git a/spec/factories/themes.rb b/spec/factories/themes.rb index 9dc836d..bd117b0 100644 --- a/spec/factories/themes.rb +++ b/spec/factories/themes.rb @@ -3,11 +3,11 @@ # Table name: themes # # id :integer not null, primary key -# title :string # description :text +# locale :string +# title :string # created_at :datetime not null # updated_at :datetime not null -# locale :string # FactoryBot.define do diff --git a/spec/factories/token_permission_types.rb b/spec/factories/token_permission_types.rb index bcccca1..4677cdf 100644 --- a/spec/factories/token_permission_types.rb +++ b/spec/factories/token_permission_types.rb @@ -3,8 +3,8 @@ # Table name: token_permission_types # # id :integer not null, primary key -# token_type :string # text_description :text +# token_type :string # created_at :datetime # updated_at :datetime # diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 0f32562..d6cf3dd 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -32,9 +32,7 @@ # updated_at :datetime not null # invited_by_id :integer # language_id :integer -# orcid_id :string # org_id :integer -# shibboleth_id :string # # Indexes #