diff --git a/app/controllers/orgs_controller.rb b/app/controllers/orgs_controller.rb index 395f419..91b8ded 100644 --- a/app/controllers/orgs_controller.rb +++ b/app/controllers/orgs_controller.rb @@ -24,12 +24,9 @@ authorize @org @org.banner_text = params["org_banner_text"] @org.logo = params[:org][:logo] if params[:org][:logo] - assign_params = params[:org].dup - assign_params.delete(:logo) - assign_params.delete(:contact_email) unless params[:org][:contact_email].present? begin - if @org.update_attributes(assign_params) + if @org.update_attributes(org_params) redirect_to admin_show_org_path(params[:id]), notice: _('Organisation was successfully updated.') else # For some reason our custom validator returns as a string and not a hash like normal activerecord @@ -45,4 +42,10 @@ render action: "admin_edit" end end + + private + + def org_params + params.require(:org).permit(:name, :abbreviation, :target_url) + end end diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb index 85396a9..25216b7 100644 --- a/app/controllers/plans_controller.rb +++ b/app/controllers/plans_controller.rb @@ -109,6 +109,7 @@ # GET /plans/show def show + puts 'plans#show' @plan = Plan.eager_load(params[:id]) authorize @plan @@ -352,6 +353,12 @@ end end + def show_export + @plan = Plan.find(params[:id]) + authorize @plan + render 'show_export' + end + def export @plan = Plan.find(params[:id]) authorize @plan @@ -360,8 +367,7 @@ @exported_plan = ExportedPlan.new.tap do |ep| ep.plan = @plan ep.user = current_user - #ep.format = request.format.try(:symbol) - ep.format = request.format.to_sym + ep.format = params[:format].to_sym plan_settings = @plan.settings(:export) Settings::Template::DEFAULT_SETTINGS.each do |key, value| @@ -369,27 +375,30 @@ end end - @exported_plan.save! # FIXME: handle invalid request types without erroring? - file_name = @exported_plan.project_name + begin + @exported_plan.save! + file_name = @exported_plan.project_name - respond_to do |format| - format.html - format.xml - format.json - format.csv { send_data @exported_plan.as_csv, filename: "#{file_name}.csv" } - format.text { send_data @exported_plan.as_txt, filename: "#{file_name}.txt" } - format.docx { headers["Content-Disposition"] = "attachment; filename=\"#{file_name}.docx\""} - format.pdf do - @formatting = @plan.settings(:export).formatting - render pdf: file_name, - margin: @formatting[:margin], - footer: { - center: t('helpers.plan.export.pdf.generated_by'), - font_size: 8, - spacing: (@formatting[:margin][:bottom] / 2) - 4, - right: '[page] of [topage]' - } + respond_to do |format| + format.html + format.csv { send_data @exported_plan.as_csv, filename: "#{file_name}.csv" } + format.text { send_data @exported_plan.as_txt, filename: "#{file_name}.txt" } + format.docx { headers["Content-Disposition"] = "attachment; filename=\"#{file_name}.docx\""} + format.pdf do + @formatting = @plan.settings(:export).formatting + render pdf: file_name, + margin: @formatting[:margin], + footer: { + center: _('This document was generated by %{application_name}') % {application_name: Rails.configuration.branding[:application][:name]}, + font_size: 8, + spacing: (@formatting[:margin][:bottom] / 2) - 4, + right: '[page] of [topage]' + } + end end + rescue ActiveRecord::RecordInvalid => e + redirect_to show_export_plan_path(@plan), notice: _('%{format} is not a valid exporting format. Available formats to export are %{available_formats}.') % + {format: params[:format], available_formats: ExportedPlan::VALID_FORMATS.to_s} end elsif !user_signed_in? then respond_to do |format| @@ -397,7 +406,7 @@ end elsif !@plan.editable_by(current_user.id) then respond_to do |format| - format.html { redirect_to projects_url, notice: _('This account does not have access to that plan.') } + format.html { redirect_to plans_path, notice: _('This account does not have access to that plan.') } end end end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index b7b3d51..8d3153d 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -35,34 +35,34 @@ # POST /resource def create #logger.debug "#{sign_up_params}" - if sign_up_params[:accept_terms] != "1" then - redirect_to after_sign_up_error_path_for(resource), alert: _('You must accept the terms and conditions to register.') - else - existing_user = User.find_by_email(sign_up_params[:email]) - if !existing_user.nil? then - if (existing_user.password == "" || existing_user.password.nil?) && existing_user.confirmed_at.nil? then - @user = existing_user - do_update(false, true) - else + if sign_up_params[:accept_terms] != "1" then + redirect_to after_sign_up_error_path_for(resource), alert: _('You must accept the terms and conditions to register.') + else + existing_user = User.find_by_email(sign_up_params[:email]) + if !existing_user.nil? then + if (existing_user.password == "" || existing_user.password.nil?) && existing_user.confirmed_at.nil? then + @user = existing_user + do_update(false, true) + else redirect_to after_sign_up_error_path_for(resource), alert: _('That email address is already registered.') - end - else + end + else build_resource(sign_up_params) - if resource.save - if resource.active_for_authentication? - set_flash_message :notice, :signed_up if is_navigational_format? - sign_up(resource_name, resource) - respond_with resource, location: after_sign_up_path_for(resource) - else - set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format? - #expire_session_data_after_sign_in! <-- DEPRECATED BY DEVISE - respond_with resource, location: after_inactive_sign_up_path_for(resource) - end - else - clean_up_passwords resource - redirect_to after_sign_up_error_path_for(resource), alert: _('Error processing registration. Please check that you have entered a valid email address and that your chosen password is at least 8 characters long.') - end - end + if resource.save + if resource.active_for_authentication? + set_flash_message :notice, :signed_up if is_navigational_format? + sign_up(resource_name, resource) + respond_with resource, location: after_sign_up_path_for(resource) + else + set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_navigational_format? + #expire_session_data_after_sign_in! <-- DEPRECATED BY DEVISE + respond_with resource, location: after_inactive_sign_up_path_for(resource) + end + else + clean_up_passwords resource + redirect_to after_sign_up_error_path_for(resource), alert: _('Error processing registration. Please check that you have entered a valid email address and that your chosen password is at least 8 characters long.') + end + end end end @@ -73,7 +73,7 @@ @other_organisations = Org.where(parent_id: nil, is_other: true).pluck(:id) @identifier_schemes = IdentifierScheme.where(active: true).order(:name) @languages = Language.sorted_by_abbreviation - do_update + do_update(require_password=needs_password?(current_user, params)) else render(:file => File.join(Rails.root, 'public/403.html'), :status => 403, :layout => false) end @@ -89,18 +89,30 @@ end def do_update(require_password = true, confirm = false) - if require_password then - successfully_updated = if needs_password?(current_user, params) - current_user.update_with_password(params[:user]) - else - # remove the virtual current_password attribute update_without_password - # doesn't know how to ignore it - params[:user].delete(:current_password) - current_user.update_without_password(params[:user]) + if require_password # user is changing email or password + if current_user.email != params[:user][:email] # if user changing email + if params[:user][:current_password].blank? # password needs to be present + message = _('Please enter your password to change email address.') + succesfully_updated = false + else + succesfully_updated = current_user.update_with_password(password_update) + end + elsif params[:user][:password].present? # user is changing password + succesfully_updated = false # shared across first 3 conditions + if params[:user][:current_password].blank? + message = _('Please enter your current password') + elsif params[:user][:password_confirmation].blank? + message = _('Please enter a password confirmation') + elsif params[:user][:password] != params[:user][:password_confirmation] + message = _('Password and comfirmation must match') + else + succesfully_updated = current_user.update_with_password(password_update) + end + else # potentially unreachable... but I dont like to leave off the else + succesfully_updated = current_user.update_with_password(password_update) end - else - current_user.update_attributes(password: params[:user][:password], password_confirmation: params[:user][:password_confirmation]) - successfully_updated = current_user.update_without_password(params[:user]) + else # password not required + current_user.update_without_password(update_params) end #unlink shibboleth from user's details @@ -108,24 +120,38 @@ current_user.update_attributes(shibboleth_id: "") end - if successfully_updated - if confirm then - current_user.skip_confirmation! - current_user.save! - end - session[:locale] = current_user.get_locale unless current_user.get_locale.nil? - set_gettext_locale #Method defined at controllers/application_controller.rb - set_flash_message :notice, :updated - sign_in current_user, bypass_sign_in: true # Sign in the user bypassing validation in case his password changed - redirect_to({:controller => "registrations", :action => "edit"}, {:notice => _('Details successfully updated.')}) + #render the correct page + if succesfully_updated + if confirm + current_user.skip_confirmation! + current_user.save! + end + session[:locale] = current_user.get_locale unless current_user.get_locale.nil? + set_gettext_locale #Method defined at controllers/application_controller.rb + set_flash_message :notice, :updated + sign_in current_user, bypass_sign_in: true # Sign in the user bypassing validation in case his password changed + redirect_to({:controller => "registrations", :action => "edit"}, {:notice => _('Details successfully updated.')}) else + flash[:notice] = message.blank? ? _('Update unsucessful, changes not saved') : messages render "edit" end end def sign_up_params - params.require(:user).permit(:email, :password, :password_confirmation, + params.require(:user).permit(:email, :password, :password_confirmation, :accept_terms, :org_id, :other_organisation) end + def update_params + params.require(:user).permit(:firstname, :org_id, :other_organisation, + :language_id, :surname) + end + + def password_update + params.require(:user).permit(:email, :firstname, :current_password, + :org_id, :language_id, :password, + :password_confirmation, :surname, + :other_organisation) + end + end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index 8b2b71c..35c95d6 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -2,60 +2,75 @@ respond_to :html after_action :verify_authorized - def create - @role = Role.new(params[:role]) + def create + @role = Role.new(role_params) authorize @role - @role.access_level = params[:role][:access_level].to_i - if params[:role][:email].present? - message = _('User added to project') - if @role.save - if @role.user.nil? then - if User.find_by_email(params[:role][:email]).nil? then - User.invite!(email: params[:role][:email]) - message = _('Invitation issued successfully.') - @role.user = User.find_by_email(params[:role][:email]) - @role.save - else - @role.user = User.find_by_email(params[:role][:email]) - @role.save - UserMailer.sharing_notification(@role).deliver - end - else - UserMailer.sharing_notification(@role).deliver - end - flash[:notice] = message - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - else - render action: "new" - end - else - flash[:notice] = _('Please enter an email address') - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - end - end + access_level = params[:role][:access_level].to_i + set_access_level(access_level) + if params[:user].present? + message = _('User added to project') + user = User.find_by(email: params[:user]) + if user.nil? + User.invite!(email: params[:user]) + message = _('Invitation issued successfully.') + user = User.find_by(email: params[:user]) + end + @role.user = user + if @role.save + UserMailer.sharing_notification(@role).deliver + flash[:notice] = message + else + flash[:notice] = @role.errors + end + else + flash[:notice] = _('Please enter an email address') + end + redirect_to controller: 'plans', action: 'share', id: @role.plan.id + end - def update - @role = Role.find(params[:id]) + + def update + @role = Role.find(params[:id]) authorize @role - @role.access_level = params[:role][:access_level].to_i - if @role.update_attributes(params[:role]) - flash[:notice] = _('Sharing details successfully updated.') - UserMailer.permissions_change_notification(@role).deliver - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - else - render action: "edit" - end - end + access_level = params[:role][:access_level].to_i + set_access_level(access_level) + if @role.update_attributes(role_params) + flash[:notice] = _('Sharing details successfully updated.') + UserMailer.permissions_change_notification(@role).deliver + redirect_to controller: 'plans', action: 'share', id: @role.plan.id + else + render action: "edit" + end + end - def destroy - @role = Role.find(params[:id]) + def destroy + @role = Role.find(params[:id]) authorize @role - user = @role.user - plan = @role.plan - @role.destroy + user = @role.user + plan = @role.plan + @role.destroy - flash[:notice] = _('Access removed') - UserMailer.project_access_removed_notification(user, plan).deliver - redirect_to controller: 'plans', action: 'share', id: @role.plan.slug - end + flash[:notice] = _('Access removed') + UserMailer.project_access_removed_notification(user, plan).deliver + redirect_to controller: 'plans', action: 'share', id: @role.plan.slug + end + + private + + def role_params + params.require(:role).permit(:plan_id) + end + + def set_access_level(access_level) + if access_level >= 1 + @role.commenter = true + end + if access_level >= 2 + @role.editor = true + end + if access_level >= 3 + @role.administrator = true + end + end + end \ No newline at end of file diff --git a/app/controllers/settings/plans_controller.rb b/app/controllers/settings/plans_controller.rb index 9708521..c9be594 100644 --- a/app/controllers/settings/plans_controller.rb +++ b/app/controllers/settings/plans_controller.rb @@ -23,6 +23,7 @@ if params[:commit] == 'Reset' s.formatting = nil s.fields = nil + s.title = nil else s.formatting = export_params[:formatting] s.fields = export_params[:fields] @@ -31,13 +32,13 @@ end if settings.save - respond_to do |format| - format.html { redirect_to(export_project_path(@plan.project)) } - end + flash[:notice] = _('Export settings updated successfully.') else - settings.formatting = nil - @export_settings = settings - render(action: :show) + flash[:alert] = _('An error has occurred while saving/resetting your export settings.') + end + respond_to do |format| + format.html { redirect_to(show_export_plan_path(@plan.id)) } + # format.json { render json: settings_json } end end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb index e11166a..773fabb 100644 --- a/app/mailers/user_mailer.rb +++ b/app/mailers/user_mailer.rb @@ -1,19 +1,19 @@ class UserMailer < ActionMailer::Base default from: I18n.t('helpers.main_email.from') - def sharing_notification(project_group) - @project_group = project_group - mail(to: @project_group.user.email, subject: I18n.t('helpers.main_email.access_given')) + def sharing_notification(role) + @role = role + mail(to: @role.user.email, subject: I18n.t('helpers.main_email.access_given')) end - def permissions_change_notification(project_group) - @project_group = project_group - mail(to: @project_group.user.email, subject: I18n.t('helpers.main_email.permission_changed')) + def permissions_change_notification(role) + @role = role + mail(to: @role.user.email, subject: I18n.t('helpers.main_email.permission_changed')) end - def project_access_removed_notification(user, project) + def project_access_removed_notification(user, plan) @user = user - @project = project + @plan = plan mail(to: @user.email, subject: I18n.t('helpers.main_email.access_removed')) end diff --git a/app/models/exported_plan.rb b/app/models/exported_plan.rb index ae52513..0ce6426 100644 --- a/app/models/exported_plan.rb +++ b/app/models/exported_plan.rb @@ -1,5 +1,6 @@ class ExportedPlan < ActiveRecord::Base include GlobalHelpers + include SettingsTemplateHelper # TODO: REMOVE AND HANDLE ATTRIBUTE SECURITY IN THE CONTROLLER! attr_accessible :plan_id, :user_id, :format, :user, :plan, :as => [:default, :admin] @@ -8,7 +9,7 @@ belongs_to :plan belongs_to :user - VALID_FORMATS = ['csv', 'html', 'json', 'pdf', 'text', 'xml', 'docx'] + VALID_FORMATS = ['csv', 'html', 'pdf', 'text', 'docx'] validates :format, inclusion: { in: VALID_FORMATS, @@ -100,28 +101,42 @@ @admin_details ||= self.settings(:export).fields[:admin] end + # Retrieves the title field + def title + self.settings(:export).title + end + # Export formats def as_csv CSV.generate do |csv| - csv << ["Section","Question","Answer","Selected option(s)","Answered by","Answered at"] + csv << [_('Section'),_('Question'),_('Answer'),_('Selected option(s)'),_('Answered by'),_('Answered at')] self.sections.each do |section| self.questions_for_section(section).each do |question| answer = self.plan.answer(question.id) - options_string = answer.options.collect {|o| o.text}.join('; ') - - csv << [section.title, sanitize_text(question.text), sanitize_text(answer.text), options_string, answer.try(:user).try(:name), answer.created_at] + q_format = question.question_format + if q_format.title == _('Check box') || q_format.title == _('Multi select box') || + q_format.title == _('Radio buttons') || q_format.title == _('Dropdown') + options_string = answer.options.collect {|o| o.text}.join('; ') + else + options_string = '' + end + csv << [section.title, sanitize_text(question.text), sanitize_text(answer.text), options_string, user.name, answer.updated_at] end end end end def as_txt - output = "#{self.plan.project.title}\n\n#{self.plan.version.phase.title}\n" - output += "\nDetails:\n\n" - attrs = self.plan.settings(:export)[:value]['fields'][:admin].collect{|f| f.to_s} - attrs.each do |attr| - output += attr + ": " + self.send(attr) + "\n" + output = "#{self.plan.title}\n\n#{self.plan.template.title}\n" + output += "\n"+_('Details')+"\n\n" + puts 'admin_details: '+self.admin_details.inspect + + self.admin_details.each do |at| + value = self.send(at) + if value.present? + output += admin_field_t(at.to_s) + ": " + value + "\n" + end end self.sections.each do |section| @@ -132,14 +147,18 @@ output += "\n* #{qtext}" answer = self.plan.answer(question.id, false) - if answer.nil? || answer.text.nil? then + if answer.nil? output += _('Question not answered.')+ "\n" else - output += answer.options.collect {|o| o.text}.join("\n") - if question.option_comment_display == true then - output += "\n#{sanitize_text(answer.text)}\n" + q_format = question.question_format + if q_format.title == _('Check box') || q_format.title == _('Multi select box') || + q_format.title == _('Radio buttons') || q_format.title == _('Dropdown') + output += answer.options.collect {|o| o.text}.join("\n") + if question.option_comment_display + output += "\n#{sanitize_text(answer.text)}\n" + end else - output += "\n" + output += "\n#{sanitize_text(answer.text)}\n" end end end diff --git a/app/models/role.rb b/app/models/role.rb index cf49c87..cee961b 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -1,8 +1,6 @@ class Role < ActiveRecord::Base include FlagShihTzu - before_validation :check_access_level - ## # Associations belongs_to :user @@ -14,6 +12,7 @@ has_flags 1 => :creator, 2 => :administrator, 3 => :editor, + 4 => :commenter, column: 'access' validates :user, :plan, :access, presence: true @@ -24,41 +23,17 @@ # 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] def access_level - if self.administrator? then + if self.administrator? return 3 - elsif self.editor? then + elsif self.editor? return 2 - else + elsif self.commenter? return 1 end end - ## - # define a new access level for the current project group - # if >=3, the user is a project administrator - # if >=2, the user is an editor - # - # @param new_access_level [Integer] the access level to give the user - def access_level=(new_access_level) - new_access_level = new_access_level.to_i - if new_access_level >= 3 then - self.administrator = true - else - self.administrator = false - end - if new_access_level >= 2 then - self.editor = true - else - self.editor = false - end - self.creator = true unless self.administrator? || self.editor? - end - - # Ensures that the access attribute is set (will default to creator - see logic in access_level=) - def check_access_level - self.access_level = self.access_level - end end diff --git a/app/policies/plan_policy.rb b/app/policies/plan_policy.rb index cb43258..98256fe 100644 --- a/app/policies/plan_policy.rb +++ b/app/policies/plan_policy.rb @@ -28,6 +28,9 @@ @plan.readable_by?(@user.id) end + def show_export? + @plan.readable_by?(@user.id) + end def update? @plan.editable_by?(@user.id) end diff --git a/app/policies/role_policy.rb b/app/policies/role_policy.rb index 7aebf02..cf2b691 100644 --- a/app/policies/role_policy.rb +++ b/app/policies/role_policy.rb @@ -9,14 +9,14 @@ end def create? - @role.plan.administerable_by(@user.id) + @role.plan.administerable_by?(@user.id) end def update? - @role.plan.administerable_by(@user.id) + @role.plan.administerable_by?(@user.id) end def destroy? - @role.plan.administerable_by(@user.id) + @role.plan.administerable_by?(@user.id) end end \ No newline at end of file diff --git a/app/views/orgs/admin_edit.html.erb b/app/views/orgs/admin_edit.html.erb index 5d4da43..58ac1fd 100644 --- a/app/views/orgs/admin_edit.html.erb +++ b/app/views/orgs/admin_edit.html.erb @@ -63,7 +63,7 @@