Skip to content

Commit

Permalink
Merge pull request #541 from t3-innovation-network/staging
Browse files Browse the repository at this point in the history
Release 06/04/24
  • Loading branch information
excelsior authored Jun 4, 2024
2 parents 549d1c3 + c373b6b commit 18b1e14
Show file tree
Hide file tree
Showing 68 changed files with 883 additions and 283 deletions.
8 changes: 7 additions & 1 deletion app/controllers/api/v1/alignments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
module API
module V1
class AlignmentsController < BaseController
include ConfigurationProfileQueryable
before_action :authorize_with_policy, except: :index

###
Expand All @@ -14,7 +15,12 @@ class AlignmentsController < BaseController
###
def index
terms = current_configuration_profile.alignments
.includes(:predicate, mapping: :specification, mapped_terms: %i(organization property vocabularies))
.includes(
:predicate,
:specification,
mapping: %i(configuration_profile_user organization),
mapped_terms: %i(organization property vocabularies)
)
.where(
mappings: { spine_id: params[:spine_id], status: :mapped }
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def call_action
private

def with_instance
@instance = ConfigurationProfile.find(params[:id])
@instance = policy_scope(ConfigurationProfile).find(params[:id])
end

def permitted_actions
Expand Down
40 changes: 26 additions & 14 deletions app/controllers/api/v1/configuration_profiles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
module API
module V1
class ConfigurationProfilesController < API::V1::ConfigurationProfilesAbstractController
before_action :with_instance, only: %i(destroy show update set_current)
before_action :authorize_with_policy_class, only: %i(create index index_for_user)
before_action :authorize_with_policy, only: %i(destroy show update set_current)

def create
cp = ConfigurationProfile.create!(creation_params)
Expand All @@ -13,19 +14,18 @@ def create
end

def index
fields = ["configuration_profiles.*"]

configuration_profiles =
if current_user && !current_user.super_admin?
current_user
.configuration_profile_users
.joins(:configuration_profile, :organization)
.select(*fields, :lead_mapper, "organizations.id organization_id, organizations.id AS organization")
else
ConfigurationProfile.select(*fields)
end

render json: configuration_profiles.order(:name)
render json: policy_scope(ConfigurationProfile).order(:name)
end

def index_shared_mappings
render json: ConfigurationProfile.active.with_shared_mappings.order(:name), with_shared_mappings: true,
shared_mappings: true
end

def index_for_user
render json: current_user.configuration_profile_users.includes(:configuration_profile, :organization)
.where(configuration_profiles: { state: :active })
.order("configuration_profiles.name"), with_shared_mappings: true
end

def destroy
Expand Down Expand Up @@ -61,13 +61,25 @@ def import

private

def authorize_with_policy_class
authorize ConfigurationProfile
end

def authorize_with_policy
authorize(with_instance)
end

def creation_params
permitted_params.merge({ name: DEFAULT_CP_NAME, administrator: @current_user })
end

def permitted_params
params.require(:configuration_profile).permit(VALID_PARAMS_LIST)
end

def with_instance
@instance = policy_scope(ConfigurationProfile).find(params[:id])
end
end
end
end
1 change: 1 addition & 0 deletions app/controllers/api/v1/domains_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
module API
module V1
class DomainsController < BaseController
include ConfigurationProfileQueryable
before_action :with_instance, only: :show

###
Expand Down
1 change: 1 addition & 0 deletions app/controllers/api/v1/organizations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
module API
module V1
class OrganizationsController < BaseController
include ConfigurationProfileQueryable
before_action :authorize_with_policy, except: :index

###
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/api/v1/predicates_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
module API
module V1
class PredicatesController < BaseController
include ConfigurationProfileQueryable

###
# @description: Lists all the predicates
###
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/specifications_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def valid_params
# @return [ActionController::Parameters]
###
def permitted_params
params.require(:specification).permit(:name, :scheme, :use_case, :uri, :version)
params.require(:specification).permit(:name, :scheme, :uri, :version)
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion app/controllers/api/v1/spine_terms_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
module API
module V1
class SpineTermsController < BaseController
include ConfigurationProfileQueryable
before_action :validate_mapped_terms, only: [:create]
after_action :set_mapped_terms, only: [:create]

Expand All @@ -15,7 +16,7 @@ def index
includes += %i(organization) if params[:with_organization].present?
terms = Spine.find(params[:id]).terms.includes(includes)

render json: terms, spine: params[:with_weights].present?,
render json: terms, spine: params[:with_weights].present?, spine_id: params[:id],
with_organization: params[:with_organization].present?
end

Expand Down
8 changes: 8 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
helper_method :current_configuration_profile_user
helper_method :current_organization
helper_method :current_user
helper_method :impersonation_mode?

# We manage our own security for sessions
skip_before_action :verify_authenticity_token
Expand Down Expand Up @@ -98,4 +99,11 @@ def user_not_authorized(err)
end
end
end

###
# @description: Returns `true` if an admin is impersonating an agent
###
def impersonation_mode?
session[:impostor_id].present?
end
end
16 changes: 16 additions & 0 deletions app/controllers/concerns/configuration_profile_queryable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module ConfigurationProfileQueryable
extend ActiveSupport::Concern

included do
before_action :set_configuration_profile, only: :index

def set_configuration_profile
return unless params[:configuration_profile_id].present?

@current_configuration_profile = ConfigurationProfile.find(params[:configuration_profile_id])
raise Pundit::NotAuthorizedError unless @current_configuration_profile.with_shared_mappings?
end
end
end
36 changes: 36 additions & 0 deletions app/controllers/impersonations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

###
# @description: Manages impersonation of agents by admins
###
class ImpersonationsController < ApplicationController
###
# @description: Signs in an agent and persists the current user as the impostor
###
def start
agent =
begin
policy_scope(User, policy_scope_class: AgentPolicy::Scope).find(params[:agent_id])
rescue ActiveRecord::RecordNotFound
nil
end

if agent
session[:impostor_id] = current_user.id
session[:user_id] = agent.id
end

redirect_to root_url
end

###
# @description: Signs in the impostor back and redirects them to the agents page
###
def stop
return redirect_to root_url unless impersonation_mode?

session[:user_id] = session[:impostor_id]
session[:impostor_id] = nil
redirect_to "/dashboard/agents"
end
end
3 changes: 0 additions & 3 deletions app/interactors/save_alignments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ def create_alignments_for_existing_mappings(term)
def create_synthetic(params)
term = Term.find(params.fetch(:mapped_term_ids).first)
uri = "#{term.uri}-synthetic"
comment = "Alignment for a synthetic property added to the spine. " \
"Synthetic uri: #{uri}"

begin
spine.terms << term
Expand All @@ -48,7 +46,6 @@ def create_synthetic(params)
end

context.adds << mapping.alignments.create!(
comment:,
spine_term: term,
synthetic: true,
uri:,
Expand Down
6 changes: 4 additions & 2 deletions app/javascript/components/auth/AuthButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSelector, useDispatch } from 'react-redux';
import { doLogout, unsetUser } from '../../actions/sessions';
import signOut from '../../services/signOut';
import { AppContext } from '../../contexts/AppContext';
import { showInfo, showError } from '../../helpers/Messages';
import { showError } from '../../helpers/Messages';

const AuthButton = () => {
const { setLoggedIn, setCurrentConfigurationProfile } = useContext(AppContext);
Expand All @@ -23,7 +23,9 @@ const AuthButton = () => {
dispatch(unsetUser());
setCurrentConfigurationProfile(null);
setLoggedIn(false);
showInfo('Signed Out');

// Reload the whole app
window.location = '/';
};

/// Show "Sign Out" if the user is already signed in
Expand Down
28 changes: 28 additions & 0 deletions app/javascript/components/auth/MetaTags.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Helmet } from 'react-helmet';
import { snakeCase } from 'lodash';
import { i18n } from '../../utils/i18n';

const MetaTags = ({ pageType = 'default' }) => {
const key = snakeCase(pageType);
const title = i18n.t(`ui.pages.${key}.title`);
const description = i18n.t(`ui.pages.${key}.description`);

return (
<Helmet>
{/* Standard metadata tags */}
<title>{title}</title>
<meta name="description" content={description} />
{/* End standard metadata tags */}
{/* OpenGraph tags */}
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
{/* End OpenGraph tags */}
{/* Twitter tags */}
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
{/* End Twitter tags */}
</Helmet>
);
};

export default MetaTags;
10 changes: 2 additions & 8 deletions app/javascript/components/auth/ProtectedRoute.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { Route, Redirect } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { Helmet } from 'react-helmet';
import { snakeCase } from 'lodash';
import MetaTags from './MetaTags';
import { showError } from '../../helpers/Messages';
import { i18n } from '../../utils/i18n';

const ProtectedRoute = ({
component: Component,
Expand All @@ -13,7 +11,6 @@ const ProtectedRoute = ({
}) => {
const isLoggedIn = useSelector((state) => state.loggedIn);
const user = useSelector((state) => state.user);
const key = snakeCase(pageType);

return (
/// If we have a valid session
Expand All @@ -29,10 +26,7 @@ const ProtectedRoute = ({
{...rest}
render={(props) => (
<>
<Helmet>
<title>{i18n.t(`ui.pages.${key}.title`)}</title>
<description>{i18n.t(`ui.pages.${key}.description`)}</description>
</Helmet>
<MetaTags pageType={pageType} />
<Component
/// Destructure all the props passed to join with all the rest
{...rest}
Expand Down
11 changes: 2 additions & 9 deletions app/javascript/components/auth/RouteWithTitle.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { Route } from 'react-router-dom';
import { Helmet } from 'react-helmet';
import { snakeCase } from 'lodash';
import { i18n } from '../../utils/i18n';
import MetaTags from './MetaTags';

const RouteWithTitle = ({ pageType = 'default', ...props }) => {
const key = snakeCase(pageType);

return (
<>
<Helmet>
<title>{i18n.t(`ui.pages.${key}.title`)}</title>
<description>{i18n.t(`ui.pages.${key}.description`)}</description>
</Helmet>
<MetaTags pageType={pageType} />
<Route {...props} />
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const SelectConfigurationProfile = ({ history }) => (
<TopNav centerContent={() => null} />
<div className="row mt-4">
<div className="col-lg-6 mx-auto">
<ConfigurationProfileSelect onChange={() => history.push('/')} />
<ConfigurationProfileSelect requestType="indexForUser" onChange={() => history.push('/')} />
</div>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions app/javascript/components/dashboard/agents/AgentsIndex.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const AgentsIndex = (_props = {}) => {
<td className="white-space-pre-line">
<ul className="list-unstyled">{profiles}</ul>
</td>
<td>
<a href={`/agents/${agent.id}/impersonate`}>Impersonate</a>
</td>
</tr>
);
};
Expand All @@ -68,6 +71,7 @@ const AgentsIndex = (_props = {}) => {
<th scope="col">{i18n.t('ui.dashboard.agents.table.phone')}</th>
<th scope="col">{i18n.t('ui.dashboard.agents.table.organization')}</th>
<th scope="col">{i18n.t('ui.dashboard.agents.table.configuration_profile')}</th>
<th scope="col" />
</tr>
</thead>
<tbody>{state.agents.map(buildTableRow)}</tbody>
Expand Down
Loading

0 comments on commit 18b1e14

Please sign in to comment.