Replace nonprofit creation with houdini:nonprofit:create Rails command
This commit is contained in:
parent
801cb8750a
commit
e26581dba5
21 changed files with 310 additions and 108 deletions
|
@ -371,12 +371,10 @@ app/javascript/legacy/supporters/info-card.es6
|
||||||
app/javascript/stories/index.jsx
|
app/javascript/stories/index.jsx
|
||||||
|
|
||||||
# tsx files
|
# tsx files
|
||||||
app/javascript/components/RegistrationPage.tsx
|
|
||||||
app/javascript/legacy_react/app/create_new_offsite_payment_pane.tsx
|
app/javascript/legacy_react/app/create_new_offsite_payment_pane.tsx
|
||||||
app/javascript/legacy_react/app/edit_payment_pane.tsx
|
app/javascript/legacy_react/app/edit_payment_pane.tsx
|
||||||
app/javascript/legacy_react/javascripts/app/create_new_offsite_payment_pane.tsx
|
app/javascript/legacy_react/javascripts/app/create_new_offsite_payment_pane.tsx
|
||||||
app/javascript/legacy_react/javascripts/app/edit_payment_pane.tsx
|
app/javascript/legacy_react/javascripts/app/edit_payment_pane.tsx
|
||||||
app/javascript/legacy_react/javascripts/app/registration_page.tsx
|
|
||||||
app/javascript/legacy_react/src/components/common/BootstrapWrapper.tsx
|
app/javascript/legacy_react/src/components/common/BootstrapWrapper.tsx
|
||||||
app/javascript/legacy_react/src/components/common/DefaultCloseButton.tsx
|
app/javascript/legacy_react/src/components/common/DefaultCloseButton.tsx
|
||||||
app/javascript/legacy_react/src/components/common/fields.tsx
|
app/javascript/legacy_react/src/components/common/fields.tsx
|
||||||
|
@ -423,7 +421,6 @@ app/javascript/legacy_react/src/components/registration_page/NonprofitInfoForm.s
|
||||||
app/javascript/legacy_react/src/components/registration_page/NonprofitInfoForm.tsx
|
app/javascript/legacy_react/src/components/registration_page/NonprofitInfoForm.tsx
|
||||||
app/javascript/legacy_react/src/components/registration_page/NonprofitInfoPanel.spec.tsx
|
app/javascript/legacy_react/src/components/registration_page/NonprofitInfoPanel.spec.tsx
|
||||||
app/javascript/legacy_react/src/components/registration_page/NonprofitInfoPanel.tsx
|
app/javascript/legacy_react/src/components/registration_page/NonprofitInfoPanel.tsx
|
||||||
app/javascript/legacy_react/src/components/registration_page/RegistrationPage.tsx
|
|
||||||
app/javascript/legacy_react/src/components/registration_page/RegistrationWizard.tsx
|
app/javascript/legacy_react/src/components/registration_page/RegistrationWizard.tsx
|
||||||
app/javascript/legacy_react/src/components/registration_page/UserInfoForm.tsx
|
app/javascript/legacy_react/src/components/registration_page/UserInfoForm.tsx
|
||||||
app/javascript/legacy_react/src/components/registration_page/UserInfoPanel.spec.tsx
|
app/javascript/legacy_react/src/components/registration_page/UserInfoPanel.spec.tsx
|
||||||
|
|
32
README.md
32
README.md
|
@ -181,11 +181,43 @@ Coverage report generated for RSpec to .../houdini/coverage. 10552 / 12716 LOC (
|
||||||
The important thing to look for is that the number of
|
The important thing to look for is that the number of
|
||||||
failures is zero.
|
failures is zero.
|
||||||
|
|
||||||
|
##### Creating your first nonprofits and user
|
||||||
|
|
||||||
|
To create a nonprofit, use the command line to run the following command and fill in the questions with the required information:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bin/rails houdini:nonprofit:create
|
||||||
|
```
|
||||||
|
|
||||||
|
There are available arguments that add congirugrations on the nonprofit's creation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
-su, [--super-admin], [--no-super-admin] # Make the nonprofit admin a super user (they can access any nonprofit's dashboards)
|
||||||
|
[--confirm-admin], [--no-confirm-admin] # Require the nonprofit admin to be confirmed via email
|
||||||
|
# Default: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionally, it is possible to provide arguments to fill in the fields for the nonprofit creation without coming across the questions:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
[--nonprofit-name=NONPROFIT_NAME] # Provide the nonprofit's name
|
||||||
|
[--state-code=STATE_CODE] # Provide the nonprofit' state code
|
||||||
|
[--city=CITY] # Provide the nonprofit's city
|
||||||
|
[--nonprofit-website=NONPROFIT_WEBSITE] # Provide the nonprofit public website
|
||||||
|
[--nonprofit-email=NONPROFIT_EMAIL] # Provide the nonprofit public email
|
||||||
|
[--user-name=USER_NAME] # Provide the nonprofit's admin's name
|
||||||
|
[--user-email=USER_EMAIL] # Provide the nonprofit's admin's email address (It'll be used for logging in)
|
||||||
|
[--user-phone=USER_PHONE] # [OPTIONAL] Provide the nonprofit's 's phone
|
||||||
|
[--user-password=USER_PASSWORD] # Provide the nonprofit's admin's password
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use this in the future for creating additional nonprofits.
|
||||||
#### Startup
|
#### Startup
|
||||||
|
|
||||||
`bin/rails server`
|
`bin/rails server`
|
||||||
You can connect to your server at http://localhost:5000
|
You can connect to your server at http://localhost:5000
|
||||||
|
|
||||||
|
|
||||||
##### Super admin
|
##### Super admin
|
||||||
|
|
||||||
There is a way to set your user as a super_admin. This role lets you access any of the nonprofits
|
There is a way to set your user as a super_admin. This role lets you access any of the nonprofits
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
class FrontController < ApplicationController
|
class FrontController < ApplicationController
|
||||||
def index
|
def index
|
||||||
if Nonprofit.none?
|
if current_role?(%i[nonprofit_admin nonprofit_associate])
|
||||||
redirect_to onboard_path
|
|
||||||
elsif current_role?(%i[nonprofit_admin nonprofit_associate])
|
|
||||||
redirect_to NonprofitPath.dashboard(administered_nonprofit)
|
redirect_to NonprofitPath.dashboard(administered_nonprofit)
|
||||||
elsif current_user
|
elsif current_user
|
||||||
redirect_to '/profiles/' + current_user.profile.id.to_s
|
redirect_to '/profiles/' + current_user.profile.id.to_s
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class OnboardController < ApplicationController
|
|
||||||
layout 'layouts/apified'
|
|
||||||
|
|
||||||
def index
|
|
||||||
@theme = 'minimal'
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,4 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module OnboardHelper
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
import React from "react"
|
|
||||||
require('bootstrap-loader');
|
|
||||||
import Root from "../legacy_react/src/components/common/Root"
|
|
||||||
import RegPage from "../legacy_react/src/components/registration_page/RegistrationPage"
|
|
||||||
|
|
||||||
|
|
||||||
function RegistrationPage(props:{}){
|
|
||||||
return (<Root><RegPage/></Root>)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default RegistrationPage
|
|
|
@ -1,16 +0,0 @@
|
||||||
// License: LGPL-3.0-or-later
|
|
||||||
|
|
||||||
// require a root component here. This will be treated as the root of a webpack package
|
|
||||||
import Root from "../../src/components/common/Root"
|
|
||||||
import RegistrationPage from "../../src/components/registration_page/RegistrationPage"
|
|
||||||
|
|
||||||
import * as ReactDOM from 'react-dom'
|
|
||||||
import * as React from 'react'
|
|
||||||
|
|
||||||
function LoadReactPage(element:HTMLElement) {
|
|
||||||
ReactDOM.render(<Root><RegistrationPage/></Root>, element)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
(window as any).LoadReactPage = LoadReactPage
|
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
// License: LGPL-3.0-or-later
|
|
||||||
import * as React from 'react';
|
|
||||||
import RegistrationWizard from "./RegistrationWizard";
|
|
||||||
|
|
||||||
import {observer} from 'mobx-react';
|
|
||||||
import { injectIntl, FormattedMessage, WrappedComponentProps} from 'react-intl';
|
|
||||||
|
|
||||||
|
|
||||||
export interface RegistrationPageProps
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class RegistrationPage extends React.Component<RegistrationPageProps & WrappedComponentProps, {}> {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return <div className="tw-bs"><div className="container"><h1><FormattedMessage id="registration.get_started.header"/></h1><p><FormattedMessage id="registration.get_started.description"/></p><RegistrationWizard/></div></div>
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default injectIntl(observer(RegistrationPage))
|
|
||||||
|
|
|
@ -33,8 +33,9 @@ class Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_nested_errors_for(record, attribute, other_validator)
|
def add_nested_errors_for(record, attribute, other_validator)
|
||||||
|
byebug
|
||||||
record.errors.messages[attribute] = other_validator.errors.messages
|
record.errors.messages[attribute] = other_validator.errors.messages
|
||||||
record.errors.details[attribute] = other_validator.errors.details
|
#record.errors.details[attribute] = other_validator.errors.details
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,9 +1,25 @@
|
||||||
|
|
||||||
|
class CustomAssociatedValidator < ActiveModel::EachValidator #:nodoc:
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
byebug
|
||||||
|
if Array(value).reject { |r| valid_object?(r) }.any?
|
||||||
|
record.errors.add(attribute, :invalid, **options.merge(value: value))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def valid_object?(record)
|
||||||
|
record.valid?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class CreateModel < Base
|
class CreateModel < Base
|
||||||
attr_accessor :nonprofit, :user
|
attr_accessor :nonprofit, :user
|
||||||
validates_presence_of :user
|
validates_presence_of :user
|
||||||
validates_presence_of :nonprofit
|
validates_presence_of :nonprofit
|
||||||
validate_nested_attribute :user, model_class: User
|
#validate_nested_attribute :user, model_class: User
|
||||||
validate_nested_attribute :nonprofit, model_class: Nonprofit
|
# validate_nested_attribute :nonprofit, model_class: Nonprofit
|
||||||
|
validates_with CustomAssociatedValidator, attributes: [:nonprofit]
|
||||||
|
|
||||||
before_validation do
|
before_validation do
|
||||||
nonprofit = Nonprofit.create(nonprofit) if !nonprofit.is_a? Nonprofit
|
nonprofit = Nonprofit.create(nonprofit) if !nonprofit.is_a? Nonprofit
|
||||||
|
@ -45,4 +61,6 @@ class CreateModel < Base
|
||||||
def save!
|
def save!
|
||||||
raise 'runtime' unless save
|
raise 'runtime' unless save
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,11 @@ class Nonprofit < ApplicationRecord
|
||||||
has_many :tickets, through: :events
|
has_many :tickets, through: :events
|
||||||
has_many :roles, as: :host, dependent: :destroy
|
has_many :roles, as: :host, dependent: :destroy
|
||||||
has_many :users, through: :roles
|
has_many :users, through: :roles
|
||||||
|
has_many :admins, -> { where('name = ?', :nonprofit_admin) }, through: :roles, class_name: 'User', autosave: true, source: :user do
|
||||||
|
def build_admin(**kwargs)
|
||||||
|
build(kwargs.merge({name: :nonprofit_admin}))
|
||||||
|
end
|
||||||
|
end
|
||||||
has_many :tag_masters, dependent: :destroy
|
has_many :tag_masters, dependent: :destroy
|
||||||
has_many :custom_field_masters, dependent: :destroy
|
has_many :custom_field_masters, dependent: :destroy
|
||||||
|
|
||||||
|
@ -89,6 +94,7 @@ class Nonprofit < ApplicationRecord
|
||||||
has_one :billing_plan, through: :billing_subscription
|
has_one :billing_plan, through: :billing_subscription
|
||||||
has_one :miscellaneous_np_info
|
has_one :miscellaneous_np_info
|
||||||
|
|
||||||
|
validates_associated :admins, on: :create
|
||||||
validates :name, presence: true
|
validates :name, presence: true
|
||||||
validates :city, presence: true
|
validates :city, presence: true
|
||||||
validates :state_code, presence: true
|
validates :state_code, presence: true
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
class Role < ApplicationRecord
|
class Role < ApplicationRecord
|
||||||
Names = [
|
Names = [
|
||||||
:super_admin, # global access
|
'super_admin', # global access
|
||||||
:super_associate, # global access to everything except bank acct info
|
'super_associate', # global access to everything except bank acct info
|
||||||
:nonprofit_admin, # npo scoped access to everything
|
'nonprofit_admin', # npo scoped access to everything
|
||||||
:nonprofit_associate, # npo scoped access to everything except bank acct info
|
'nonprofit_associate', # npo scoped access to everything except bank acct info
|
||||||
:campaign_editor, # fundraising tools, without dashboard access
|
'campaign_editor', # fundraising tools, without dashboard access
|
||||||
:event_editor # //
|
'event_editor' # //
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
# :name,
|
# :name,
|
||||||
|
@ -30,16 +30,12 @@ class Role < ApplicationRecord
|
||||||
validates :name, inclusion: { in: Names }
|
validates :name, inclusion: { in: Names }
|
||||||
validates :host, presence: true, unless: %i[super_admin? super_associate?]
|
validates :host, presence: true, unless: %i[super_admin? super_associate?]
|
||||||
|
|
||||||
def name
|
|
||||||
super.to_sym
|
|
||||||
end
|
|
||||||
|
|
||||||
def super_admin?
|
def super_admin?
|
||||||
name == :super_admin
|
name == 'super_admin'
|
||||||
end
|
end
|
||||||
|
|
||||||
def super_associate?
|
def super_associate?
|
||||||
name == :super_associate
|
name == 'super_associate'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.create_for_nonprofit(role_name, email, nonprofit)
|
def self.create_for_nonprofit(role_name, email, nonprofit)
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
<% content_for :title, t("registration.get_started.header") %>
|
|
||||||
<% content_for :javascripts do %>
|
|
||||||
<%= javascript_pack_tag 'loading_indicator', 'i18n', 'application' %>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= react_component('RegistrationPage', {}) %>
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#!/usr/bin/env ruby
|
#!/usr/bin/env ruby
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
$LOAD_PATH.unshift(File.expand_path('../commands', __dir__))
|
||||||
APP_PATH = File.expand_path('../config/application', __dir__)
|
APP_PATH = File.expand_path('../config/application', __dir__)
|
||||||
require_relative "../config/boot"
|
require_relative "../config/boot"
|
||||||
require_relative '../lib/generators/overrides'
|
require_relative '../lib/generators/overrides'
|
||||||
|
|
||||||
require "rails/commands"
|
require "rails/commands"
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
||||||
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
|
#
|
||||||
|
# NOTE: if this is moved to bess, it should be in the `houdini/lib/` subdirectory of bess.
|
||||||
|
#
|
||||||
|
module Houdini # rubocop:disable Style/ClassAndModuleChildren -- can't combine because Houdini hasn't been defined before
|
||||||
|
class Nonprofit # rubocop:disable Style/ClassAndModuleChildren -- can't combine becuase Nonprofit hasn't been defined before
|
||||||
|
# Used for creating nonprofits at the command line
|
||||||
|
class CreateCommand < Rails::Command::Base
|
||||||
|
desc 'Create a new nonprofit on your Houdini instance'
|
||||||
|
option :super_admin, aliases: '-su', default: false, type: :boolean,
|
||||||
|
desc: "Make the nonprofit admin a super user (they can access any nonprofit's dashboards)"
|
||||||
|
option :confirm_admin, default: true, type: :boolean, desc: 'Require the nonprofit admin to be confirmed via email'
|
||||||
|
|
||||||
|
option :nonprofit_name, default: nil, desc: "Provide the nonprofit's name"
|
||||||
|
option :state_code, default: nil, desc: "Provide the nonprofit's state code, e.g. WI for Wisconsin"
|
||||||
|
option :city, default: nil, desc: "Provide the nonprofit's city"
|
||||||
|
option :nonprofit_website, default: nil, desc: "[OPTIONAL] Provide the nonprofit's public website"
|
||||||
|
option :nonprofit_email, default: nil, desc: "[OPTIONAL] Provide the nonprofit's public email"
|
||||||
|
option :nonprofit_phone, default: nil, desc: "[OPTIONAL] Provide the nonprofit's public phone number"
|
||||||
|
|
||||||
|
option :user_name, default: nil, desc: "Provide the nonprofit's admin's name"
|
||||||
|
option :user_email, default: nil,
|
||||||
|
desc: "Provide the nonprofit's admin's email address (It'll be used for logging in)"
|
||||||
|
option :user_password, default: nil, desc: "Provide the nonprofit's admin's password"
|
||||||
|
|
||||||
|
def perform
|
||||||
|
result = {
|
||||||
|
nonprofit: ask_for_nonprofit_information(options),
|
||||||
|
user: ask_for_user_information(options)
|
||||||
|
}
|
||||||
|
say
|
||||||
|
require_application_and_environment!
|
||||||
|
|
||||||
|
creation_result = ::NonprofitCreation.new(result, options).call
|
||||||
|
|
||||||
|
creation_result[:messages].each do |msg|
|
||||||
|
say(msg)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ask_for_nonprofit_information(options)
|
||||||
|
{
|
||||||
|
name: options[:nonprofit_name] || ask("What is the nonprofit's name?"),
|
||||||
|
state_code: options[:state_code] || ask("What is the nonprofit's state?"),
|
||||||
|
city: options[:city] || ask("What is the nonprofit's city?"),
|
||||||
|
website: options[:nonprofit_website] || ask("[OPTIONAL] What is the nonprofit's public website?"),
|
||||||
|
email: options[:nonprofit_email] || ask("[OPTIONAL] What is the nonprofit's public e-mail?"),
|
||||||
|
phone: options[:nonprofit_phone] || ask("[OPTIONAL] What is your nonprofit's public phone number?")
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def ask_for_user_information(options)
|
||||||
|
{
|
||||||
|
name: options[:user_name] || ask("What is your nonprofit's admin's name?"),
|
||||||
|
email: options[:user_email] || ask(
|
||||||
|
"What is your nonprofit's admin's email address? (It'll be used for logging in)"
|
||||||
|
),
|
||||||
|
password: options[:user_password] || ask("What is the nonprofit's admin's password?", echo: false)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,6 @@ Rails.application.routes.draw do
|
||||||
get '/button_debug/embedded/:id' => 'button_debug#embedded'
|
get '/button_debug/embedded/:id' => 'button_debug#embedded'
|
||||||
get '/button_debug/button/:id' => 'button_debug#button'
|
get '/button_debug/button/:id' => 'button_debug#button'
|
||||||
end
|
end
|
||||||
get 'onboard' => 'onboard#index'
|
|
||||||
|
|
||||||
namespace(:api) do
|
namespace(:api) do
|
||||||
resources(:nonprofits)
|
resources(:nonprofits)
|
||||||
|
@ -120,7 +119,6 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
resources(:nonprofits, only: %i[show create update destroy]) do
|
resources(:nonprofits, only: %i[show create update destroy]) do
|
||||||
post(:onboard, on: :collection)
|
|
||||||
get(:profile_todos, on: :member)
|
get(:profile_todos, on: :member)
|
||||||
get(:recurring_donation_stats, on: :member)
|
get(:recurring_donation_stats, on: :member)
|
||||||
get(:search, on: :collection)
|
get(:search, on: :collection)
|
||||||
|
|
|
@ -13,6 +13,7 @@ module Houdini
|
||||||
autoload :PaymentProvider
|
autoload :PaymentProvider
|
||||||
autoload :EventPublisher
|
autoload :EventPublisher
|
||||||
autoload :WebhookAdapter
|
autoload :WebhookAdapter
|
||||||
|
autoload :NonprofitCreation
|
||||||
|
|
||||||
mattr_accessor :intl, :maintenance, :ccs
|
mattr_accessor :intl, :maintenance, :ccs
|
||||||
|
|
||||||
|
|
63
lib/nonprofit_creation.rb
Normal file
63
lib/nonprofit_creation.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
||||||
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
|
#
|
||||||
|
# NOTE: this should be moved to bess when Nonprofit and wiki is
|
||||||
|
class NonprofitCreation
|
||||||
|
def initialize(result, options = nil)
|
||||||
|
result = sanitize_optional_fields(result)
|
||||||
|
@nonprofit = ::Nonprofit.new(result[:nonprofit].merge({ register_np_only: true }))
|
||||||
|
@user = User.new(result[:user])
|
||||||
|
@options = options
|
||||||
|
end
|
||||||
|
|
||||||
|
def call
|
||||||
|
@user.skip_confirmation! if @options&.dig(:no_confirm_admin)
|
||||||
|
|
||||||
|
result = {}
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
result = if @user.save && @nonprofit.save && roles.each(&:save)
|
||||||
|
{ success: true, messages: ["Nonprofit #{@nonprofit.id} successfully created."] }
|
||||||
|
else
|
||||||
|
retrieve_error_messages
|
||||||
|
end
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def retrieve_error_messages
|
||||||
|
result = { success: false, messages: [] }
|
||||||
|
result = retrieve_user_error_messages(result)
|
||||||
|
result = retrieve_nonprofit_error_messages(result)
|
||||||
|
retrieve_roles_error_messages(result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_user_error_messages(result)
|
||||||
|
@user.errors.full_messages.each { |i| result[:messages] << "Error creating user: #{i}" }
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_nonprofit_error_messages(result)
|
||||||
|
@nonprofit.errors.full_messages.each { |i| result[:messages] << "Error creating nonprofit: #{i}" }
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def retrieve_roles_error_messages(result)
|
||||||
|
roles.each { |role| role.errors.full_messages.each { |i| result[:messages] << "Error creating role: #{i}" } }
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
def roles
|
||||||
|
roles = [Role.new(host: @nonprofit, name: 'nonprofit_admin', user: @user)]
|
||||||
|
roles << Role.new(host: @nonprofit, name: 'super_admin', user: @user) if @options&.dig(:super_admin)
|
||||||
|
roles
|
||||||
|
end
|
||||||
|
|
||||||
|
def sanitize_optional_fields(result)
|
||||||
|
result.transform_values! { |keys| keys.transform_values! { |value| value&.empty? ? nil : value } }
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,11 +15,6 @@ describe FrontController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'index redirects to onboard with no non-profits' do
|
|
||||||
get(:index)
|
|
||||||
expect(response).to redirect_to onboard_url
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'have nonprofit info' do
|
describe 'have nonprofit info' do
|
||||||
include_context :shared_user_context
|
include_context :shared_user_context
|
||||||
it 'redirect to nonprofit admin' do
|
it 'redirect to nonprofit admin' do
|
||||||
|
|
98
spec/lib/nonprofit_creation_spec.rb
Normal file
98
spec/lib/nonprofit_creation_spec.rb
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
||||||
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe NonprofitCreation do
|
||||||
|
subject { described_class.new(result, options).call }
|
||||||
|
|
||||||
|
let(:result) do
|
||||||
|
{
|
||||||
|
nonprofit: {
|
||||||
|
name: 'My Nonprofit',
|
||||||
|
state_code: 'DF',
|
||||||
|
city: 'Aguas Claras',
|
||||||
|
website: 'https://www.mynonprofit.org',
|
||||||
|
email: 'mynonprofit@email.com',
|
||||||
|
phone: '5561999999999'
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
name: 'User Name',
|
||||||
|
email: 'username@email.com',
|
||||||
|
password: 'P@ssw0rd!'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
let(:options) { { confirm_admin: true } }
|
||||||
|
|
||||||
|
describe 'command side effects' do
|
||||||
|
it { is_expected.to include(success: true, messages: ["Nonprofit #{Nonprofit.last.id} successfully created."]) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'created nonprofit' do
|
||||||
|
subject do
|
||||||
|
super()
|
||||||
|
Nonprofit.find_by(name: 'My Nonprofit')
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:expected_attributes) do
|
||||||
|
{
|
||||||
|
state_code: 'DF',
|
||||||
|
city: 'Aguas Claras',
|
||||||
|
website: 'https://www.mynonprofit.org',
|
||||||
|
email: 'mynonprofit@email.com',
|
||||||
|
phone: '5561999999999'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to have_attributes(expected_attributes) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'created user' do
|
||||||
|
subject do
|
||||||
|
super()
|
||||||
|
User.find_by(email: 'username@email.com')
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to_not be_super_admin }
|
||||||
|
it { is_expected.to_not be_confirmed }
|
||||||
|
|
||||||
|
it { is_expected.to have_attributes(name: 'User Name') }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'super_admin_option' do
|
||||||
|
subject do
|
||||||
|
super()
|
||||||
|
User.find_by(email: 'anotherusername@email.com')
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
result[:user][:email] = 'anotherusername@email.com'
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:options) { { super_admin: true } }
|
||||||
|
|
||||||
|
it { is_expected.to be_super_admin }
|
||||||
|
it { is_expected.to_not be_confirmed }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when nonprofit can not be saved' do
|
||||||
|
before do
|
||||||
|
result[:user][:email] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:expected_error_result) do
|
||||||
|
{
|
||||||
|
success: false,
|
||||||
|
messages: [
|
||||||
|
"Error creating user: Email can't be blank",
|
||||||
|
'Error creating user: Email is invalid'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it { is_expected.to eq(expected_error_result) }
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,11 +11,11 @@ describe 'Maintenance Mode' do
|
||||||
token = 'thoathioa'
|
token = 'thoathioa'
|
||||||
include_context :shared_user_context
|
include_context :shared_user_context
|
||||||
|
|
||||||
describe OnboardController, type: :controller do
|
describe SettingsController, type: :controller do
|
||||||
describe '(Onboard is just a basic example controller)'
|
describe '(Settings is just a basic example controller)'
|
||||||
it 'not in maintenance mode' do
|
it 'not in maintenance mode' do
|
||||||
get :index
|
get :index
|
||||||
assert_response 200
|
assert_response 302
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'in maintenance' do
|
describe 'in maintenance' do
|
||||||
|
@ -23,7 +23,7 @@ describe 'Maintenance Mode' do
|
||||||
Houdini.maintenance = Houdini::Maintenance.new(active: true, token: token, page: page)
|
Houdini.maintenance = Houdini::Maintenance.new(active: true, token: token, page: page)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'redirects for onboard' do
|
it 'redirects for settings' do
|
||||||
get :index
|
get :index
|
||||||
assert_redirected_to page
|
assert_redirected_to page
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue