feat: Unify user and super admin credentials (#3830)

Fixes: #3061, #3489
This commit is contained in:
Sojan Jose 2022-01-25 16:58:49 -08:00 committed by GitHub
parent 23965fbaa3
commit 34e8ad9dc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 303 additions and 233 deletions

View file

@ -2,7 +2,7 @@
class AccountBuilder class AccountBuilder
include CustomExceptions::Account 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 def perform
if @user.nil? if @user.nil?
@ -65,6 +65,7 @@ class AccountBuilder
password: user_password, password: user_password,
password_confirmation: user_password, password_confirmation: user_password,
name: @user_full_name) name: @user_full_name)
@user.type = 'SuperAdmin' if @super_admin
@user.confirm if @confirmed @user.confirm if @confirmed
@user.save! @user.save!
end end

View file

@ -10,6 +10,7 @@ class Installation::OnboardingController < ApplicationController
user_full_name: onboarding_params.dig(:user, :name), user_full_name: onboarding_params.dig(:user, :name),
email: onboarding_params.dig(:user, :email), email: onboarding_params.dig(:user, :email),
user_password: params.dig(:user, :password), user_password: params.dig(:user, :password),
super_admin: true,
confirmed: true confirmed: true
).perform ).perform
rescue StandardError => e rescue StandardError => e

View file

@ -8,7 +8,7 @@ class SuperAdmin::Devise::SessionsController < Devise::SessionsController
def create def create
redirect_to(super_admin_session_path, flash: { error: @error_message }) && return unless valid_credentials? 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 flash.discard
redirect_to super_admin_users_path redirect_to super_admin_users_path
end end

View file

@ -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

View file

@ -33,12 +33,15 @@ class SuperAdmin::UsersController < SuperAdmin::ApplicationController
# empty values into nil values. It uses other APIs such as `resource_class` # empty values into nil values. It uses other APIs such as `resource_class`
# and `dashboard`: # and `dashboard`:
# #
# def resource_params def resource_params
# params.require(resource_class.model_name.param_key). permitted_params = super
# permit(dashboard.permitted_attributes). permitted_params.delete(:password) if permitted_params[:password].blank?
# transform_values { |value| value == "" ? nil : value } permitted_params
# end end
# See https://administrate-prototype.herokuapp.com/customizing_controller_actions # See https://administrate-prototype.herokuapp.com/customizing_controller_actions
# for more information # for more information
def find_resource(param)
super.becomes(User)
end
end end

View file

@ -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

View file

@ -30,6 +30,7 @@ class UserDashboard < Administrate::BaseDashboard
created_at: Field::DateTime, created_at: Field::DateTime,
updated_at: Field::DateTime, updated_at: Field::DateTime,
pubsub_token: Field::String, pubsub_token: Field::String,
type: Field::Select.with_options(collection: [nil, 'SuperAdmin']),
accounts: CountField accounts: CountField
}.freeze }.freeze
@ -44,6 +45,7 @@ class UserDashboard < Administrate::BaseDashboard
name name
email email
accounts accounts
type
].freeze ].freeze
# SHOW_PAGE_ATTRIBUTES # SHOW_PAGE_ATTRIBUTES
@ -53,10 +55,12 @@ class UserDashboard < Administrate::BaseDashboard
avatar_url avatar_url
unconfirmed_email unconfirmed_email
name name
type
display_name display_name
email email
created_at created_at
updated_at updated_at
confirmed_at
account_users account_users
].freeze ].freeze
@ -68,6 +72,8 @@ class UserDashboard < Administrate::BaseDashboard
display_name display_name
email email
password password
confirmed_at
type
].freeze ].freeze
# COLLECTION_FILTERS # COLLECTION_FILTERS

View file

@ -12,7 +12,7 @@ module Avatarable
def avatar_url def avatar_url
return url_for(avatar.representation(resize: '250x250')) if avatar.attached? && avatar.representable? 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) hash = Digest::MD5.hexdigest(email)
return "https://www.gravatar.com/avatar/#{hash}?d=404" return "https://www.gravatar.com/avatar/#{hash}?d=404"
end end

View file

@ -1,25 +1,41 @@
# == Schema Information # == Schema Information
# #
# Table name: super_admins # Table name: users
# #
# id :bigint not null, primary key # id :integer not null, primary key
# current_sign_in_at :datetime # availability :integer default("online")
# current_sign_in_ip :inet # confirmation_sent_at :datetime
# email :string default(""), not null # confirmation_token :string
# encrypted_password :string default(""), not null # confirmed_at :datetime
# last_sign_in_at :datetime # current_sign_in_at :datetime
# last_sign_in_ip :inet # current_sign_in_ip :string
# remember_created_at :datetime # custom_attributes :jsonb
# sign_in_count :integer default(0), not null # display_name :string
# created_at :datetime not null # email :string
# updated_at :datetime not null # 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 # 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 class SuperAdmin < User
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :trackable, :rememberable, :validatable, :password_has_required_content
end end

View file

