From 34e8ad9dc55ec55137f8b8b066e1da63186b1eca Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 25 Jan 2022 16:58:49 -0800 Subject: [PATCH] feat: Unify user and super admin credentials (#3830) Fixes: #3061, #3489 --- app/builders/account_builder.rb | 3 +- .../installation/onboarding_controller.rb | 1 + .../super_admin/devise/sessions_controller.rb | 2 +- .../super_admin/super_admins_controller.rb | 44 ----------- .../super_admin/users_controller.rb | 13 ++-- app/dashboards/super_admin_dashboard.rb | 75 ------------------- app/dashboards/user_dashboard.rb | 6 ++ app/models/concerns/avatarable.rb | 2 +- app/models/super_admin.rb | 50 ++++++++----- app/models/user.rb | 1 + app/views/fields/belongs_to/_form.html.erb | 26 +++++++ app/views/fields/belongs_to/_index.html.erb | 32 ++++++++ app/views/fields/belongs_to/_show.html.erb | 27 +++++++ app/views/fields/polymorphic/_form.html.erb | 29 +++++++ app/views/fields/polymorphic/_index.html.erb | 31 ++++++++ app/views/fields/polymorphic/_show.html.erb | 28 +++++++ .../application/_navigation.html.erb | 5 ++ .../super_admin/users/_collection.html.erb | 8 +- config/initializers/rack_attack.rb | 9 +++ config/routes.rb | 1 - .../20220121055444_add_type_to_users.rb | 42 +++++++++++ db/schema.rb | 3 +- db/seeds.rb | 3 +- .../access_tokens_controller_spec.rb | 2 +- .../account_users_controller_spec.rb | 2 +- .../super_admin/accounts_controller_spec.rb | 2 +- .../super_admin/agent_bots_controller_spec.rb | 2 +- .../super_admin/app_config_controller_spec.rb | 4 +- .../installation_configs_controller_spec.rb | 6 +- .../platform_apps_controller_spec.rb | 2 +- .../super_admins_controller_spec.rb | 24 ------ .../super_admin/users_controller_spec.rb | 2 +- .../super_admin_controller_spec.rb | 46 ------------ spec/factories/super_admins.rb | 3 + 34 files changed, 303 insertions(+), 233 deletions(-) delete mode 100644 app/controllers/super_admin/super_admins_controller.rb delete mode 100644 app/dashboards/super_admin_dashboard.rb create mode 100644 app/views/fields/belongs_to/_form.html.erb create mode 100644 app/views/fields/belongs_to/_index.html.erb create mode 100644 app/views/fields/belongs_to/_show.html.erb create mode 100644 app/views/fields/polymorphic/_form.html.erb create mode 100644 app/views/fields/polymorphic/_index.html.erb create mode 100644 app/views/fields/polymorphic/_show.html.erb create mode 100644 db/migrate/20220121055444_add_type_to_users.rb delete mode 100644 spec/controllers/super_admin/super_admins_controller_spec.rb delete mode 100644 spec/controllers/super_admin_controller_spec.rb diff --git a/app/builders/account_builder.rb b/app/builders/account_builder.rb index 0464c8013..575f14aaa 100644 --- a/app/builders/account_builder.rb +++ b/app/builders/account_builder.rb @@ -2,7 +2,7 @@ class AccountBuilder include CustomExceptions::Account - pattr_initialize [:account_name!, :email!, :confirmed, :user, :user_full_name, :user_password] + pattr_initialize [:account_name!, :email!, :confirmed, :user, :user_full_name, :user_password, :super_admin] def perform if @user.nil? @@ -65,6 +65,7 @@ class AccountBuilder password: user_password, password_confirmation: user_password, name: @user_full_name) + @user.type = 'SuperAdmin' if @super_admin @user.confirm if @confirmed @user.save! end diff --git a/app/controllers/installation/onboarding_controller.rb b/app/controllers/installation/onboarding_controller.rb index 130938fd8..272b4e5eb 100644 --- a/app/controllers/installation/onboarding_controller.rb +++ b/app/controllers/installation/onboarding_controller.rb @@ -10,6 +10,7 @@ class Installation::OnboardingController < ApplicationController user_full_name: onboarding_params.dig(:user, :name), email: onboarding_params.dig(:user, :email), user_password: params.dig(:user, :password), + super_admin: true, confirmed: true ).perform rescue StandardError => e diff --git a/app/controllers/super_admin/devise/sessions_controller.rb b/app/controllers/super_admin/devise/sessions_controller.rb index de7002206..b5e50d177 100644 --- a/app/controllers/super_admin/devise/sessions_controller.rb +++ b/app/controllers/super_admin/devise/sessions_controller.rb @@ -8,7 +8,7 @@ class SuperAdmin::Devise::SessionsController < Devise::SessionsController def create redirect_to(super_admin_session_path, flash: { error: @error_message }) && return unless valid_credentials? - sign_in(@super_admin, scope: :super_admin) + sign_in(:super_admin, @super_admin) flash.discard redirect_to super_admin_users_path end diff --git a/app/controllers/super_admin/super_admins_controller.rb b/app/controllers/super_admin/super_admins_controller.rb deleted file mode 100644 index 16d91a151..000000000 --- a/app/controllers/super_admin/super_admins_controller.rb +++ /dev/null @@ -1,44 +0,0 @@ -class SuperAdmin::SuperAdminsController < SuperAdmin::ApplicationController - # Overwrite any of the RESTful controller actions to implement custom behavior - # For example, you may want to send an email after a foo is updated. - # - # def update - # super - # send_foo_updated_email(requested_resource) - # end - - # Override this method to specify custom lookup behavior. - # This will be used to set the resource for the `show`, `edit`, and `update` - # actions. - # - # def find_resource(param) - # Foo.find_by!(slug: param) - # end - - # The result of this lookup will be available as `requested_resource` - - # Override this if you have certain roles that require a subset - # this will be used to set the records shown on the `index` action. - # - # def scoped_resource - # if current_user.super_admin? - # resource_class - # else - # resource_class.with_less_stuff - # end - # end - - # Override `resource_params` if you want to transform the submitted - # data before it's persisted. For example, the following would turn all - # empty values into nil values. It uses other APIs such as `resource_class` - # and `dashboard`: - # - # def resource_params - # params.require(resource_class.model_name.param_key). - # permit(dashboard.permitted_attributes). - # transform_values { |value| value == "" ? nil : value } - # end - - # See https://administrate-prototype.herokuapp.com/customizing_controller_actions - # for more information -end diff --git a/app/controllers/super_admin/users_controller.rb b/app/controllers/super_admin/users_controller.rb index 613670849..23c212c29 100644 --- a/app/controllers/super_admin/users_controller.rb +++ b/app/controllers/super_admin/users_controller.rb @@ -33,12 +33,15 @@ class SuperAdmin::UsersController < SuperAdmin::ApplicationController # empty values into nil values. It uses other APIs such as `resource_class` # and `dashboard`: # - # def resource_params - # params.require(resource_class.model_name.param_key). - # permit(dashboard.permitted_attributes). - # transform_values { |value| value == "" ? nil : value } - # end + def resource_params + permitted_params = super + permitted_params.delete(:password) if permitted_params[:password].blank? + permitted_params + end # See https://administrate-prototype.herokuapp.com/customizing_controller_actions # for more information + def find_resource(param) + super.becomes(User) + end end diff --git a/app/dashboards/super_admin_dashboard.rb b/app/dashboards/super_admin_dashboard.rb deleted file mode 100644 index 1d9afd1ba..000000000 --- a/app/dashboards/super_admin_dashboard.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'administrate/base_dashboard' - -class SuperAdminDashboard < Administrate::BaseDashboard - # ATTRIBUTE_TYPES - # a hash that describes the type of each of the model's fields. - # - # Each different type represents an Administrate::Field object, - # which determines how the attribute is displayed - # on pages throughout the dashboard. - ATTRIBUTE_TYPES = { - id: Field::Number, - email: Field::String, - password: Field::Password, - remember_created_at: Field::DateTime, - sign_in_count: Field::Number, - current_sign_in_at: Field::DateTime, - last_sign_in_at: Field::DateTime, - current_sign_in_ip: Field::String.with_options(searchable: false), - last_sign_in_ip: Field::String.with_options(searchable: false), - created_at: Field::DateTime, - updated_at: Field::DateTime - }.freeze - - # COLLECTION_ATTRIBUTES - # an array of attributes that will be displayed on the model's index page. - # - # By default, it's limited to four items to reduce clutter on index pages. - # Feel free to add, remove, or rearrange items. - COLLECTION_ATTRIBUTES = %i[ - id - email - ].freeze - - # SHOW_PAGE_ATTRIBUTES - # an array of attributes that will be displayed on the model's show page. - SHOW_PAGE_ATTRIBUTES = %i[ - id - email - remember_created_at - sign_in_count - current_sign_in_at - last_sign_in_at - current_sign_in_ip - last_sign_in_ip - created_at - updated_at - ].freeze - - # FORM_ATTRIBUTES - # an array of attributes that will be displayed - # on the model's form (`new` and `edit`) pages. - FORM_ATTRIBUTES = %i[ - email - password - ].freeze - - # COLLECTION_FILTERS - # a hash that defines filters that can be used while searching via the search - # field of the dashboard. - # - # For example to add an option to search for open resources by typing "open:" - # in the search field: - # - # COLLECTION_FILTERS = { - # open: ->(resources) { resources.where(open: true) } - # }.freeze - COLLECTION_FILTERS = {}.freeze - - # Overwrite this method to customize how super admins are displayed - # across all pages of the admin dashboard. - # - # def display_resource(super_admin) - # "SuperAdmin ##{super_admin.id}" - # end -end diff --git a/app/dashboards/user_dashboard.rb b/app/dashboards/user_dashboard.rb index f34f48257..1d59525f2 100644 --- a/app/dashboards/user_dashboard.rb +++ b/app/dashboards/user_dashboard.rb @@ -30,6 +30,7 @@ class UserDashboard < Administrate::BaseDashboard created_at: Field::DateTime, updated_at: Field::DateTime, pubsub_token: Field::String, + type: Field::Select.with_options(collection: [nil, 'SuperAdmin']), accounts: CountField }.freeze @@ -44,6 +45,7 @@ class UserDashboard < Administrate::BaseDashboard name email accounts + type ].freeze # SHOW_PAGE_ATTRIBUTES @@ -53,10 +55,12 @@ class UserDashboard < Administrate::BaseDashboard avatar_url unconfirmed_email name + type display_name email created_at updated_at + confirmed_at account_users ].freeze @@ -68,6 +72,8 @@ class UserDashboard < Administrate::BaseDashboard display_name email password + confirmed_at + type ].freeze # COLLECTION_FILTERS diff --git a/app/models/concerns/avatarable.rb b/app/models/concerns/avatarable.rb index d5bcb862d..441afa106 100644 --- a/app/models/concerns/avatarable.rb +++ b/app/models/concerns/avatarable.rb @@ -12,7 +12,7 @@ module Avatarable def avatar_url return url_for(avatar.representation(resize: '250x250')) if avatar.attached? && avatar.representable? - if [User, Contact].include?(self.class) && email.present? + if [SuperAdmin, User, Contact].include?(self.class) && email.present? hash = Digest::MD5.hexdigest(email) return "https://www.gravatar.com/avatar/#{hash}?d=404" end diff --git a/app/models/super_admin.rb b/app/models/super_admin.rb index 5bad00c05..acc5f28dd 100644 --- a/app/models/super_admin.rb +++ b/app/models/super_admin.rb @@ -1,25 +1,41 @@ # == Schema Information # -# Table name: super_admins +# Table name: users # -# id :bigint not null, primary key -# current_sign_in_at :datetime -# current_sign_in_ip :inet -# email :string default(""), not null -# encrypted_password :string default(""), not null -# last_sign_in_at :datetime -# last_sign_in_ip :inet -# remember_created_at :datetime -# sign_in_count :integer default(0), not null -# created_at :datetime not null -# updated_at :datetime not null +# id :integer not null, primary key +# availability :integer default("online") +# confirmation_sent_at :datetime +# confirmation_token :string +# confirmed_at :datetime +# current_sign_in_at :datetime +# current_sign_in_ip :string +# custom_attributes :jsonb +# display_name :string +# email :string +# encrypted_password :string default(""), not null +# last_sign_in_at :datetime +# last_sign_in_ip :string +# name :string not null +# provider :string default("email"), not null +# pubsub_token :string +# remember_created_at :datetime +# reset_password_sent_at :datetime +# reset_password_token :string +# sign_in_count :integer default(0), not null +# tokens :json +# type :string +# ui_settings :jsonb +# uid :string default(""), not null +# unconfirmed_email :string +# created_at :datetime not null +# updated_at :datetime not null # # Indexes # -# index_super_admins_on_email (email) UNIQUE +# index_users_on_email (email) +# index_users_on_pubsub_token (pubsub_token) UNIQUE +# index_users_on_reset_password_token (reset_password_token) UNIQUE +# index_users_on_uid_and_provider (uid,provider) UNIQUE # -class SuperAdmin < ApplicationRecord - # Include default devise modules. Others available are: - # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable - devise :database_authenticatable, :trackable, :rememberable, :validatable, :password_has_required_content +class SuperAdmin < User end diff --git a/app/models/user.rb b/app/models/user.rb index 16798904c..773277e15 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,6 +23,7 @@ # reset_password_token :string # sign_in_count :integer default(0), not null # tokens :json +# type :string # ui_settings :jsonb # uid :string default(""), not null # unconfirmed_email :string diff --git a/app/views/fields/belongs_to/_form.html.erb b/app/views/fields/belongs_to/_form.html.erb new file mode 100644 index 000000000..5e8b62ca3 --- /dev/null +++ b/app/views/fields/belongs_to/_form.html.erb @@ -0,0 +1,26 @@ +<%# +# BelongsTo Form Partial + +This partial renders an input element for belongs_to relationships. +By default, the input is a collection select box +that displays all possible records to associate with. + +## Local variables: + +- `f`: + A Rails form generator, used to help create the appropriate input fields. +- `field`: + An instance of [Administrate::Field::BelongsTo][1]. + Contains helper methods for displaying a collection select box. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/BelongsTo +%> + +
+ <%= f.label field.permitted_attribute %> +
+
+ <%= f.select(field.permitted_attribute, + options_for_select(field.associated_resource_options, field.selected_option), + include_blank: field.include_blank_option) %> +
diff --git a/app/views/fields/belongs_to/_index.html.erb b/app/views/fields/belongs_to/_index.html.erb new file mode 100644 index 000000000..8637400ca --- /dev/null +++ b/app/views/fields/belongs_to/_index.html.erb @@ -0,0 +1,32 @@ +<%# +# BelongsTo Index Partial + +This partial renders a belongs_to relationship, +to be displayed on a resource's index page. + +By default, the relationship is rendered as a link to the associated object. + +## Local variables: + +- `field`: + An instance of [Administrate::Field::BelongsTo][1]. + A wrapper around the belongs_to relationship pulled from the database. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/BelongsTo +%> + +<% if field.data %> + <% if field.data.is_a? User %> + <%= link_to( + field.display_associated_resource, + super_admin_user_path(field.data), + ) %> + <% elsif valid_action?(:show, field.associated_class) %> + <%= link_to( + field.display_associated_resource, + [namespace, field.data], + ) %> + <% else %> + <%= field.display_associated_resource %> + <% end %> +<% end %> diff --git a/app/views/fields/belongs_to/_show.html.erb b/app/views/fields/belongs_to/_show.html.erb new file mode 100644 index 000000000..24b47081a --- /dev/null +++ b/app/views/fields/belongs_to/_show.html.erb @@ -0,0 +1,27 @@ +<%# +# BelongsTo Show Partial + +This partial renders a belongs_to relationship, +to be displayed on a resource's show page. + +By default, the relationship is rendered as a link to the associated object. + +## Local variables: + +- `field`: + An instance of [Administrate::Field::BelongsTo][1]. + A wrapper around the belongs_to relationship pulled from the database. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/BelongsTo +%> + +<% if field.data %> + <% if valid_action?(:show, field.associated_class) %> + <%= link_to( + field.display_associated_resource, + [namespace, field.data], + ) %> + <% else %> + <%= field.display_associated_resource %> + <% end %> +<% end %> diff --git a/app/views/fields/polymorphic/_form.html.erb b/app/views/fields/polymorphic/_form.html.erb new file mode 100644 index 000000000..edf0c62d5 --- /dev/null +++ b/app/views/fields/polymorphic/_form.html.erb @@ -0,0 +1,29 @@ +<%# +# Polymorphic Form Partial + +This partial renders an input element for polymorphic relationships. + +## Local variables: + +- `f`: + A Rails form generator, used to help create the appropriate input fields. +- `field`: + An instance of [Administrate::Field::Polymorphic][1]. + A wrapper around the polymorphic belongs_to relationship + pulled from the database. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Polymorphic +%> + +<%= f.fields_for field.attribute do |pf| %> +
+ <%= pf.label :value, field.name.humanize %> +
+ +
+ <%= pf.hidden_field(:type, value: field.class.name) %> + <%= pf.select(:value) do %> + <%= grouped_options_for_select(field.associated_resource_grouped_options, field.selected_global_id, prompt: true) %> + <% end %> +
+<% end %> diff --git a/app/views/fields/polymorphic/_index.html.erb b/app/views/fields/polymorphic/_index.html.erb new file mode 100644 index 000000000..f1e4d499f --- /dev/null +++ b/app/views/fields/polymorphic/_index.html.erb @@ -0,0 +1,31 @@ +<%# +# Polymorphic Index Partial + +This partial renders a polymorphic relationship, +to be displayed on a resource's index page. + +By default, the relationship is rendered as a link to the associated object. + +## Local variables: + +- `field`: + An instance of [Administrate::Field::Polymorphic][1]. + A wrapper around the polymorphic belongs_to relationship + pulled from the database. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Polymorphic +%> + +<% if field.data %> + <% if field.data.is_a? User %> + <%= link_to( + "User ##{field.data.id}", + super_admin_user_path(field.data) + ) %> + <% else %> + <%= link_to( + field.display_associated_resource, + [namespace, field.data] + ) %> + <% end %> +<% end %> diff --git a/app/views/fields/polymorphic/_show.html.erb b/app/views/fields/polymorphic/_show.html.erb new file mode 100644 index 000000000..27a5645ae --- /dev/null +++ b/app/views/fields/polymorphic/_show.html.erb @@ -0,0 +1,28 @@ +<%# +# Polymorphic Show Partial + +This partial renders a polymorphic relationship, +to be displayed on a resource's show page. + +By default, the relationship is rendered as a link to the associated object. + +## Local variables: + +- `field`: + An instance of [Administrate::Field::Polymorphic][1]. + A wrapper around the polymorphic belongs_to relationship + pulled from the database. + +[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/Polymorphic +%> + +<% if field.data %> + <% if valid_action?(:show, field.data.class) %> + <%= link_to( + field.display_associated_resource, + [namespace, field.data], + ) %> + <% else %> + <%= field.display_associated_resource %> + <% end %> +<% end %> diff --git a/app/views/super_admin/application/_navigation.html.erb b/app/views/super_admin/application/_navigation.html.erb index fb4fd9018..73e7c29af 100644 --- a/app/views/super_admin/application/_navigation.html.erb +++ b/app/views/super_admin/application/_navigation.html.erb @@ -56,9 +56,14 @@ as defined by the routes in the `admin/` namespace diff --git a/app/views/super_admin/users/_collection.html.erb b/app/views/super_admin/users/_collection.html.erb index 3f7aa489c..f1f25987c 100644 --- a/app/views/super_admin/users/_collection.html.erb +++ b/app/views/super_admin/users/_collection.html.erb @@ -57,13 +57,13 @@ to display a collection of resources in an HTML table. - <%= %(role=link data-url=#{polymorphic_path([namespace, resource])}) %> + <%= %(role=link data-url=#{polymorphic_path([namespace, resource.becomes(User)])}) %> <% end %> > <% collection_presenter.attributes_for(resource).each do |attribute| %> <% if show_action? :show, resource -%> - <%= render_field attribute %> @@ -75,7 +75,7 @@ to display a collection of resources in an HTML table. <% if valid_action? :edit, collection_presenter.resource_name %> <%= link_to( t("administrate.actions.edit"), - [:edit, namespace, resource], + [:edit, namespace, resource.becomes(User)], class: "action-edit", ) if show_action? :edit, resource%> <% end %> @@ -83,7 +83,7 @@ to display a collection of resources in an HTML table. <% if valid_action? :destroy, collection_presenter.resource_name %> <%= link_to( t("administrate.actions.destroy"), - [namespace, resource], + [namespace, resource.becomes(User)], class: "text-color-red", method: :delete, data: { confirm: t("administrate.actions.confirm") } diff --git a/config/initializers/rack_attack.rb b/config/initializers/rack_attack.rb index 39556b6f2..87deded55 100644 --- a/config/initializers/rack_attack.rb +++ b/config/initializers/rack_attack.rb @@ -72,6 +72,15 @@ class Rack::Attack end end + throttle('super_admin_login/email', limit: 20, period: 5.minutes) do |req| + if req.path == '/super_admin/sign_in' && req.post? + # NOTE: This line used to throw ArgumentError /rails/action_mailbox/sendgrid/inbound_emails : invalid byte sequence in UTF-8 + # Hence placed in the if block + email = req.params['email'].presence || ActionDispatch::Request.new(req.env).params['email'].presence + email.to_s.downcase.gsub(/\s+/, '') + end + end + throttle('reset_password/email', limit: 5, period: 1.hour) do |req| if req.path == '/auth/password' && req.post? email = req.params['email'].presence || ActionDispatch::Request.new(req.env).params['email'].presence diff --git a/config/routes.rb b/config/routes.rb index aaf0330ea..880f8bdcc 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -303,7 +303,6 @@ Rails.application.routes.draw do # order of resources affect the order of sidebar navigation in super admin resources :accounts resources :users, only: [:index, :new, :create, :show, :edit, :update] - resources :super_admins resources :access_tokens, only: [:index, :show] resources :installation_configs, only: [:index, :new, :create, :show, :edit, :update] diff --git a/db/migrate/20220121055444_add_type_to_users.rb b/db/migrate/20220121055444_add_type_to_users.rb new file mode 100644 index 000000000..b4e0687b5 --- /dev/null +++ b/db/migrate/20220121055444_add_type_to_users.rb @@ -0,0 +1,42 @@ +class AddTypeToUsers < ActiveRecord::Migration[6.1] + def change + add_column :users, :type, :string + migrate_existing_super_admins + + drop_table :super_admins do |t| + t.string :email, null: false, default: '' + t.string :encrypted_password, null: false, default: '' + t.datetime :remember_created_at + t.integer :sign_in_count, default: 0, null: false + t.datetime :current_sign_in_at + t.datetime :last_sign_in_at + t.inet :current_sign_in_ip + t.inet :last_sign_in_ip + t.timestamps null: false + end + end + + private + + def old_super_admins + ActiveRecord::Base.connection.execute('SELECT * from super_admins').to_a + end + + def create_user_account_for_super_admin(super_admin) + u = User.new(email: super_admin['email'], name: "SuperUser #{super_admin['id']}", encrypted_password: super_admin['encrypted_password'], + confirmed_at: DateTime.now, type: 'SuperAdmin') + u.save(validate: false) + end + + def migrate_existing_super_admins + old_super_admins.each do |super_admin| + user = User.find_by(email: super_admin['email']) + if user.present? + user.update(type: 'SuperAdmin') + else + Rails.logger.debug { "User with email #{super_admin['email']} not found" } + create_user_account_for_super_admin(super_admin) + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index de8245d92..8dc74b602 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_01_11_223630) do +ActiveRecord::Schema.define(version: 2022_01_21_055444) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" @@ -745,6 +745,7 @@ ActiveRecord::Schema.define(version: 2022_01_11_223630) do t.integer "availability", default: 0 t.jsonb "ui_settings", default: {} t.jsonb "custom_attributes", default: {} + t.string "type" t.index ["email"], name: "index_users_on_email" t.index ["pubsub_token"], name: "index_users_on_pubsub_token", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true diff --git a/db/seeds.rb b/db/seeds.rb index 306d8ba2d..47ce3f6fb 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -10,7 +10,6 @@ end ## Seeds for Local Development unless Rails.env.production? - SuperAdmin.create!(email: 'john@acme.inc', password: 'Password1!') account = Account.create!( name: 'Acme Inc' @@ -20,7 +19,7 @@ unless Rails.env.production? name: 'Acme Org' ) - user = User.new(name: 'John', email: 'john@acme.inc', password: 'Password1!') + user = User.new(name: 'John', email: 'john@acme.inc', password: 'Password1!', type: 'SuperAdmin') user.skip_confirmation! user.save! diff --git a/spec/controllers/super_admin/access_tokens_controller_spec.rb b/spec/controllers/super_admin/access_tokens_controller_spec.rb index ace011663..8e0eb5430 100644 --- a/spec/controllers/super_admin/access_tokens_controller_spec.rb +++ b/spec/controllers/super_admin/access_tokens_controller_spec.rb @@ -14,7 +14,7 @@ RSpec.describe 'Super Admin access tokens API', type: :request do context 'when it is an authenticated super admin' do it 'shows the list of access tokens' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/access_tokens' expect(response).to have_http_status(:success) expect(response.body).to include(platform_app.access_token.token) diff --git a/spec/controllers/super_admin/account_users_controller_spec.rb b/spec/controllers/super_admin/account_users_controller_spec.rb index 64b4d0e71..6fe705630 100644 --- a/spec/controllers/super_admin/account_users_controller_spec.rb +++ b/spec/controllers/super_admin/account_users_controller_spec.rb @@ -13,7 +13,7 @@ RSpec.describe 'Super Admin Account Users API', type: :request do context 'when it is an authenticated super admin' do it 'shows the account user create page' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/account_users/new' expect(response).to have_http_status(:success) end diff --git a/spec/controllers/super_admin/accounts_controller_spec.rb b/spec/controllers/super_admin/accounts_controller_spec.rb index f4da5ad3d..1f155609a 100644 --- a/spec/controllers/super_admin/accounts_controller_spec.rb +++ b/spec/controllers/super_admin/accounts_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Super Admin accounts API', type: :request do let!(:account) { create(:account) } it 'shows the list of accounts' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/accounts' expect(response).to have_http_status(:success) expect(response.body).to include('New account') diff --git a/spec/controllers/super_admin/agent_bots_controller_spec.rb b/spec/controllers/super_admin/agent_bots_controller_spec.rb index 39aa3cfe4..63548e441 100644 --- a/spec/controllers/super_admin/agent_bots_controller_spec.rb +++ b/spec/controllers/super_admin/agent_bots_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Super Admin agent-bots API', type: :request do let!(:agent_bot) { create(:agent_bot) } it 'shows the list of users' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/agent_bots' expect(response).to have_http_status(:success) expect(response.body).to include(agent_bot.name) diff --git a/spec/controllers/super_admin/app_config_controller_spec.rb b/spec/controllers/super_admin/app_config_controller_spec.rb index 9676790ce..3a81ac7d3 100644 --- a/spec/controllers/super_admin/app_config_controller_spec.rb +++ b/spec/controllers/super_admin/app_config_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Super Admin Application Config API', type: :request do let!(:config) { create(:installation_config, { name: 'FB_APP_ID', value: 'TESTVALUE' }) } it 'shows the app_config page' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/app_config' expect(response).to have_http_status(:success) expect(response.body).to include(config.name) @@ -33,7 +33,7 @@ RSpec.describe 'Super Admin Application Config API', type: :request do context 'when it is an aunthenticated super admin' do it 'shows the app_config page' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) post '/super_admin/app_config', params: { app_config: { TESTKEY: 'TESTVALUE' } } expect(response.status).to eq(302) diff --git a/spec/controllers/super_admin/installation_configs_controller_spec.rb b/spec/controllers/super_admin/installation_configs_controller_spec.rb index 263e63c24..f1b6c82d3 100644 --- a/spec/controllers/super_admin/installation_configs_controller_spec.rb +++ b/spec/controllers/super_admin/installation_configs_controller_spec.rb @@ -19,20 +19,20 @@ RSpec.describe 'Super Admin Installation Config API', type: :request do end it 'shows the installation_configs create page' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/installation_configs/new' expect(response).to have_http_status(:success) end it 'shows the installation_configs edit page' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) editable_config = InstallationConfig.editable.first get "/super_admin/installation_configs/#{editable_config.id}/edit" expect(response).to have_http_status(:success) end it 'shows the installation_configs list page' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/installation_configs' expect(response).to have_http_status(:success) expect(response.body).to include(config.name) diff --git a/spec/controllers/super_admin/platform_apps_controller_spec.rb b/spec/controllers/super_admin/platform_apps_controller_spec.rb index 6ce9c9942..fca14fc1f 100644 --- a/spec/controllers/super_admin/platform_apps_controller_spec.rb +++ b/spec/controllers/super_admin/platform_apps_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Super Admin platform app API', type: :request do let!(:platform_app) { create(:platform_app) } it 'shows the list of users' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/platform_apps' expect(response).to have_http_status(:success) expect(response.body).to include(platform_app.name) diff --git a/spec/controllers/super_admin/super_admins_controller_spec.rb b/spec/controllers/super_admin/super_admins_controller_spec.rb deleted file mode 100644 index 0255b520c..000000000 --- a/spec/controllers/super_admin/super_admins_controller_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'Super Admin super admins API', type: :request do - let(:super_admin) { create(:super_admin) } - - describe 'GET /super_admin/users' do - context 'when it is an unauthenticated super admin' do - it 'returns unauthorized' do - get '/super_admin/super_admins' - expect(response).to have_http_status(:redirect) - end - end - - context 'when it is an authenticated super admin' do - it 'shows the list of super admins' do - sign_in super_admin - get '/super_admin/super_admins' - expect(response).to have_http_status(:success) - expect(response.body).to include('New super admin') - expect(response.body).to include(super_admin.email) - end - end - end -end diff --git a/spec/controllers/super_admin/users_controller_spec.rb b/spec/controllers/super_admin/users_controller_spec.rb index 16891823a..c34c91d2a 100644 --- a/spec/controllers/super_admin/users_controller_spec.rb +++ b/spec/controllers/super_admin/users_controller_spec.rb @@ -15,7 +15,7 @@ RSpec.describe 'Super Admin Users API', type: :request do let!(:user) { create(:user) } it 'shows the list of users' do - sign_in super_admin + sign_in(super_admin, scope: :super_admin) get '/super_admin/users' expect(response).to have_http_status(:success) expect(response.body).to include('New user') diff --git a/spec/controllers/super_admin_controller_spec.rb b/spec/controllers/super_admin_controller_spec.rb deleted file mode 100644 index 8fbece081..000000000 --- a/spec/controllers/super_admin_controller_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'Super Admin', type: :request do - let(:super_admin) { create(:super_admin) } - - describe 'request to /super_admin' do - context 'when the super admin is unauthenticated' do - it 'redirects to signin page' do - get '/super_admin/' - expect(response).to have_http_status(:redirect) - expect(response.body).to include('sign_in') - end - - it 'signs super admin in and out' do - sign_in super_admin - get '/super_admin' - expect(response).to have_http_status(:success) - expect(response.body).to include('Dashboard') - - sign_out super_admin - get '/super_admin' - expect(response).to have_http_status(:redirect) - end - end - end - - describe 'request to /super_admin/sidekiq' do - context 'when the super admin is unauthenticated' do - it 'redirects to signin page' do - get '/monitoring/sidekiq' - expect(response).to have_http_status(:not_found) - expect(response.body).to include('sign_in') - end - - it 'signs super admin in and out' do - sign_in super_admin - get '/monitoring/sidekiq' - expect(response).to have_http_status(:success) - - sign_out super_admin - get '/monitoring/sidekiq' - expect(response).to have_http_status(:not_found) - end - end - end -end diff --git a/spec/factories/super_admins.rb b/spec/factories/super_admins.rb index fc0b485c5..fbb821ca0 100644 --- a/spec/factories/super_admins.rb +++ b/spec/factories/super_admins.rb @@ -1,6 +1,9 @@ FactoryBot.define do factory :super_admin do + name { Faker::Name.name } email { "admin@#{SecureRandom.uuid}.com" } password { 'Password1!' } + type { 'SuperAdmin' } + confirmed_at { Time.zone.now } end end