From c20d01c4e8d9e462c87413f055df072f767d37c6 Mon Sep 17 00:00:00 2001 From: Eric Schultz Date: Tue, 21 Apr 2020 13:47:49 -0500 Subject: [PATCH] Add api/nonprofits#create --- app/controllers/api/api_controller.rb | 13 ++ app/controllers/api/nonprofits_controller.rb | 95 +------- app/helpers/api/nonprofits_helper.rb | 12 ++ app/models/nonprofit.rb | 29 +-- app/views/api/nonprofits/create.json.jbuilder | 19 ++ spec/api/houdini/nonprofit_spec.rb | 204 ------------------ .../support/api_shared_user_verification.rb | 172 --------------- .../api/nonprofits_controller_spec.rb | 142 ++---------- spec/models/nonprofit_spec.rb | 29 ++- spec/rails_helper.rb | 1 + 10 files changed, 114 insertions(+), 602 deletions(-) create mode 100644 app/controllers/api/api_controller.rb create mode 100644 app/helpers/api/nonprofits_helper.rb create mode 100644 app/views/api/nonprofits/create.json.jbuilder delete mode 100644 spec/api/houdini/nonprofit_spec.rb delete mode 100644 spec/api/support/api_shared_user_verification.rb diff --git a/app/controllers/api/api_controller.rb b/app/controllers/api/api_controller.rb new file mode 100644 index 00000000..44c5e5fa --- /dev/null +++ b/app/controllers/api/api_controller.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +class Api::ApiController < ApplicationController + rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_rescue + + protected + + def record_invalid_rescue(error) + render json:{errors: error.record.errors.messages}, status: :unprocessable_entity + end + +end \ No newline at end of file diff --git a/app/controllers/api/nonprofits_controller.rb b/app/controllers/api/nonprofits_controller.rb index 5b48dfc6..992b403a 100644 --- a/app/controllers/api/nonprofits_controller.rb +++ b/app/controllers/api/nonprofits_controller.rb @@ -1,5 +1,7 @@ -class Api::NonprofitsController < ApplicationController - rescue_from ActiveRecord::RecordInvalid, with: :record_invalid_rescue +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +class Api::NonprofitsController < Api::ApiController # requires :nonprofit, type: Hash do # requires :name, type: String, desc: 'Organization Name', allow_blank: false, documentation: { param_type: 'body' } # requires :zip_code, type: String, allow_blank: false, desc: 'Organization Address ZIP Code', documentation: { param_type: 'body' } @@ -12,94 +14,15 @@ class Api::NonprofitsController < ApplicationController # requires :email, type: String, desc: 'Username', allow_blank: false, documentation: { param_type: 'body' } # requires :password, type: String, desc: 'Password', allow_blank: false, is_equal_to: :password_confirmation, documentation: { param_type: 'body' } def create - #model = CreateModel.new(clean_params) - Qx.transaction do - # raise Errors::MessageInvalid.new(model) unless model.valid? - nonprofit = Nonprofit.new(clean_params) - nonprofit.save! - end - # Qx.transaction do - # byebug - # np = ::Nonprofit.new(OnboardAccounts.set_nonprofit_defaults(clean_params[:nonprofit])) - - # begin - # np.save! - # rescue ActiveRecord::RecordInvalid => e - # if e.record.errors[:slug] - # begin - # slug = SlugNonprofitNamingAlgorithm.new(np.state_code_slug, np.city_slug).create_copy_name(np.slug) - # np.slug = slug - # np.save! - # rescue UnableToCreateNameCopyError - # raise Grape::Exceptions::ValidationErrors.new(errors: [Grape::Exceptions::Validation.new( - # params: ['nonprofit[name]'], - # message: 'has an invalid slug. Contact support for help.' - # )]) - # end - # else - # raise e - # end - # end - - # u = User.new(clean_params[:user]) - # u.save! - - # role = u.roles.build(host: np, name: 'nonprofit_admin') - # role.save! - - # billing_plan = BillingPlan.find(Settings.default_bp.id) - # b_sub = np.build_billing_subscription(billing_plan: billing_plan, status: 'active') - # b_sub.save! - # rescue ActiveRecord::RecordInvalid => e - # class_to_name = { Nonprofit => 'nonprofit', User => 'user' } - # if class_to_name[e.record.class] - # errors = e.record.errors.keys.map do |k| - # errors = e.record.errors[k].uniq - # errors.map do |error| - # Grape::Exceptions::Validation.new( - # params: ["#{class_to_name[e.record.class]}[#{k}]"], - # message: error - # ) - # end - # end - - # raise Grape::Exceptions::ValidationErrors.new(errors: errors.flatten) - # else - # raise e - # end - # end + @nonprofit = Nonprofit.new(clean_params.merge({user_id: current_user_id})) + @nonprofit.save! + render status: :created end private - def record_invalid_rescue(error) - render json:{errors: error.record.errors.messages}, status: :unprocessable_entity - end - - def change_to_errors(message) - message.model.errors.keys.map do |k| - errors = e.record.errors[k].uniq - errors.map do |error| - Grape::Exceptions::Validation.new( - params: ["#{class_to_name[e.record.class]}[#{k}]"], - message: error - ) - end - end - end - - def flatten_errors(hash_or_array, parent=nil) - if hash_or_array.keys - result = hash_or_array.keys.map{|i| - param = !parent ? i : "#{parent}[#{i}]" - - } - else - return hash_or_array; - end - end - + def clean_params - params.permit(:name, :zip_code, :state_code, :city, :user) + params.permit(:name, :zip_code, :state_code, :city, :phone, :email, :website) end end diff --git a/app/helpers/api/nonprofits_helper.rb b/app/helpers/api/nonprofits_helper.rb new file mode 100644 index 00000000..eca003fe --- /dev/null +++ b/app/helpers/api/nonprofits_helper.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +module Api::NonprofitsHelper + def nonprofit_slug_url(nonprofit) + nonprofit_location_url city: nonprofit.city_slug, state_code: nonprofit.state_code_slug, name: nonprofit.slug + end + + def nonprofit_slug_path(nonprofit) + nonprofit_location_path city: nonprofit.city_slug, state_code: nonprofit.state_code_slug, name: nonprofit.slug + end +end diff --git a/app/models/nonprofit.rb b/app/models/nonprofit.rb index 5d89a682..38298350 100755 --- a/app/models/nonprofit.rb +++ b/app/models/nonprofit.rb @@ -83,10 +83,11 @@ class Nonprofit < ApplicationRecord validates :name, presence: true validates :city, presence: true validates :state_code, presence: true - validates :email, format: { with: Email::Regex }, allow_blank: true - validates_uniqueness_of :slug, scope: %i[city_slug state_code_slug] + validates_format_of :email, with: Email::Regex, allow_nil: true + validates_format_of :website, with: URI.regexp(['https', 'http']), allow_nil: true validates_presence_of :slug - + validates_uniqueness_of :slug, scope: %i[city_slug state_code_slug] + validates_presence_of :user_id, on: :create, unless: -> {register_np_only} validate :user_is_valid, on: :create, unless: -> {register_np_only} validate :user_registerable_as_admin, on: :create, unless: -> {register_np_only} @@ -165,7 +166,7 @@ class Nonprofit < ApplicationRecord slug = SlugNonprofitNamingAlgorithm.new(self.state_code_slug, self.city_slug).create_copy_name(self.slug) self.slug = slug rescue UnableToCreateNameCopyError - errors.add(:slug, "another nonprofit admin") + errors.add(:slug, "could not be created.") end end @@ -176,10 +177,6 @@ class Nonprofit < ApplicationRecord self end - def user_is_valid - (user && user.is_a?(User)) || errors.add(:user_id, "is not a valid user") - end - def full_address Format::Address.full_address(address, city, state_code) end @@ -228,11 +225,6 @@ class Nonprofit < ApplicationRecord Settings.intntl.all_currencies.find { |i| i.abbv.casecmp(currency).zero? }&.symbol end - def user_registerable_as_admin - if user && user.roles.nonprofit_admins.any? - errors.add(:user_id, "cannot already be an admin for a nonprofit.") - end - end private def build_admin_role role = user.roles.build(host: self, name: 'nonprofit_admin') @@ -244,4 +236,15 @@ private b_sub = build_billing_subscription(billing_plan: billing_plan, status: 'active') b_sub.save! end + + def user_registerable_as_admin + if user && user.roles.nonprofit_admins.any? + errors.add(:user_id, "cannot already be an admin for a nonprofit.") + end + end + + def user_is_valid + (user && user.is_a?(User)) || errors.add(:user_id, "is not a valid user") + end + end diff --git a/app/views/api/nonprofits/create.json.jbuilder b/app/views/api/nonprofits/create.json.jbuilder new file mode 100644 index 00000000..388e5ef7 --- /dev/null +++ b/app/views/api/nonprofits/create.json.jbuilder @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later +json.id @nonprofit.id +json.name @nonprofit.name +json.city @nonprofit.city +json.state_code @nonprofit.state_code +json.zip_code @nonprofit.zip_code +json.state_code_slug @nonprofit.state_code_slug +json.city_slug @nonprofit.city_slug +json.slug @nonprofit.slug +json.email @nonprofit.email +json.website @nonprofit.website +json.phone @nonprofit.phone + +json.urls do + json.plain_url nonprofit_url(@nonprofit) + json.slug_url nonprofit_slug_url(@nonprofit) +end \ No newline at end of file diff --git a/spec/api/houdini/nonprofit_spec.rb b/spec/api/houdini/nonprofit_spec.rb deleted file mode 100644 index 86c37ce8..00000000 --- a/spec/api/houdini/nonprofit_spec.rb +++ /dev/null @@ -1,204 +0,0 @@ -# frozen_string_literal: true - -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'rails_helper' - -describe 'HOUDINI NOnprofit_spec', type: :request do - describe 'get' do - end - - describe 'post' do - around(:each) do |example| - @old_bp = Settings.default_bp - example.run - Settings.default_bp = @old_bp - end - def expect_validation_errors(actual, input) - expected_errors = input.with_indifferent_access[:errors] - expect(actual['errors']).to match_array expected_errors - end - - def create_errors(*wrapper_params) - output = totally_empty_errors - wrapper_params.each { |i| output[:errors].push(h(params: [i], messages: gr_e('presence'))) } - output - end - - def h(h = {}) - h.with_indifferent_access - end - - let(:totally_empty_errors) do - { - errors: - [ - h(params: ['nonprofit[name]'], messages: gr_e('presence', 'blank')), - h(params: ['nonprofit[zip_code]'], messages: gr_e('presence', 'blank')), - h(params: ['nonprofit[state_code]'], messages: gr_e('presence', 'blank')), - h(params: ['nonprofit[city]'], messages: gr_e('presence', 'blank')), - - h(params: ['user[name]'], messages: gr_e('presence', 'blank')), - h(params: ['user[email]'], messages: gr_e('presence', 'blank')), - h(params: ['user[password]'], messages: gr_e('presence', 'blank')), - h(params: ['user[password_confirmation]'], messages: gr_e('presence', 'blank')) - ] - - }.with_indifferent_access - end - describe 'authorization' do - around(:each) do |e| - Rails.configuration.action_controller.allow_forgery_protection = true - e.run - Rails.configuration.action_controller.allow_forgery_protection = false - end - - it 'rejects csrf' do - post '/api/nonprofits', params: {}, xhr: true - expect(response.code).to eq '400' - end - end - - it 'validates nothing' do - input = {} - post '/api/nonprofits', params: input, xhr: true - expect(response.code).to eq '400' - expect_validation_errors(JSON.parse(response.body), create_errors('nonprofit', 'user')) - end - - it 'validates url, email, phone ' do - input = { - nonprofit: { - email: 'noemeila', - phone: 'notphone', - url: '' - } - } - post '/api/nonprofits', params: input, xhr: true - expect(response.code).to eq '400' - expected = create_errors('user') - expected[:errors].push(h(params: ['nonprofit[email]'], messages: gr_e('regexp'))) - # expected[:errors].push(h(params:["nonprofit[phone]"], messages: gr_e("regexp"))) - # expected[:errors].push(h(params:["nonprofit[url]"], messages: gr_e("regexp"))) - - expect_validation_errors(JSON.parse(response.body), expected) - end - - it 'should reject unmatching passwords ' do - input = { - - user: { - email: 'wmeil@email.com', - name: 'name', - password: 'password', - password_confirmation: 'doesn\'t match' - } - } - post '/api/nonprofits', params: input, xhr: true - expect(response.code).to eq '400' - expect(JSON.parse(response.body)['errors']).to include(h(params: ['user[password]', 'user[password_confirmation]'], messages: gr_e('is_equal_to'))) - end - - it 'attempts to make a slug copy and returns the proper errors' do - force_create(:nm_justice, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton') - input = { - nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915 }, - user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' } - } - - expect_any_instance_of(SlugNonprofitNamingAlgorithm).to receive(:create_copy_name).and_raise(UnableToCreateNameCopyError.new) - - post '/api/nonprofits', params: input, xhr: true - expect(response.code).to eq '400' - - expect_validation_errors(JSON.parse(response.body), - errors: [ - h( - params: ['nonprofit[name]'], - messages: ['has an invalid slug. Contact support for help.'] - ) - ]) - end - - it 'errors on attempt to add user with email that already exists' do - force_create(:user, email: 'em@em.com') - - input = { - nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915 }, - user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' } - } - - post '/api/nonprofits', params: input, xhr: true - expect(response.code).to eq '400' - - expect_validation_errors(JSON.parse(response.body), - errors: [ - h( - params: ['user[email]'], - messages: ['has already been taken'] - ) - ]) - end - - it 'succeeds' do - force_create(:nm_justice, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton') - input = { - nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, url: 'www.cs.c', website: 'www.cs.c' }, - user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' } - } - - bp = force_create(:billing_plan) - Settings.default_bp.id = bp.id - - # expect(Houdini::V1::Nonprofit).to receive(:sign_in) - - post '/api/nonprofits', params: input, xhr: true - expect(response.code).to eq '201' - - our_np = Nonprofit.all[1] - expected_np = { - name: 'n', - state_code: 'WI', - city: 'appleton', - zip_code: '54915', - state_code_slug: 'wi', - city_slug: 'appleton', - slug: 'n-00', - website: 'http://www.cs.c' - }.with_indifferent_access - - expected_np = our_np.attributes.with_indifferent_access.merge(expected_np) - expect(our_np.attributes).to eq expected_np - - expect(our_np.billing_subscription.billing_plan).to eq bp - - response_body = { - id: our_np.id - }.with_indifferent_access - - expect(JSON.parse(response.body)).to eq response_body - - user = User.first - expected_user = { - email: 'em@em.com', - name: 'Name' - } - - expected_user = user.attributes.with_indifferent_access.merge(expected_user) - expect(our_np.roles.nonprofit_admins.count).to eq 1 - expect(our_np.roles.nonprofit_admins.first.user.attributes).to eq expected_user - end - end -end - -def find_error_message(json, field_name) - errors = json['errors'] - - error = errors.select { |i| i['params'].any? { |j| j == field_name } }.first - return error unless error - - error['messages'] -end - -def gr_e(*keys) - keys.map { |i| I18n.translate('grape.errors.messages.' + i, locale: 'en') } -end diff --git a/spec/api/support/api_shared_user_verification.rb b/spec/api/support/api_shared_user_verification.rb deleted file mode 100644 index 715bd6a8..00000000 --- a/spec/api/support/api_shared_user_verification.rb +++ /dev/null @@ -1,172 +0,0 @@ -# frozen_string_literal: true - -# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later -require 'controllers/support/general_shared_user_context' -RSpec.shared_context :api_shared_user_verification do - include_context :general_shared_user_context - let(:user_as_np_admin) do - __create_admin(nonprofit) - end - - let(:user_as_other_np_admin) do - __create_admin(other_nonprofit) - end - - let(:user_as_np_associate) do - __create_associate(nonprofit) - end - - let(:user_as_other_np_associate) do - __create_associate(other_nonprofit) - end - - let(:unauth_user) do - force_create(:user) - end - - let(:campaign_editor) do - __create(:campaign_editor, campaign) - end - - let(:confirmed_user) do - force_create(:user, confirmed_at: Time.current) - end - - let(:event_editor) do - __create(:event_editor, event) - end - - let(:super_admin) do - __create(:super_admin, other_nonprofit) - end - - let(:user_with_profile) do - u = force_create(:user) - force_create(:profile, user: u) - u - end - - let(:all_users) do - { user_as_np_admin: user_as_np_admin, - user_as_other_np_admin: user_as_other_np_admin, - user_as_np_associate: user_as_np_associate, - user_as_other_np_associate: user_as_other_np_associate, - unauth_user: unauth_user, - campaign_editor: campaign_editor, - event_editor: event_editor, - super_admin: super_admin, - user_with_profile: user_with_profile } - end - - let(:roles__open_to_all) do - [nil, :user_as_np_admin, - :user_as_other_np_admin, - :user_as_np_associate, - :user_as_other_np_associate, - :unauth_user, - :campaign_editor, - :event_editor, - :super_admin, - :user_with_profile] - end - - let(:roles__open_to_np_associate) do - %i[user_as_np_admin - - user_as_np_associate - - super_admin] - end - - def __create(name, host) - u = force_create(:user) - force_create(:role, user: u, name: name, host: host) - u - end - - def __create_admin(host) - u = force_create(:user) - force_create(:role, user: u, name: :nonprofit_admin, host: host) - u - end - - def __create_associate(host) - u = force_create(:user) - force_create(:role, user: u, name: :nonprofit_associate, host: host) - u - end - - def sign_in(user_to_signin) - post_via_redirect 'users/sign_in', 'user[email]' => user_to_signin.email, 'user[password]' => user_to_signin.password, format: 'json' - end - - def sign_out - send(:get, 'users/sign_out') - end - - def send(method, *args) - case method - when :get - xhr(:get, *args) - when :post - xhr(:post, *args) - when :delete - xhr(:delete, *args) - when :put - xhr(:put, *args) - end - end - - def accept(user_to_signin:, method:, action:, args:) - new_user = user_to_signin - if !user_to_signin.nil? && user_to_signin.is_a?(OpenStruct) - new_user = user_to_signin.value - end - sign_in new_user if new_user - # allows us to run the helpers but ignore what the controller action does - # - send(method, action, args) - expect(response.status).to eq(200), "expcted success for user: #{(user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ':' : '')} #{new_user&.attributes}" - sign_out - end - - def reject(user_to_signin:, method:, action:, args:) - new_user = user_to_signin - if !user_to_signin.nil? && user_to_signin.is_a?(OpenStruct) - new_user = user_to_signin.value - end - sign_in new_user if new_user - send(method, action, args) - expect(response.status).to eq(401), "expected failure for user: #{(user_to_signin.is_a?(OpenStruct) ? user_to_signin.key.to_s + ':' : '')} #{new_user&.attributes}" - sign_out - end - - alias_method :redirects_to, :reject - - def run_authorization_tests(details, &block) - @method = details[:method] - @successful_users = details[:successful_users] - @action = details[:action] - @block_to_get_arguments_to_run = block || ->(_) {} # no-op - accept_test_for_nil = false - all_users.each do |k, v| - os = OpenStruct.new - os.key = k - os.value = v - - if k.nil? - accept(user_to_signin: nil, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v)) - accept_test_for_nil = true - end - if @successful_users.include? k - accept(user_to_signin: os, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v)) - else - reject(user_to_signin: os, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(v)) - end - end - - unless accept_test_for_nil - reject(user_to_signin: nil, method: @method, action: @action, args: @block_to_get_arguments_to_run.call(nil)) - end - end -end diff --git a/spec/controllers/api/nonprofits_controller_spec.rb b/spec/controllers/api/nonprofits_controller_spec.rb index 874e0a27..86913965 100644 --- a/spec/controllers/api/nonprofits_controller_spec.rb +++ b/spec/controllers/api/nonprofits_controller_spec.rb @@ -9,115 +9,35 @@ describe Api::NonprofitsController, type: :request do role end let(:nonprofit) {create(:nm_justice)} + describe 'get' do end - describe 'post' do + describe 'create' do around(:each) do |example| @old_bp = Settings.default_bp example.run Settings.default_bp = @old_bp end - def expect_validation_errors(actual, input) - expected_errors = input.with_indifferent_access[:errors] - expect(actual['errors']).to match_array expected_errors - end - def create_errors(*wrapper_params) - output = totally_empty_errors - wrapper_params.each { |i| output[:errors].push(h(params: [i], messages: gr_e('presence'))) } - output - end - - def h(h = {}) - h.with_indifferent_access - end - - describe 'authorization' do - around(:each) do |e| - Rails.configuration.action_controller.allow_forgery_protection = true - e.run - Rails.configuration.action_controller.allow_forgery_protection = false - end - - it 'rejects csrf' do - post :create, params: {}, xhr: true - expect(response.code).to eq '400' - end - end - - it 'validates nothing' do + it 'validates and returns correct errors' do input = {} post '/api/nonprofits', params: input, xhr: true expect(response).to have_http_status :unprocessable_entity - expect(response.parsed_body['errors'].keys).to match_array ['name', 'city', 'state_code', 'slug', 'user'] - end - - it 'validates url, email, phone ' do - input = { - nonprofit: { - email: 'noemeila', - phone: 'notphone', - url: '' - } - } - post :create, params: input, xhr: true - expect(response.code).to eq '400' - expected = create_errors('user') - expected[:errors].push(h(params: ['nonprofit[email]'], messages: gr_e('regexp'))) - # expected[:errors].push(h(params:["nonprofit[phone]"], messages: gr_e("regexp"))) - # expected[:errors].push(h(params:["nonprofit[url]"], messages: gr_e("regexp"))) - - expect_validation_errors(JSON.parse(response.body), expected) - end - - it 'attempts to make a slug copy and returns the proper errors' do - force_create(:nonprofit, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton') - input = { - nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915 }, - user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' } - } - - expect_any_instance_of(SlugNonprofitNamingAlgorithm).to receive(:create_copy_name).and_raise(UnableToCreateNameCopyError.new) - - post :create, params: input, xhr: true - expect(response.code).to eq '400' - - expect_validation_errors(JSON.parse(response.body), - errors: [ - h( - params: ['nonprofit[name]'], - messages: ['has an invalid slug. Contact support for help.'] - ) - ]) - end - - it 'errors on attempt to add the user to a second nonprofit' do - nonprofit_admin_role - input = { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, user_id: user.id } - post '/api/nonprofits', params: input, xhr:true - expect(response).to have_http_status :unprocessable_entity - expect(response.parsed_body['errors'].keys).to match_array 'user' - byebug - expect(response.parsed_body['errors']['user'].first).to has_include? 'nonprofit admin' + expect(response.parsed_body['errors'].keys).to match_array ['name', 'city', 'state_code', 'slug', 'user_id'] end it 'succeeds' do - force_create(:nonprofit, slug: 'n', state_code_slug: 'wi', city_slug: 'appleton') - input = { - nonprofit: { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, url: 'www.cs.c', website: 'www.cs.c' }, - user: { name: 'Name', email: 'em@em.com', password: '12345678', password_confirmation: '12345678' } - } - + input = { name: 'n', state_code: 'WI', city: 'appleton', zip_code: 54_915, user_id: user.id, phone: '920-555-5555' } + sign_in user bp = force_create(:billing_plan) Settings.default_bp.id = bp.id - # expect(Houdini::V1::Nonprofit).to receive(:sign_in) + sign_in user - post :create, params: input, xhr: true - expect(response.code).to eq '201' + post '/api/nonprofits', params: input, xhr: true + expect(response).to have_http_status :created - our_np = Nonprofit.all[1] expected_np = { name: 'n', state_code: 'WI', @@ -125,45 +45,17 @@ describe Api::NonprofitsController, type: :request do zip_code: '54915', state_code_slug: 'wi', city_slug: 'appleton', - slug: 'n-00', - website: 'http://www.cs.c' + slug: 'n', + phone: '920-555-5555', + email: nil, + website: nil, + urls: {plain_url: "http://www.example.com/nonprofits/1", slug_url: "http://www.example.com/wi/appleton/n"} }.with_indifferent_access - - expected_np = our_np.attributes.with_indifferent_access.merge(expected_np) - expect(our_np.attributes).to eq expected_np - - expect(our_np.billing_subscription.billing_plan).to eq bp - - response_body = { - id: our_np.id - }.with_indifferent_access - - expect(JSON.parse(response.body)).to eq response_body - - user = User.first - expected_user = { - email: 'em@em.com', - name: 'Name' - } - - expected_user = user.attributes.with_indifferent_access.merge(expected_user) - expect(our_np.roles.nonprofit_admins.count).to eq 1 - expect(our_np.roles.nonprofit_admins.first.user.attributes).to eq expected_user + + expect(response.parsed_body['id']).to be > 0 + expect(response.parsed_body.except('id')).to eq expected_np end end end -def find_error_message(json, field_name) - errors = json['errors'] - - error = errors.select { |i| i['params'].any? { |j| j == field_name } }.first - return error unless error - - error['messages'] -end - -def gr_e(*keys) - keys.map { |i| I18n.translate('grape.errors.messages.' + i, locale: 'en') } -end - diff --git a/spec/models/nonprofit_spec.rb b/spec/models/nonprofit_spec.rb index 54849d11..d1dc8149 100644 --- a/spec/models/nonprofit_spec.rb +++ b/spec/models/nonprofit_spec.rb @@ -53,6 +53,8 @@ RSpec.describe Nonprofit, type: :model do let(:nonprofit_with_same_name) { Nonprofit.new({name: "New Mexico Equality", state_code: nm_justice.state_code, city: nm_justice.city, user_id: user.id})} let(:nonprofit_with_same_name_but_different_state) { Nonprofit.new({name: "New Mexico Equality", state_code: 'mn', city: nm_justice.city, user_id: user.id })} + let(:nonprofit_with_bad_email_and_website) { Nonprofit.new({email: 'not_email', website: 'not_website'})} + let(:user) { create(:user)} let(:nonprofit_admin_role) do role = user.roles.build(host: nonprofit, name: 'nonprofit_admin') @@ -61,7 +63,15 @@ RSpec.describe Nonprofit, type: :model do end let(:nm_justice) {create(:nm_justice)} - before(:each) { nonprofit.valid?; nonprofit_with_invalid_user.valid?; nonprofit_with_user_who_already_admin.valid?; nonprofit_with_same_name.valid?; nonprofit_with_same_name_but_different_state.valid?} + before(:each) do + nonprofit.valid? + nonprofit_with_invalid_user.valid? + nonprofit_with_user_who_already_admin.valid? + nonprofit_with_same_name.valid? + nonprofit_with_same_name_but_different_state.valid? + nonprofit_with_bad_email_and_website.valid? + end + it 'has an error for no name' do expect(nonprofit.errors['name'].first).to match /.*blank.*/ end @@ -91,10 +101,25 @@ RSpec.describe Nonprofit, type: :model do expect(nonprofit_with_same_name.slug).to eq "#{nm_justice.slug}-00" end - it 'does nothing to a slug when it tries to save' do + it 'does nothing to a slug when a slug was provided' do expect(nonprofit_with_same_name_but_different_state.errors['slug']).to be_empty expect(nonprofit_with_same_name_but_different_state.slug).to eq "#{nm_justice.slug}" end + + it 'marks email as having errors if they do' do + expect(nonprofit_with_bad_email_and_website.errors['email'].first).to match /.*invalid.*/ + end + + it 'marks website as having errors if they do' do + expect(nonprofit_with_bad_email_and_website.errors['website'].first).to match /.*invalid.*/ + end + + it 'marks an nonprofit as invalid when no slug could be created ' do + nonprofit = Nonprofit.new({name: nm_justice.name, city: nm_justice.city, state_code: nm_justice.state_code, slug: nm_justice.slug}) + expect_any_instance_of(SlugNonprofitNamingAlgorithm).to receive(:create_copy_name).and_raise(UnableToCreateNameCopyError.new) + nonprofit.valid? + expect(nonprofit.errors['slug'].first).to match /.*could not be created.*/ + end end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 79e26590..8af99c06 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -70,5 +70,6 @@ RSpec.configure do |config| # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") config.include Devise::Test::ControllerHelpers, type: :controller + config.include Devise::Test::IntegrationHelpers, type: :request config.include RSpec::Rails::RequestExampleGroup, type: :request, file_path: %r{spec/api} end