@ -23,6 +23,7 @@
# reset_password_token :string # reset_password_token :string
# sign_in_count :integer default(0), not null # sign_in_count :integer default(0), not null
# tokens :json # tokens :json
# type :string
# ui_settings :jsonb # ui_settings :jsonb
# uid :string default(""), not null # uid :string default(""), not null
# unconfirmed_email :string # unconfirmed_email :string

View file

@ -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
%>
<div class="field-unit__label">
<%= f.label field.permitted_attribute %>
</div>
<div class="field-unit__field">
<%= f.select(field.permitted_attribute,
options_for_select(field.associated_resource_options, field.selected_option),
include_blank: field.include_blank_option) %>
</div>

View file

@ -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 %>

View file

@ -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 %>

View file

@ -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| %>
<div class="field-unit__label">
<%= pf.label :value, field.name.humanize %>
</div>
<div class="field-unit__field">
<%= 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 %>
</div>
<% end %>

View file

@ -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 %>

View file

@ -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 %>

View file

@ -56,9 +56,14 @@ as defined by the routes in the `admin/` namespace
</li> </li>
</ul> </ul>
<ul class="logout"> <ul class="logout">
<li class="navigation__link"> <li class="navigation__link">
<i class="ion ion-log-out"></i> <i class="ion ion-log-out"></i>
<%= link_to "Logout", super_admin_logout_url %> <%= link_to "Logout", super_admin_logout_url %>
</li> </li>
<li class="navigation__link">
<i class="ion ion-android-contacts"></i>
<%= link_to "Agent Dashboard", '/' %>
</li>
</ul> </ul>
</div> </div>

View file

@ -57,13 +57,13 @@ to display a collection of resources in an HTML table.
<tr class="js-table-row" <tr class="js-table-row"
tabindex="0" tabindex="0"
<% if valid_action? :show, collection_presenter.resource_name %> <% if valid_action? :show, collection_presenter.resource_name %>
<%= %(role=link data-url=#{polymorphic_path([namespace, resource])}) %> <%= %(role=link data-url=#{polymorphic_path([namespace, resource.becomes(User)])}) %>
<% end %> <% end %>
> >
<% collection_presenter.attributes_for(resource).each do |attribute| %> <% collection_presenter.attributes_for(resource).each do |attribute| %>
<td class="cell-data cell-data--<%= attribute.html_class %>"> <td class="cell-data cell-data--<%= attribute.html_class %>">
<% if show_action? :show, resource -%> <% if show_action? :show, resource -%>
<a href="<%= polymorphic_path([namespace, resource]) -%>" <a href="<%= polymorphic_path([namespace, resource.becomes(User)]) -%>"
class="action-show" class="action-show"
> >
<%= render_field attribute %> <%= 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 %> <% if valid_action? :edit, collection_presenter.resource_name %>
<td><%= link_to( <td><%= link_to(
t("administrate.actions.edit"), t("administrate.actions.edit"),
[:edit, namespace, resource], [:edit, namespace, resource.becomes(User)],
class: "action-edit", class: "action-edit",
) if show_action? :edit, resource%></td> ) if show_action? :edit, resource%></td>
<% end %> <% end %>
@ -83,7 +83,7 @@ to display a collection of resources in an HTML table.
<% if valid_action? :destroy, collection_presenter.resource_name %> <% if valid_action? :destroy, collection_presenter.resource_name %>
<td><%= link_to( <td><%= link_to(
t("administrate.actions.destroy"), t("administrate.actions.destroy"),
[namespace, resource], [namespace, resource.becomes(User)],
class: "text-color-red", class: "text-color-red",
method: :delete, method: :delete,
data: { confirm: t("administrate.actions.confirm") } data: { confirm: t("administrate.actions.confirm") }

View file

@ -72,6 +72,15 @@ class Rack::Attack
end end
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| throttle('reset_password/email', limit: 5, period: 1.hour) do |req|
if req.path == '/auth/password' && req.post? if req.path == '/auth/password' && req.post?
email = req.params['email'].presence || ActionDispatch::Request.new(req.env).params['email'].presence email = req.params['email'].presence || ActionDispatch::Request.new(req.env).params['email'].presence

View file

@ -303,7 +303,6 @@ Rails.application.routes.draw do
# order of resources affect the order of sidebar navigation in super admin # order of resources affect the order of sidebar navigation in super admin
resources :accounts resources :accounts
resources :users, only: [:index, :new, :create, :show, :edit, :update] resources :users, only: [:index, :new, :create, :show, :edit, :update]
resources :super_admins
resources :access_tokens, only: [:index, :show] resources :access_tokens, only: [:index, :show]
resources :installation_configs, only: [:index, :new, :create, :show, :edit, :update] resources :installation_configs, only: [:index, :new, :create, :show, :edit, :update]

View file

@ -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

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # 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 # These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements" enable_extension "pg_stat_statements"
@ -745,6 +745,7 @@ ActiveRecord::Schema.define(version: 2022_01_11_223630) do
t.integer "availability", default: 0 t.integer "availability", default: 0
t.jsonb "ui_settings", default: {} t.jsonb "ui_settings", default: {}
t.jsonb "custom_attributes", default: {} t.jsonb "custom_attributes", default: {}
t.string "type"
t.index ["email"], name: "index_users_on_email" t.index ["email"], name: "index_users_on_email"
t.index ["pubsub_token"], name: "index_users_on_pubsub_token", unique: true 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 t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true

View file

@ -10,7 +10,6 @@ end
## Seeds for Local Development ## Seeds for Local Development
unless Rails.env.production? unless Rails.env.production?
SuperAdmin.create!(email: 'john@acme.inc', password: 'Password1!')
account = Account.create!( account = Account.create!(
name: 'Acme Inc' name: 'Acme Inc'
@ -20,7 +19,7 @@ unless Rails.env.production?
name: 'Acme Org' 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.skip_confirmation!
user.save! user.save!

View file

@ -14,7 +14,7 @@ RSpec.describe 'Super Admin access tokens API', type: :request do
context 'when it is an authenticated super admin' do context 'when it is an authenticated super admin' do
it 'shows the list of access tokens' 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' get '/super_admin/access_tokens'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include(platform_app.access_token.token) expect(response.body).to include(platform_app.access_token.token)

View file

@ -13,7 +13,7 @@ RSpec.describe 'Super Admin Account Users API', type: :request do
context 'when it is an authenticated super admin' do context 'when it is an authenticated super admin' do
it 'shows the account user create page' 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' get '/super_admin/account_users/new'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end

View file

@ -15,7 +15,7 @@ RSpec.describe 'Super Admin accounts API', type: :request do
let!(:account) { create(:account) } let!(:account) { create(:account) }
it 'shows the list of accounts' do it 'shows the list of accounts' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
get '/super_admin/accounts' get '/super_admin/accounts'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include('New account') expect(response.body).to include('New account')

View file

@ -15,7 +15,7 @@ RSpec.describe 'Super Admin agent-bots API', type: :request do
let!(:agent_bot) { create(:agent_bot) } let!(:agent_bot) { create(:agent_bot) }
it 'shows the list of users' do it 'shows the list of users' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
get '/super_admin/agent_bots' get '/super_admin/agent_bots'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include(agent_bot.name) expect(response.body).to include(agent_bot.name)

View file

@ -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' }) } let!(:config) { create(:installation_config, { name: 'FB_APP_ID', value: 'TESTVALUE' }) }
it 'shows the app_config page' do it 'shows the app_config page' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
get '/super_admin/app_config' get '/super_admin/app_config'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include(config.name) 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 context 'when it is an aunthenticated super admin' do
it 'shows the app_config page' 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' } } post '/super_admin/app_config', params: { app_config: { TESTKEY: 'TESTVALUE' } }
expect(response.status).to eq(302) expect(response.status).to eq(302)

View file

@ -19,20 +19,20 @@ RSpec.describe 'Super Admin Installation Config API', type: :request do
end end
it 'shows the installation_configs create page' do 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' get '/super_admin/installation_configs/new'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
it 'shows the installation_configs edit page' do it 'shows the installation_configs edit page' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
editable_config = InstallationConfig.editable.first editable_config = InstallationConfig.editable.first
get "/super_admin/installation_configs/#{editable_config.id}/edit" get "/super_admin/installation_configs/#{editable_config.id}/edit"
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
end end
it 'shows the installation_configs list page' do it 'shows the installation_configs list page' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
get '/super_admin/installation_configs' get '/super_admin/installation_configs'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include(config.name) expect(response.body).to include(config.name)

View file

@ -15,7 +15,7 @@ RSpec.describe 'Super Admin platform app API', type: :request do
let!(:platform_app) { create(:platform_app) } let!(:platform_app) { create(:platform_app) }
it 'shows the list of users' do it 'shows the list of users' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
get '/super_admin/platform_apps' get '/super_admin/platform_apps'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include(platform_app.name) expect(response.body).to include(platform_app.name)

View file

@ -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

View file

@ -15,7 +15,7 @@ RSpec.describe 'Super Admin Users API', type: :request do
let!(:user) { create(:user) } let!(:user) { create(:user) }
it 'shows the list of users' do it 'shows the list of users' do
sign_in super_admin sign_in(super_admin, scope: :super_admin)
get '/super_admin/users' get '/super_admin/users'
expect(response).to have_http_status(:success) expect(response).to have_http_status(:success)
expect(response.body).to include('New user') expect(response.body).to include('New user')

View file

@ -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

View file

@ -1,6 +1,9 @@
FactoryBot.define do FactoryBot.define do
factory :super_admin do factory :super_admin do
name { Faker::Name.name }
email { "admin@#{SecureRandom.uuid}.com" } email { "admin@#{SecureRandom.uuid}.com" }
password { 'Password1!' } password { 'Password1!' }
type { 'SuperAdmin' }
confirmed_at { Time.zone.now }
end end
end end