From 4e32b2f72bbfc41344727d1fe8e3fd81c4516e9c Mon Sep 17 00:00:00 2001 From: Don Restarone <35935196+donrestarone@users.noreply.github.com> Date: Tue, 6 Dec 2022 08:45:07 -0500 Subject: [PATCH] [feature] allow access to API by category (#1103) (#1181) * [feature] allow access to API by category (#1103) Addresses: https://github.com/restarone/violet_rails/issues/1075 # Demo https://user-images.githubusercontent.com/35935196/191496793-30d7e50f-7674-489f-bb30-699fa4ab02f6.mp4 https://user-images.githubusercontent.com/25191509/198866316-2d57a2de-2e33-42ab-ba74-c59eb59c08c0.mov Co-authored-by: Prashant Co-authored-by: Prashant Khadka Co-authored-by: Prashant Khadka Co-authored-by: Prashant Khadka <25191509+alis-khadka@users.noreply.github.com> --- .../comfy/admin/api_actions_controller.rb | 5 +- .../comfy/admin/api_clients_controller.rb | 3 +- .../comfy/admin/api_forms_controller.rb | 2 +- .../comfy/admin/api_namespaces_controller.rb | 95 +- .../comfy/admin/api_resources_controller.rb | 4 +- .../admin/external_api_clients_controller.rb | 26 +- .../comfy/admin/users_controller.rb | 9 +- app/controllers/subdomains/base_controller.rb | 189 +- app/helpers/api_accessibility_helper.rb | 55 + app/models/api_namespace.rb | 36 + app/models/user.rb | 3 +- .../api_actions/action_workflow.html.haml | 5 +- .../comfy/admin/api_namespaces/show.html.haml | 64 +- .../comfy/admin/users/_api_accessibility.haml | 295 +++ app/views/comfy/admin/users/_form.haml | 5 +- app/views/comfy/admin/users/index.html.haml | 4 +- config/routes.rb | 5 +- ...13021415_add_api_accessibility_to_users.rb | 5 + ...m_users_and_back_fill_api_accessibility.rb | 17 + db/schema.rb | 2 +- .../comfy/api_actions_controller_test.rb | 786 +++++- .../comfy/api_clients_controller_test.rb | 630 ++++- .../admin/comfy/api_forms_controller_test.rb | 177 +- .../comfy/api_namespaces_controller_test.rb | 2137 ++++++++++++++++- .../comfy/api_resources_controller_test.rb | 448 +++- .../external_api_clients_controller_test.rb | 1468 ++++++++++- .../admin/comfy/users_controller_test.rb | 2 +- .../users/sessions_controller_test.rb | 8 +- test/helpers/api_accessibility_helper_test.rb | 35 + test/plugins/bishop_monitoring_plugin_test.rb | 2 +- .../bishop_tls_monitoring_plugin_test.rb | 2 +- 31 files changed, 6358 insertions(+), 166 deletions(-) create mode 100644 app/helpers/api_accessibility_helper.rb create mode 100644 app/views/comfy/admin/users/_api_accessibility.haml create mode 100644 db/migrate/20220913021415_add_api_accessibility_to_users.rb create mode 100644 db/migrate/20220917134117_remove_can_manage_api_from_users_and_back_fill_api_accessibility.rb create mode 100644 test/helpers/api_accessibility_helper_test.rb diff --git a/app/controllers/comfy/admin/api_actions_controller.rb b/app/controllers/comfy/admin/api_actions_controller.rb index afe762751..c1300b800 100644 --- a/app/controllers/comfy/admin/api_actions_controller.rb +++ b/app/controllers/comfy/admin/api_actions_controller.rb @@ -1,6 +1,7 @@ class Comfy::Admin::ApiActionsController < Comfy::Admin::Cms::BaseController - before_action :ensure_authority_to_manage_api - before_action :set_api_action, except: :new + before_action :set_api_action + before_action :ensure_authority_for_read_api_actions_only_in_api, only: %i[ show index ] + before_action :ensure_authority_for_full_access_for_api_actions_only_in_api, only: %i[ new action_workflow ] before_action :set_current_user_and_visit def new diff --git a/app/controllers/comfy/admin/api_clients_controller.rb b/app/controllers/comfy/admin/api_clients_controller.rb index 8cac566fc..598c7bdb5 100755 --- a/app/controllers/comfy/admin/api_clients_controller.rb +++ b/app/controllers/comfy/admin/api_clients_controller.rb @@ -1,7 +1,8 @@ class Comfy::Admin::ApiClientsController < Comfy::Admin::Cms::BaseController - before_action :ensure_authority_to_manage_api before_action :set_api_client, only: %i[ show edit update destroy ] before_action :set_api_namespace + before_action :ensure_authority_for_read_api_clients_only_in_api, only: %i[ show index ] + before_action :ensure_authority_for_full_access_for_api_clients_only_in_api, only: %i[ new edit create update destroy ] # GET /api_clients or /api_clients.json def index diff --git a/app/controllers/comfy/admin/api_forms_controller.rb b/app/controllers/comfy/admin/api_forms_controller.rb index e3abf8dc3..d1d2ff397 100644 --- a/app/controllers/comfy/admin/api_forms_controller.rb +++ b/app/controllers/comfy/admin/api_forms_controller.rb @@ -1,6 +1,6 @@ class Comfy::Admin::ApiFormsController < Comfy::Admin::Cms::BaseController - before_action :ensure_authority_to_manage_api before_action :set_api_namespace + before_action :ensure_authority_for_full_access_for_api_form_only_in_api, only: %i[ edit update ] before_action :set_api_form, only: %i[show edit update] diff --git a/app/controllers/comfy/admin/api_namespaces_controller.rb b/app/controllers/comfy/admin/api_namespaces_controller.rb index 2636ba716..a79c01619 100755 --- a/app/controllers/comfy/admin/api_namespaces_controller.rb +++ b/app/controllers/comfy/admin/api_namespaces_controller.rb @@ -1,18 +1,29 @@ require 'will_paginate/array' class Comfy::Admin::ApiNamespacesController < Comfy::Admin::Cms::BaseController - before_action :ensure_authority_to_manage_api - before_action :set_api_namespace, only: %i[ show edit update destroy discard_failed_api_actions rerun_failed_api_actions export export_api_resources duplicate_with_associations duplicate_without_associations export_without_associations_as_json export_with_associations_as_json ] + before_action :set_api_namespace, only: %i[ show edit update destroy discard_failed_api_actions rerun_failed_api_actions export export_api_resources duplicate_with_associations duplicate_without_associations export_without_associations_as_json export_with_associations_as_json social_share_metadata api_action_workflow ] + + before_action :ensure_authority_for_creating_api, only: %i[ new create import_as_json] + before_action :ensure_authority_for_viewing_all_api, only: :index + + before_action :ensure_authority_for_full_read_access_in_api, only: [:show] + before_action :ensure_authority_for_full_access_in_api_namespace_only, only: %i[ edit update ] + before_action :ensure_authority_for_delete_access_in_api_namespace_only, only: %i[ destroy ] + before_action :ensure_authority_for_allow_exports_in_api, only: %i[ export export_api_resources export_without_associations_as_json export_with_associations_as_json ] + before_action :ensure_authority_for_allow_duplication_in_api, only: %i[ duplicate_with_associations duplicate_without_associations ] + before_action :ensure_authority_for_allow_social_share_metadata_in_api, only: %i[ social_share_metadata ] + before_action :ensure_authority_for_full_access_for_api_actions_only_in_api, only: %i[ api_action_workflow discard_failed_api_actions rerun_failed_api_actions ] # GET /api_namespaces or /api_namespaces.json def index params[:q] ||= {} @api_namespaces_q = if params[:categories].present? - ApiNamespace.includes(:categories).for_category(params[:categories]).ransack(params[:q]) + ApiNamespace.filter_by_user_api_accessibility(current_user).for_category(params[:categories]).ransack(params[:q]) else - ApiNamespace.ransack(params[:q]) + ApiNamespace.filter_by_user_api_accessibility(current_user).ransack(params[:q]) end - + @api_namespaces_q.sorts = 'id asc' if @api_namespaces_q.sorts.empty? + if params.dig(:q, :s) && params[:q][:s].match(/CMS (asc|desc)/) namespaces = @api_namespaces_q.result.sort_by { |namespace| namespace.cms_associations.size } namespaces = namespaces.reverse if params[:q][:s].match(/CMS desc/) @@ -66,10 +77,16 @@ def create def update respond_to do |format| if @api_namespace.update(api_namespace_params) - format.html { handle_success_redirect } + format.html do + flash[:notice] = 'Api namespace was successfully updated.' + redirect_to @api_namespace + end format.json { render :show, status: :ok, location: @api_namespace } else - format.html { handle_error_redirect } + format.html do + flash[:error] = @api_namespace.errors.full_messages + render :edit, status: :unprocessable_entity + end format.json { render json: @api_namespace.errors, status: :unprocessable_entity } end end @@ -184,6 +201,42 @@ def import_as_json end end + def social_share_metadata + respond_to do |format| + if @api_namespace.update(api_namespace_social_share_metadata_params) + format.html do + flash[:notice] = 'Social Share Metadata successfully updated.' + redirect_to @api_namespace + end + format.json { render :show, status: :ok, location: @api_namespace } + else + format.html do + flash[:error] = @api_namespace.errors.full_messages + render :edit, status: :unprocessable_entity + end + format.json { render json: @api_namespace.errors, status: :unprocessable_entity } + end + end + end + + def api_action_workflow + respond_to do |format| + if @api_namespace.update(api_action_workflow_params) + format.html do + flash[:notice] = 'Action Workflow successfully updated.' + redirect_to api_namespace_api_actions_path(api_namespace_id: @api_namespace.id) + end + format.json { render :show, status: :ok, location: @api_namespace } + else + format.html do + flash[:error] = @api_namespace.errors.full_messages + redirect_to action_workflow_api_namespace_api_actions_path(api_namespace_id: @api_namespace.id) + end + format.json { render json: @api_namespace.errors, status: :unprocessable_entity } + end + end + end + private # Use callbacks to share common setup or constraints between actions. def set_api_namespace @@ -192,36 +245,28 @@ def set_api_namespace # Only allow a list of trusted parameters through. def api_namespace_params - api_actions_attributes = [:id, :trigger, :action_type, :properties, :include_api_resource_data, :email, :email_subject, :custom_message, :payload_mapping, :request_url, :redirect_url, :redirect_type, :bearer_token, :file_snippet, :position, :custom_headers, :http_method, :method_definition, :_destroy] params.require(:api_namespace).permit(:name, :version, :properties, :requires_authentication, :namespace_type, :has_form, - social_share_metadata: [:title, :description, :image], non_primitive_properties_attributes: [:id, :label, :field_type, :content, :attachment, :allow_attachments, :_destroy], - new_api_actions_attributes: api_actions_attributes, - create_api_actions_attributes: api_actions_attributes, - show_api_actions_attributes: api_actions_attributes, - update_api_actions_attributes: api_actions_attributes, - destroy_api_actions_attributes: api_actions_attributes, - error_api_actions_attributes: api_actions_attributes, category_ids: [] ) end - def handle_success_redirect - flash[:notice] = "Api namespace was successfully updated." - redirect_to api_namespace_api_actions_path(api_namespace_id: @api_namespace.id) and return if params[:source] == 'action_workflow' - - redirect_to @api_namespace + def api_action_workflow_params + api_actions_attributes = [:id, :trigger, :action_type, :properties, :include_api_resource_data, :email, :email_subject, :custom_message, :payload_mapping, :request_url, :redirect_url, :redirect_type, :bearer_token, :file_snippet, :position, :custom_headers, :http_method, :method_definition, :_destroy] + params.require(:api_namespace).permit(new_api_actions_attributes: api_actions_attributes, + create_api_actions_attributes: api_actions_attributes, + show_api_actions_attributes: api_actions_attributes, + update_api_actions_attributes: api_actions_attributes, + destroy_api_actions_attributes: api_actions_attributes, + error_api_actions_attributes: api_actions_attributes) end - def handle_error_redirect - flash[:error] = @api_namespace.errors.full_messages - redirect_to action_workflow_api_namespace_api_actions_path(api_namespace_id: @api_namespace.id) and return if params[:source] == 'action_workflow' - - render :edit, status: :unprocessable_entity + def api_namespace_social_share_metadata_params + params.require(:api_namespace).permit(social_share_metadata: [:title, :description, :image]) end end \ No newline at end of file diff --git a/app/controllers/comfy/admin/api_resources_controller.rb b/app/controllers/comfy/admin/api_resources_controller.rb index 42f3deef4..43efd5894 100755 --- a/app/controllers/comfy/admin/api_resources_controller.rb +++ b/app/controllers/comfy/admin/api_resources_controller.rb @@ -1,6 +1,8 @@ class Comfy::Admin::ApiResourcesController < Comfy::Admin::Cms::BaseController - before_action :ensure_authority_to_manage_api before_action :set_api_resource + before_action :ensure_authority_for_read_api_resources_only_in_api, only: %i[ show ] + before_action :ensure_authority_for_delete_access_for_api_resources_only_in_api, only: %i[ destroy ] + before_action :ensure_authority_for_full_access_for_api_resources_only_in_api, only: %i[ new edit create update ] include ApiActionable # GET /api_resources/1 or /api_resources/1.json diff --git a/app/controllers/comfy/admin/external_api_clients_controller.rb b/app/controllers/comfy/admin/external_api_clients_controller.rb index 233a3f9fd..edf739938 100644 --- a/app/controllers/comfy/admin/external_api_clients_controller.rb +++ b/app/controllers/comfy/admin/external_api_clients_controller.rb @@ -1,27 +1,28 @@ class Comfy::Admin::ExternalApiClientsController < Comfy::Admin::Cms::BaseController - before_action :ensure_authority_to_manage_api before_action :set_external_api_client, only: %i[ show edit update destroy start stop clear_errors clear_state] before_action :set_api_namespace + before_action :ensure_authority_for_read_external_api_connections_only_in_api, only: %i[ show index ] + before_action :ensure_authority_for_full_access_for_external_api_connections_only_in_api, only: %i[ new edit create update destroy start stop clear_errors clear_state ] - # GET /api_clients or /api_clients.json + # GET /external_api_clients or /external_api_clients.json def index @external_api_clients = @api_namespace.external_api_clients end - # GET /api_clients/1 or /api_clients/1.json + # GET /external_api_clients/1 or /external_api_clients/1.json def show end - # GET /api_clients/new + # GET /external_api_clients/new def new @external_api_client = ExternalApiClient.new(api_namespace_id: @api_namespace.id) end - # GET /api_clients/1/edit + # GET /external_api_clients/1/edit def edit end - # POST /api_clients or /api_clients.json + # POST /external_api_clients or /external_api_clients.json def create @external_api_client = ExternalApiClient.new(external_api_client_params) respond_to do |format| @@ -35,7 +36,7 @@ def create end end - # PATCH/PUT /api_clients/1 or /api_clients/1.json + # PATCH/PUT /external_api_clients/1 or /external_api_clients/1.json def update respond_to do |format| if @external_api_client.update(external_api_client_params) @@ -48,38 +49,43 @@ def update end end - # DELETE /api_clients/1 or /api_clients/1.json + # DELETE /external_api_clients/1 or /external_api_clients/1.json def destroy @external_api_client.destroy respond_to do |format| - format.html { redirect_to api_namespace_api_clients_path(api_namespace_id: @api_namespace.id), notice: "Api client was successfully destroyed." } + format.html { redirect_to api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id), notice: "Api client was successfully destroyed." } format.json { head :no_content } end end + # GET /external_api_clients/1/start def start @external_api_client.run redirect_back(fallback_location: api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id)) end + # GET /external_api_clients/1/stop def stop @external_api_client.stop redirect_back(fallback_location: api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id)) end + # GET /external_api_clients/1/clear_errors def clear_errors @external_api_client.clear_error_data redirect_back(fallback_location: api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id)) end + # GET /external_api_clients/1/clear_state def clear_state @external_api_client.clear_state_data redirect_back(fallback_location: api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id)) end + private # Use callbacks to share common setup or constraints between actions. def set_api_namespace - @api_namespace = ApiNamespace.find_by(id: params[:api_namespace_id]) + @api_namespace = ApiNamespace.friendly.find(params[:api_namespace_id]) rescue nil end diff --git a/app/controllers/comfy/admin/users_controller.rb b/app/controllers/comfy/admin/users_controller.rb index a904db391..4c60ae416 100644 --- a/app/controllers/comfy/admin/users_controller.rb +++ b/app/controllers/comfy/admin/users_controller.rb @@ -3,6 +3,7 @@ class Comfy::Admin::UsersController < Comfy::Admin::Cms::BaseController before_action :track_ahoy_visit, only: %i[update], raise: false before_action :load_user, only: [:edit, :update, :destroy] before_action :ensure_authority_to_manage_users + before_action :set_default_api_accessibility_param, only: :update def index params[:q] ||= {} @@ -77,7 +78,6 @@ def update_params :can_manage_blog, :can_manage_email, :can_manage_users, - :can_manage_api, :can_manage_analytics, :can_manage_files, :moderator, @@ -87,11 +87,16 @@ def update_params :can_manage_subdomain_settings, :can_access_admin, :deliver_error_notifications, - category_ids: [] + category_ids: [], + api_accessibility: {} ) end def invite_params params.require(:user).permit(:email) end + + def set_default_api_accessibility_param + params[:user].merge!(api_accessibility: {}) if params[:user].present? && params.dig(:user, :api_accessibility).blank? + end end \ No newline at end of file diff --git a/app/controllers/subdomains/base_controller.rb b/app/controllers/subdomains/base_controller.rb index 5c809a92d..aeaa0a9c9 100644 --- a/app/controllers/subdomains/base_controller.rb +++ b/app/controllers/subdomains/base_controller.rb @@ -46,10 +46,193 @@ def ensure_authority_to_manage_users end end - def ensure_authority_to_manage_api - unless current_user.can_manage_api - flash.alert = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + # API Accessibilities + def ensure_authority_for_full_access_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access]) + flash.alert = "You do not have the permission to do that. Only users with full_access are allowed to perform that action." redirect_back(fallback_location: root_url) end end + + def ensure_authority_for_full_read_access_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_read_access_in_api_namespace]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_read_access or delete_access_api_namespace_only or allow_exports or allow_duplication or full_access_api_namespace_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_full_access_in_api_namespace_only + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_api_namespace_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_delete_access_in_api_namespace_only + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:delete_access_api_namespace_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or delete_access_api_namespace_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_read_api_resources_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:read_api_resources_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_resources_only or read_api_resources_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_full_access_for_api_resources_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_for_api_resources_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_delete_access_for_api_resources_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:delete_access_for_api_resources_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only or delete_access_for_api_resources_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_allow_exports_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:allow_exports]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_allow_duplication_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:allow_duplication]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_duplication are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_allow_social_share_metadata_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:allow_social_share_metadata]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_social_share_metadata are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_read_api_actions_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:read_api_actions_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_actions_only or read_api_actions_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_full_access_for_api_actions_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_for_api_actions_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_read_external_api_connections_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:read_external_api_connections_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_external_api_connections_only or read_external_api_connections_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_full_access_for_external_api_connections_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_for_external_api_connections_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_read_api_clients_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:read_api_clients_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_clients_only or read_api_clients_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_full_access_for_api_clients_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_for_api_clients_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_full_access_for_api_form_only_in_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_for_api_form_only]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + def ensure_authority_for_viewing_all_api + unless user_authorized_to_view_all_api?(ApiNamespace::API_ACCESSIBILITIES[:full_read_access_in_api_namespace]) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_api_namespace_only are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + # For new, create action of api_namespaces_controller, we cannot use the category specicfic authorization + def ensure_authority_for_creating_api + unless user_authorized_for_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:full_access_api_namespace_only], check_categories: false) + flash.alert = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + redirect_back(fallback_location: root_url) + end + end + + private + def user_authorized_for_api_accessibility?(api_permissions, check_categories: true) + user_api_accessibility = current_user.api_accessibility + + return false unless user_api_accessibility.present? + + is_user_authorized = false + + if user_api_accessibility.keys.include?('all_namespaces') + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('all_namespaces', access_name).present? && user_api_accessibility.dig('all_namespaces', access_name) == 'true' + end + elsif check_categories && user_api_accessibility.keys.include?('namespaces_by_category') + categories = @api_namespace.categories.pluck(:label) + + if categories.blank? && user_api_accessibility.dig('namespaces_by_category', 'uncategorized').present? + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('namespaces_by_category', 'uncategorized', access_name).present? && user_api_accessibility.dig('namespaces_by_category', 'uncategorized', access_name) == 'true' + end + else + categories.any? do |category| + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('namespaces_by_category', category, access_name).present? && user_api_accessibility.dig('namespaces_by_category', category, access_name) == 'true' + end + end + end + end + + is_user_authorized + end + + def user_authorized_to_view_all_api?(api_permissions) + user_api_accessibility = current_user.api_accessibility + + return false unless user_api_accessibility.present? + + is_user_authorized = false + + if user_api_accessibility.keys.include?('all_namespaces') + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('all_namespaces', access_name).present? && user_api_accessibility.dig('all_namespaces', access_name) == 'true' + end + elsif user_api_accessibility.keys.include?('namespaces_by_category') + categories = user_api_accessibility.dig('namespaces_by_category').keys + + categories.any? do |category| + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('namespaces_by_category', category, access_name).present? && user_api_accessibility.dig('namespaces_by_category', category, access_name) == 'true' + end + end + end + + is_user_authorized + end end \ No newline at end of file diff --git a/app/helpers/api_accessibility_helper.rb b/app/helpers/api_accessibility_helper.rb new file mode 100644 index 000000000..4c05c0e54 --- /dev/null +++ b/app/helpers/api_accessibility_helper.rb @@ -0,0 +1,55 @@ +module ApiAccessibilityHelper + def has_access_to_main_category?(api_accessibility, top_category) + api_accessibility.dig(top_category).present? + end + + def has_access_to_specific_category?(api_accessibility, category_label) + api_accessibility.dig('namespaces_by_category', category_label).present? + end + + def has_sub_access_to_specific_category?(api_accessibility, sub_access, top_category, category_label = nil) + if top_category == 'all_namespaces' + api_accessibility.dig(top_category, sub_access).present? + else + api_accessibility.dig(top_category, category_label, sub_access).present? + end + end + + def has_no_sub_access_to_specific_category?(api_accessibility, top_category, category_label = nil) + if top_category == 'all_namespaces' + api_accessibility.dig(top_category)&.keys.present? + else + api_accessibility.dig(top_category, category_label)&.keys.present? + end + end + + def has_access_to_api_accessibility?(api_permissions, user, api_namespace) + user_api_accessibility = user.api_accessibility + + return false unless user_api_accessibility.present? + + is_user_authorized = false + + if user_api_accessibility.keys.include?('all_namespaces') + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('all_namespaces', access_name).present? && user_api_accessibility.dig('all_namespaces', access_name) == 'true' + end + elsif user_api_accessibility.keys.include?('namespaces_by_category') + categories = api_namespace.categories.pluck(:label) + + if categories.blank? && user_api_accessibility.dig('namespaces_by_category', 'uncategorized').present? + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('namespaces_by_category', 'uncategorized', access_name).present? && user_api_accessibility.dig('namespaces_by_category', 'uncategorized', access_name) == 'true' + end + else + categories.any? do |category| + is_user_authorized = api_permissions.any? do |access_name| + user_api_accessibility.dig('namespaces_by_category', category, access_name).present? && user_api_accessibility.dig('namespaces_by_category', category, access_name) == 'true' + end + end + end + end + + is_user_authorized + end +end diff --git a/app/models/api_namespace.rb b/app/models/api_namespace.rb index 6080c27cf..3b7f31b4b 100755 --- a/app/models/api_namespace.rb +++ b/app/models/api_namespace.rb @@ -56,6 +56,42 @@ class ApiNamespace < ApplicationRecord } } + API_ACCESSIBILITIES = { + full_access: ['full_access'], + full_read_access: ['full_access', 'full_read_access'], + full_read_access_in_api_namespace: ['full_access', 'full_read_access', 'delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'allow_social_share_metadata', 'full_access_api_namespace_only', 'read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'], + full_access_api_namespace_only: ['full_access', 'full_access_api_namespace_only'], + delete_access_api_namespace_only: ['full_access', 'full_access_api_namespace_only', 'delete_access_api_namespace_only'], + allow_exports: ['full_access', 'full_access_api_namespace_only', 'allow_exports'], + allow_duplication: ['full_access', 'full_access_api_namespace_only', 'allow_duplication'], + allow_social_share_metadata: ['full_access', 'full_access_api_namespace_only', 'allow_social_share_metadata'], + read_api_resources_only: ['full_access', 'full_read_access', 'full_access_for_api_resources_only', 'read_api_resources_only', 'delete_access_for_api_resources_only'], + full_access_for_api_resources_only: ['full_access', 'full_access_for_api_resources_only'], + delete_access_for_api_resources_only: ['full_access', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only'], + read_api_actions_only: ['full_access', 'full_read_access', 'full_access_for_api_actions_only', 'read_api_actions_only'], + full_access_for_api_actions_only: ['full_access', 'full_access_for_api_actions_only'], + read_external_api_connections_only: ['full_access', 'full_read_access', 'full_access_for_external_api_connections_only', 'read_external_api_connections_only'], + full_access_for_external_api_connections_only: ['full_access', 'full_access_for_external_api_connections_only'], + read_api_clients_only: ['full_access', 'full_read_access', 'full_access_for_api_clients_only', 'read_api_clients_only'], + full_access_for_api_clients_only: ['full_access', 'full_access_for_api_clients_only'], + full_access_for_api_form_only: ['full_access', 'full_access_for_api_form_only'], + } + + scope :filter_by_user_api_accessibility, ->(user) { + api_accessibility = user.api_accessibility + + if api_accessibility.keys.include?('all_namespaces') + self + elsif api_accessibility.keys.include?('namespaces_by_category') + category_specific_keys = api_accessibility['namespaces_by_category'].keys + if category_specific_keys.include?('uncategorized') + self.includes(:categories).left_outer_joins(categorizations: :category).where("comfy_cms_categories.id IS ? OR comfy_cms_categories.label IN (?)", nil, category_specific_keys) + else + self.includes(:categories).for_category(category_specific_keys) + end + end + } + def update_api_form if has_form == '1' if api_form.present? diff --git a/app/models/user.rb b/app/models/user.rb index c6af39b87..89e99f448 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,4 +1,5 @@ class User < ApplicationRecord + include JsonbFieldsParsable include SimpleDiscussion::ForumUser include Comfy::Cms::WithCategories include ActionText::Attachable @@ -54,7 +55,7 @@ class User < ApplicationRecord can_manage_users: true, can_manage_blog: true, can_manage_subdomain_settings: true, - can_manage_api: true, + api_accessibility: {all_namespaces: {full_access: 'true'}}, can_view_restricted_pages: true, moderator: true } diff --git a/app/views/comfy/admin/api_actions/action_workflow.html.haml b/app/views/comfy/admin/api_actions/action_workflow.html.haml index 6bb04e8b2..61ac7f17b 100644 --- a/app/views/comfy/admin/api_actions/action_workflow.html.haml +++ b/app/views/comfy/admin/api_actions/action_workflow.html.haml @@ -4,8 +4,7 @@ > API Actions > Workflow -= form_for @api_namespace, html: {multipart: true} do |f| - = hidden_field_tag 'source', 'action_workflow' += form_for @api_namespace, method: :patch, url: api_action_workflow_api_namespace_path(@api_namespace), html: {multipart: true} do |f| - if @api_namespace.errors.any? #error_explanation %h2= "#{pluralize(@api_namespace.errors.count, "error")} prohibited this api_namespace from being saved:" @@ -71,7 +70,7 @@ function appendApiActionForm(type) { var index = $("#" + `${type}_forms > .form-container`).length - var url = "#{new_api_action_path()}" + `?index=${index}&type=${type}` + var url = "#{new_api_namespace_api_action_path(api_namespace_id: @api_namespace.id)}" + `?index=${index}&type=${type}` $.ajax({ url: url , type: 'GET', diff --git a/app/views/comfy/admin/api_namespaces/show.html.haml b/app/views/comfy/admin/api_namespaces/show.html.haml index 33134c97e..3f92e9996 100755 --- a/app/views/comfy/admin/api_namespaces/show.html.haml +++ b/app/views/comfy/admin/api_namespaces/show.html.haml @@ -202,7 +202,7 @@ No CMS associations for this api-namespace #social.tab-pane.fade{"aria-labelledby" => "social-tab", :role => "tabpanel"} - = form_with(method: :patch , url: api_namespace_path(@api_namespace)) do |f| + = form_with(method: :patch , url: social_share_metadata_api_namespace_path(@api_namespace)) do |f| .form-group = f.label :title = f.select 'api_namespace[social_share_metadata][title]', options_for_select(@api_namespace.properties.keys,(@api_namespace.social_share_metadata.present? ? @api_namespace.social_share_metadata["title"] : nil)),{include_blank: "Choose an option"}, {class: 'form-control'} @@ -215,38 +215,40 @@ .form-group = f.submit "Submit", class: 'btn btn-primary' -.container-fluid.mt-5 - .d-flex.justify-content-between.py-2.page-header - %h2 - Listing - = @api_namespace.name.pluralize - %div - = link_to "Create new #{@api_namespace.name.singularize}", new_api_namespace_resource_path(api_namespace_id: @api_namespace.id), class: 'btn btn-primary' - - = render partial: 'comfy/admin/api_resources/search_filters', locals: { objects: @api_resources_q, path: api_namespace_path(@api_namespace) } - = render partial: 'pagination', locals: { objects: @api_resources } - .table-responsive - %table - %thead - %tr - %th.px-3= sort_link @api_resources_q, :id - %th.px-3= sort_link @api_resources_q, :created_at - %th.px-3= sort_link @api_resources_q, :updated_at - - dynamic_columns = @api_namespace.properties.keys - - dynamic_columns.each do |dynamic_column| - %th.px-3= sort_link @api_resources_q, dynamic_column - %th.px-3 - %th.px-3 - %tbody - - @api_resources.each do |api_resource| +-# We show this only if the user has full_access or access related to api-resources +- if has_access_to_api_accessibility?(ApiNamespace::API_ACCESSIBILITIES[:read_api_resources_only], current_user, @api_namespace) + #api-resources-list.container-fluid.mt-5 + .d-flex.justify-content-between.py-2.page-header + %h2 + Listing + = @api_namespace.name.pluralize + %div + = link_to "Create new #{@api_namespace.name.singularize}", new_api_namespace_resource_path(api_namespace_id: @api_namespace.id), class: 'btn btn-primary' + + = render partial: 'comfy/admin/api_resources/search_filters', locals: { objects: @api_resources_q, path: api_namespace_path(@api_namespace) } + = render partial: 'pagination', locals: { objects: @api_resources } + .table-responsive + %table + %thead %tr - %td.px-3.py-2= link_to api_resource.id, api_namespace_resource_path(api_namespace_id: api_resource.api_namespace_id, id: api_resource.id) - %td.px-3= api_resource.created_at.strftime('%F %T') - %td.px-3= api_resource.updated_at.strftime('%F %T') + %th.px-3= sort_link @api_resources_q, :id + %th.px-3= sort_link @api_resources_q, :created_at + %th.px-3= sort_link @api_resources_q, :updated_at + - dynamic_columns = @api_namespace.properties.keys - dynamic_columns.each do |dynamic_column| - %td.px-3= api_resource.properties[dynamic_column] - %td.px-3= link_to 'Edit', edit_api_namespace_resource_path(api_namespace_id: api_resource.api_namespace_id, id: api_resource.id) - %td.px-3= link_to 'Destroy', api_namespace_resource_path(api_namespace_id: api_resource.api_namespace_id, id: api_resource.id), method: :delete, data: { confirm: 'Are you sure?' } + %th.px-3= sort_link @api_resources_q, dynamic_column + %th.px-3 + %th.px-3 + %tbody + - @api_resources.each do |api_resource| + %tr + %td.px-3.py-2= link_to api_resource.id, api_namespace_resource_path(api_namespace_id: api_resource.api_namespace_id, id: api_resource.id) + %td.px-3= api_resource.created_at.strftime('%F %T') + %td.px-3= api_resource.updated_at.strftime('%F %T') + - dynamic_columns.each do |dynamic_column| + %td.px-3= api_resource.properties[dynamic_column] + %td.px-3= link_to 'Edit', edit_api_namespace_resource_path(api_namespace_id: api_resource.api_namespace_id, id: api_resource.id) + %td.px-3= link_to 'Destroy', api_namespace_resource_path(api_namespace_id: api_resource.api_namespace_id, id: api_resource.id), method: :delete, data: { confirm: 'Are you sure?' } %br diff --git a/app/views/comfy/admin/users/_api_accessibility.haml b/app/views/comfy/admin/users/_api_accessibility.haml new file mode 100644 index 000000000..0905adafb --- /dev/null +++ b/app/views/comfy/admin/users/_api_accessibility.haml @@ -0,0 +1,295 @@ +.card.api-accessibility.my-5 + .card-header + %strong + Can manage API + .card-body + .form-group + = check_box_tag '', nil, has_access_to_main_category?(@user.api_accessibility, 'all_namespaces'), data: { group: 'api-sub-settings', type: 'toggle-checkboxes' } + %label + All Namespaces + + %ul.mt-2{ style: "display: #{has_access_to_main_category?(@user.api_accessibility, 'all_namespaces') ? 'block' : 'none'}"} + %li + = check_box_tag 'user[api_accessibility][all_namespaces][full_access]', true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces'), class: 'full-access-option', disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces') + = label_tag nil, 'Full access' + %ul.mb-2.sub-options + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_read_access', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: { name: 'user[api_accessibility][all_namespaces][full_read_access]'} + = label_tag nil, 'Full read access' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_api_namespace_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: { name: 'user[api_accessibility][all_namespaces][full_access_api_namespace_only]'} + = label_tag nil, 'Full access for API Namespace only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'delete_access_api_namespace_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: { name: 'user[api_accessibility][all_namespaces][delete_access_api_namespace_only]'} + = label_tag nil, 'Delete access for API Namespace only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_exports', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][allow_exports]'} + = label_tag nil, 'Allow exports' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_duplication', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][allow_duplication]'} + = label_tag nil, 'Allow duplication' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_social_share_metadata', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][allow_social_share_metadata]'} + = label_tag nil, 'Allow social share metadata' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_resources_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][read_api_resources_only]'} + = label_tag nil, 'Read API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'delete_access_for_api_resources_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][delete_access_for_api_resources_only]'} + = label_tag nil, 'Delete access for API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_resources_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][full_access_for_api_resources_only]'} + = label_tag nil, 'Full access for API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_actions_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][read_api_actions_only]'} + = label_tag nil, 'Read API Actions only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_actions_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][full_access_for_api_actions_only]'} + = label_tag nil, 'Full access for API Actions only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_external_api_connections_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][read_external_api_connections_only]'} + = label_tag nil, 'Read External API Connections only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_external_api_connections_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][full_access_for_external_api_connections_only]'} + = label_tag nil, 'Full access for External API Connections only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_clients_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][read_api_clients_only]'} + = label_tag nil, 'Read API Clients only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_clients_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][full_access_for_api_clients_only]'} + = label_tag nil, 'Full access for API Clients only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'all_namespaces') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_form_only', 'all_namespaces'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'all_namespaces'), data: {name: 'user[api_accessibility][all_namespaces][full_access_for_api_form_only]'} + = label_tag nil, 'Full access for API Form only' + + .form-group + = check_box_tag '', nil, has_access_to_main_category?(@user.api_accessibility, 'namespaces_by_category'), data: { group: 'api-sub-settings', type: 'toggle-checkboxes' } + %label + API Namespaces by category + + - categories = Comfy::Cms::Category.of_type('ApiNamespace') + + %ul.mt-2{ style: "display: #{has_access_to_main_category?(@user.api_accessibility, 'namespaces_by_category') ? 'block' : 'none'}"} + - categories.each do |category| + %li + .form-group + = check_box_tag '', nil, has_access_to_specific_category?(@user.api_accessibility, category.label), data: { group: 'api-sub-settings' } + %label + = category.label + %ul.mt-2{ style: "display: #{has_access_to_specific_category?(@user.api_accessibility, category.label) ? 'block' : 'none'}"} + %li + = check_box_tag "user[api_accessibility][namespaces_by_category][#{category.label}][full_access]", true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label), class: 'full-access-option', disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label) + = label_tag nil, 'Full access' + %ul.mb-2.sub-options + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_read_access', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_read_access]"} + = label_tag nil, 'Full read access' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_api_namespace_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_access_api_namespace_only]"} + = label_tag nil, 'Full access for API Namespace only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'delete_access_api_namespace_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][delete_access_api_namespace_only]"} + = label_tag nil, 'Delete access for API Namespace only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_exports', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][allow_exports]"} + = label_tag nil, 'Allow exports' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_duplication', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][allow_duplication]"} + = label_tag nil, 'Allow duplication' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_social_share_metadata', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][allow_social_share_metadata]"} + = label_tag nil, 'Allow social share metadata' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_resources_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][read_api_resources_only]"} + = label_tag nil, 'Read API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_resources_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_access_for_api_resources_only]"} + = label_tag nil, 'Full access for API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'delete_access_for_api_resources_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][delete_access_for_api_resources_only]"} + = label_tag nil, 'Delete access for API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_actions_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][read_api_actions_only]"} + = label_tag nil, 'Read API Actions only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_actions_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_access_for_api_actions_only]"} + = label_tag nil, 'Full access for API Actions only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_external_api_connections_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][read_external_api_connections_only]"} + = label_tag nil, 'Read External API Connections only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_external_api_connections_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_access_for_external_api_connections_only]"} + = label_tag nil, 'Full access for External API Connections only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_clients_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][read_api_clients_only]"} + = label_tag nil, 'Read API Clients only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_clients_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_access_for_api_clients_only]"} + = label_tag nil, 'Full access for API Clients only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', category.label) || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_form_only', 'namespaces_by_category', category.label), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', category.label), data: {name: "user[api_accessibility][namespaces_by_category][#{category.label}][full_access_for_api_form_only]"} + = label_tag nil, 'Full access for API Form only' + + %li + .form-group + = check_box_tag '', nil, has_access_to_specific_category?(@user.api_accessibility, 'uncategorized'), data: { group: 'api-sub-settings' } + %label.text-primary + uncategorized + %ul.mt-2{ style: "display: #{has_access_to_specific_category?(@user.api_accessibility, 'uncategorized') ? 'block' : 'none'}"} + %li + = check_box_tag "user[api_accessibility][namespaces_by_category][uncategorized][full_access]", true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized'), class: 'full-access-option', disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized') + = label_tag nil, 'Full access' + %ul.mb-2.sub-options + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_read_access', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_read_access]"} + = label_tag nil, 'Full read access' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_api_namespace_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_access_api_namespace_only]"} + = label_tag nil, 'Full access for API Namespace only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'delete_access_api_namespace_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][delete_access_api_namespace_only]"} + = label_tag nil, 'Delete access for API Namespace only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_exports', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][allow_exports]"} + = label_tag nil, 'Allow exports' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_duplication', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: 'user[api_accessibility][namespaces_by_category][uncategorized][allow_duplication]'} + = label_tag nil, 'Allow duplication' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'allow_social_share_metadata', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: 'user[api_accessibility][namespaces_by_category][uncategorized][allow_social_share_metadata]'} + = label_tag nil, 'Allow social share metadata' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_resources_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][read_api_resources_only]"} + = label_tag nil, 'Read API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_resources_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_access_for_api_resources_only]"} + = label_tag nil, 'Full access for API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'delete_access_for_api_resources_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][delete_access_for_api_resources_only]"} + = label_tag nil, 'Delete access for API Resources only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_actions_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][read_api_actions_only]"} + = label_tag nil, 'Read API Actions only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_actions_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_access_for_api_actions_only]"} + = label_tag nil, 'Full access for API Actions only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_external_api_connections_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][read_external_api_connections_only]"} + = label_tag nil, 'Read External API Connections only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_external_api_connections_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_access_for_external_api_connections_only]"} + = label_tag nil, 'Full access for External API Connections only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'read_api_clients_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][read_api_clients_only]"} + = label_tag nil, 'Read API Clients only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_clients_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_access_for_api_clients_only]"} + = label_tag nil, 'Full access for API Clients only' + %li + = check_box_tag nil, true, has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'uncategorized') || has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access_for_api_form_only', 'namespaces_by_category', 'uncategorized'), disabled: !has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'uncategorized'), data: {name: "user[api_accessibility][namespaces_by_category][uncategorized][full_access_for_api_form_only]"} + = label_tag nil, 'Full access for API Form only' + +:css + .api-accessibility ul { + list-style-type: none; + + li { + list-style-type: none; + } + } + +:javascript + $(document).ready(function() { + toggleContent(); + toggleCheckboxes(); + toggleFullAccessAndSubOptions(); + + // intialize indeterminate states for full-access checkboxes + $("input.full-access-option[type='checkbox']:not([disabled='disabled'])").each(function() { + const subOptions = $(this).parent().next().find("input[type='checkbox']"); + const totalSubOptions = subOptions.length; + const totalCheckedSubOptions = $(this).parent().next().find("input[type='checkbox']:checked").length; + + const shouldFullAccessBeIndeterminate = totalCheckedSubOptions > 0 && totalCheckedSubOptions < totalSubOptions; + $(this).prop('indeterminate', shouldFullAccessBeIndeterminate); + }); + }); + + function toggleContent() { + $("input[data-group='api-sub-settings']").on('change', function() { + const specificAccessCheckboxes = $(this).siblings('ul').first().find("> li > input.full-access-option[type='checkbox'], > li + ul.sub-options input[type='checkbox']"); + const categoryCheckboxes = $(this).siblings('ul').first().find("> li > div > input[type='checkbox']"); + + if (this.checked) { + if ($(specificAccessCheckboxes).attr('value')) { + $(specificAccessCheckboxes).attr('disabled', false); + $(specificAccessCheckboxes).prop('checked', true); + } + $(this).siblings('ul').show(); + } else { + if ($(specificAccessCheckboxes).attr('value')) { + $(specificAccessCheckboxes).attr('disabled', true); + $(specificAccessCheckboxes).prop('checked', false); + } + $(categoryCheckboxes).prop('checked', false); + $(categoryCheckboxes).trigger('change'); + + $(this).siblings('ul').hide(); + } + + $(specificAccessCheckboxes).trigger('change'); + }) + } + + function toggleCheckboxes() { + $("input[data-type='toggle-checkboxes']").on('click', function() { + if (this.checked) { + const currentElement = this; + + $("input[data-type='toggle-checkboxes']").each(function() { + if (this != currentElement) { + this.checked = false; + $(this).trigger('change'); + } + }) + } + }) + } + + function toggleFullAccessAndSubOptions() { + $('input.full-access-option').on('change', function() { + const subOptionCheckboxes = $(this).parent().siblings('ul.sub-options').find("input[type='checkbox']"); + + + if (this.checked) { + subOptionCheckboxes.prop('checked', true); + } else { + subOptionCheckboxes.prop('checked', false); + } + subOptionCheckboxes.trigger('change'); + }) + + $("ul.sub-options input[type='checkbox']").on('change', function() { + const fullAccessCheckbox = $(this).parents("ul.sub-options").siblings('li').find("input.full-access-option[type='checkbox']"); + const subOptions = $(this).parents("ul.sub-options").find("input[type='checkbox']"); + const totalSubOptions = subOptions.length; + const totalCheckedSubOptions = $(this).parents("ul.sub-options").find("input[type='checkbox']:checked").length; + + const shouldCheckFullAccess = totalCheckedSubOptions > 0 && totalCheckedSubOptions == totalSubOptions; + const shouldFullAccessBeIndeterminate = totalCheckedSubOptions > 0 && totalCheckedSubOptions < totalSubOptions; + + fullAccessCheckbox.prop('checked', shouldCheckFullAccess); + fullAccessCheckbox.prop('indeterminate', shouldFullAccessBeIndeterminate); + + if (shouldCheckFullAccess) { + subOptions.each(function() { + $(this).removeAttr('name'); + }); + } else { + subOptions.each(function() { + const nameAttrValue = $(this).attr('data-name'); + $(this).attr('name', nameAttrValue); + }); + } + }) + } \ No newline at end of file diff --git a/app/views/comfy/admin/users/_form.haml b/app/views/comfy/admin/users/_form.haml index 40a814252..dc90421de 100644 --- a/app/views/comfy/admin/users/_form.haml +++ b/app/views/comfy/admin/users/_form.haml @@ -39,14 +39,11 @@ = f.check_box :can_manage_email %label Can manage emailbox - .form-group - = f.check_box :can_manage_api - %label - Can manage API .form-group = f.check_box :can_manage_blog %label Can manage Blog + = render partial: 'api_accessibility' .card.my-5 .card-header %strong diff --git a/app/views/comfy/admin/users/index.html.haml b/app/views/comfy/admin/users/index.html.haml index 3a6748369..eedadecaa 100644 --- a/app/views/comfy/admin/users/index.html.haml +++ b/app/views/comfy/admin/users/index.html.haml @@ -27,7 +27,7 @@ %th{:scope => "col"} = sort_link @users_q, :can_manage_blog %th{:scope => "col"} - = sort_link @users_q, :can_manage_api + = sort_link @users_q, :api_accessibility %th{:scope => "col"} = sort_link @users_q, :can_manage_subdomain_settings, 'Can manage app settings' %th{:scope => "col"} @@ -51,7 +51,7 @@ %td= user.can_manage_email %td= user.can_manage_users %td= user.can_manage_blog - %td= user.can_manage_api + %td= user.api_accessibility.to_json %td= user.can_manage_subdomain_settings %td= user.can_view_restricted_pages %td= user.moderator diff --git a/config/routes.rb b/config/routes.rb index fe698dab2..00569e551 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,6 +61,8 @@ def self.matches?(request) post 'duplicate_without_associations' get 'export_with_associations_as_json' get 'export_without_associations_as_json' + patch 'social_share_metadata' + patch 'api_action_workflow' end resources :resources, except: [:index], controller: 'comfy/admin/api_resources' @@ -77,7 +79,7 @@ def self.matches?(request) resources :resource, controller: 'resource', only: [:create] - resources :api_actions, controller: 'comfy/admin/api_actions', only: [:index, :show] do + resources :api_actions, controller: 'comfy/admin/api_actions', only: [:index, :show, :new] do collection do get 'action_workflow' end @@ -91,7 +93,6 @@ def self.matches?(request) end end resources :non_primitive_properties, controller: 'comfy/admin/non_primitive_properties', only: [:new] - resources :api_actions, controller: 'comfy/admin/api_actions', only: [:new] # system admin panel login devise_scope :user do diff --git a/db/migrate/20220913021415_add_api_accessibility_to_users.rb b/db/migrate/20220913021415_add_api_accessibility_to_users.rb new file mode 100644 index 000000000..540857e3f --- /dev/null +++ b/db/migrate/20220913021415_add_api_accessibility_to_users.rb @@ -0,0 +1,5 @@ +class AddApiAccessibilityToUsers < ActiveRecord::Migration[6.1] + def change + add_column :users, :api_accessibility, :jsonb, default: {} + end +end diff --git a/db/migrate/20220917134117_remove_can_manage_api_from_users_and_back_fill_api_accessibility.rb b/db/migrate/20220917134117_remove_can_manage_api_from_users_and_back_fill_api_accessibility.rb new file mode 100644 index 000000000..c691ae63f --- /dev/null +++ b/db/migrate/20220917134117_remove_can_manage_api_from_users_and_back_fill_api_accessibility.rb @@ -0,0 +1,17 @@ +class RemoveCanManageApiFromUsersAndBackFillApiAccessibility < ActiveRecord::Migration[6.1] + def up + users_to_be_given_full_access = User.where(can_manage_api: true) + users_to_be_given_full_access.each do |user| + user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + end + + remove_column :users, :can_manage_api + end + + def down + add_column :users, :can_manage_api, :boolean, default: false + + users_to_be_given_api_access = User.where("api_accessibility#>>'{all_namespaces, full_access}' = ?", "true") + users_to_be_given_api_access.update_all("can_manage_api": true) + end +end diff --git a/db/schema.rb b/db/schema.rb index b76e1c5bb..9efa6d900 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -525,13 +525,13 @@ t.boolean "moderator" t.boolean "can_view_restricted_pages" t.boolean "deliver_analytics_report", default: false - t.boolean "can_manage_api", default: false t.boolean "can_manage_subdomain_settings", default: false t.string "session_timeoutable_in", default: "1-hour" t.boolean "can_access_admin", default: false t.boolean "deliver_error_notifications", default: false t.boolean "can_manage_analytics", default: false t.boolean "can_manage_files", default: false + t.jsonb "api_accessibility", default: {} t.string "encrypted_otp_secret" t.string "encrypted_otp_secret_iv" t.string "encrypted_otp_secret_salt" diff --git a/test/controllers/admin/comfy/api_actions_controller_test.rb b/test/controllers/admin/comfy/api_actions_controller_test.rb index 46d54be6c..cbb50568f 100644 --- a/test/controllers/admin/comfy/api_actions_controller_test.rb +++ b/test/controllers/admin/comfy/api_actions_controller_test.rb @@ -3,15 +3,15 @@ class Comfy::Admin::ApiActionsControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) @api_namespace = api_namespaces(:one) @api_action = api_actions(:one) end test "should not get #index, #new, #show if signed in but not allowed to manage api" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) - get new_api_action_url(index: 1, type: 'new_api_actions'), xhr: true + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true assert_response :redirect get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) assert_response :redirect @@ -21,7 +21,7 @@ class Comfy::Admin::ApiActionsControllerTest < ActionDispatch::IntegrationTest test "should get new" do sign_in(@user) - get new_api_action_url(index: 1, type: 'new_api_actions'), xhr: true + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true assert_response :success end @@ -43,4 +43,782 @@ class Comfy::Admin::ApiActionsControllerTest < ActionDispatch::IntegrationTest get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) assert_response :success end + + # SHOW + # API access for all_namespaces + test 'should get show if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has full_access_for_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has read_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_actions_only: 'true'}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should not get show if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_actions_only or read_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get show if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has full_access_for_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has read_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_actions_only: 'true'}}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should get show if user has read_api_actions_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_api_actions_only: 'true'}}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :success + end + + test 'should not get show if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + api_action = api_actions(:two) + get api_namespace_api_action_url(api_action, api_namespace_id: api_action.api_resource.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_actions_only or read_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # INDEX + # API access for all_namespaces + test 'should get index if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has full_access_for_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has read_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_actions_only: 'true'}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should not get index if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_actions_only or read_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get index if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has full_access_for_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has read_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_actions_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get index if user has read_api_actions_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_api_actions_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should not get index if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_actions_only or read_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # NEW + # API access for all_namespaces + test 'should get new if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should get new if user has full_access_for_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should not get new if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_actions_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get new if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should get new if user has full_access_for_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should get new if user has read_api_actions_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should not get new if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_actions_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # EDIT + # API access for all_namespaces + test 'should get edit if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should get edit if user has full_access_for_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should not get edit if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_actions_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get edit if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should get edit if user has full_access_for_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should get edit if user has read_api_actions_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :success + end + + test 'should not get edit if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_actions_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_action_url(api_namespace_id: @api_action.api_namespace_id, index: 1, type: 'new_api_actions'), xhr: true + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # ACTION_WORKFLOW + # API access for all_namespaces + test 'should get action_workflow if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get action_workflow if user has full_access_for_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should not get action_workflow if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_actions_only: 'true'}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test 'should update action_workflow if user has full_access_for_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + payload = { + api_namespace: { + create_api_actions_attributes: { + "0": { + action_type: "send_email", + include_api_resource_data: "true", + email: "test@restarone.com", + email_subject: "Test", + custom_message: "
Test email
\r\n", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "0" + }, + "1": { + action_type: "send_web_request", + include_api_resource_data: "false", + email: "", + email_subject: "", + custom_message: "
", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "https://api.spotify.com/v1/search", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "1" + } + } + } + } + + sign_in(@user) + assert_difference "@api_action.api_namespace.create_api_actions.count", 2 do + patch api_action_workflow_api_namespace_url(id: @api_action.api_namespace_id), params: payload + end + + assert_response :redirect + expected_message = 'Action Workflow successfully updated.' + assert_equal expected_message, flash[:notice] + end + + test 'should not update action_workflow if user has read_api_actions_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_actions_only: 'true'}}) + + payload = { + api_namespace: { + create_api_actions_attributes: { + "0": { + action_type: "send_email", + include_api_resource_data: "true", + email: "test@restarone.com", + email_subject: "Test", + custom_message: "
Test email
\r\n", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "0" + }, + "1": { + action_type: "send_web_request", + include_api_resource_data: "false", + email: "", + email_subject: "", + custom_message: "
", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "https://api.spotify.com/v1/search", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "1" + } + } + } + } + + sign_in(@user) + assert_no_difference "@api_action.api_namespace.create_api_actions.count" do + patch api_action_workflow_api_namespace_url(id: @api_action.api_namespace_id), params: payload + end + + assert_response :redirect + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get action_workflow if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get action_workflow if user has full_access_for_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should get action_workflow if user has read_api_actions_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_actions_only: 'true'}}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :success + end + + test 'should not get action_workflow if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_actions_only: 'true'}}}) + + sign_in(@user) + get action_workflow_api_namespace_api_actions_url(api_namespace_id: @api_action.api_namespace_id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test 'should update action_workflow if user has category-specific full_access_for_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + payload = { + api_namespace: { + create_api_actions_attributes: { + "0": { + action_type: "send_email", + include_api_resource_data: "true", + email: "test@restarone.com", + email_subject: "Test", + custom_message: "
Test email
\r\n", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "0" + }, + "1": { + action_type: "send_web_request", + include_api_resource_data: "false", + email: "", + email_subject: "", + custom_message: "
", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "https://api.spotify.com/v1/search", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "1" + } + } + } + } + + sign_in(@user) + assert_difference "@api_action.api_namespace.create_api_actions.count", 2 do + patch api_action_workflow_api_namespace_url(id: @api_action.api_namespace_id), params: payload + end + + assert_response :redirect + expected_message = 'Action Workflow successfully updated.' + assert_equal expected_message, flash[:notice] + end + + test 'should not update action_workflow if user has category-specific read_api_actions_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_actions_only: 'true'}}}) + + payload = { + api_namespace: { + create_api_actions_attributes: { + "0": { + action_type: "send_email", + include_api_resource_data: "true", + email: "test@restarone.com", + email_subject: "Test", + custom_message: "
Test email
\r\n", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "0" + }, + "1": { + action_type: "send_web_request", + include_api_resource_data: "false", + email: "", + email_subject: "", + custom_message: "
", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "https://api.spotify.com/v1/search", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "1" + } + } + } + } + + sign_in(@user) + assert_no_difference "@api_action.api_namespace.create_api_actions.count" do + patch api_action_workflow_api_namespace_url(id: @api_action.api_namespace_id), params: payload + end + + assert_response :redirect + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test 'should update action_workflow if user has uncategorized full_access_for_api_actions_only for the namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_actions_only: 'true'}}}) + + payload = { + api_namespace: { + create_api_actions_attributes: { + "0": { + action_type: "send_email", + include_api_resource_data: "true", + email: "test@restarone.com", + email_subject: "Test", + custom_message: "
Test email
\r\n", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "0" + }, + "1": { + action_type: "send_web_request", + include_api_resource_data: "false", + email: "", + email_subject: "", + custom_message: "
", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "https://api.spotify.com/v1/search", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "1" + } + } + } + } + + sign_in(@user) + assert_difference "@api_action.api_namespace.create_api_actions.count", 2 do + patch api_action_workflow_api_namespace_url(id: @api_action.api_namespace_id), params: payload + end + + assert_response :redirect + expected_message = 'Action Workflow successfully updated.' + assert_equal expected_message, flash[:notice] + end + + test 'should not update action_workflow if user has uncategorized read_api_actions_only for the namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_api_actions_only: 'true'}}}) + + payload = { + api_namespace: { + create_api_actions_attributes: { + "0": { + action_type: "send_email", + include_api_resource_data: "true", + email: "test@restarone.com", + email_subject: "Test", + custom_message: "
Test email
\r\n", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "0" + }, + "1": { + action_type: "send_web_request", + include_api_resource_data: "false", + email: "", + email_subject: "", + custom_message: "
", + redirect_type: "cms_page", + redirect_url: "", + file_snippet: "", + request_url: "https://api.spotify.com/v1/search", + http_method: "get", + payload_mapping: "{}", + custom_headers: "{}", + bearer_token: "[FILTERED]", + method_definition: "raise StandardError", + "_destroy": "false", + position: "1" + } + } + } + } + + sign_in(@user) + assert_no_difference "@api_action.api_namespace.create_api_actions.count" do + patch api_action_workflow_api_namespace_url(id: @api_action.api_namespace_id), params: payload + end + + assert_response :redirect + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end end diff --git a/test/controllers/admin/comfy/api_clients_controller_test.rb b/test/controllers/admin/comfy/api_clients_controller_test.rb index 639f0df66..c73c3c5d7 100755 --- a/test/controllers/admin/comfy/api_clients_controller_test.rb +++ b/test/controllers/admin/comfy/api_clients_controller_test.rb @@ -3,7 +3,7 @@ class Comfy::Admin::ApiClientsControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) @api_client = api_clients(:one) @api_namespace = api_namespaces(:one) end @@ -15,7 +15,7 @@ class Comfy::Admin::ApiClientsControllerTest < ActionDispatch::IntegrationTest test "should not get #index, #new if signed in but not allowed to manage web" do sign_in(@user) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) assert_response :redirect get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) @@ -93,4 +93,630 @@ class Comfy::Admin::ApiClientsControllerTest < ActionDispatch::IntegrationTest assert_redirected_to api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) end + + # SHOW + # API access for all namespaces + test 'should get show if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has read_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should not get show if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_clients_only or read_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get show if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has read_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should get show if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_api_clients_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :show + end + + test 'should not get show if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_clients_only or read_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # INDEX + # API access for all namespaces + test 'should get index if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has read_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get index if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_clients_only or read_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get index if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has read_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_api_clients_only: 'true'}}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get index if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_clients_only or read_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # NEW + # API access for all_namespaces + test 'should get new if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get new if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get new if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get new if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_api_client_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # EDIT + # API access for all_namespaces + test 'should get edit if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :edit + end + + test 'should get edit if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :edit + end + + test 'should not get edit if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get edit if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :edit + end + + test 'should get edit if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :edit + end + + test 'should get edit if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :success + assert_template :edit + end + + test 'should not get edit if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_client_path(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # CREATE + # API access for all_namespaces + test 'should get create if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + assert_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + api_client = ApiClient.last + assert_redirected_to api_namespace_api_client_path(api_namespace_id: api_client.api_namespace.id, id: api_client.id) + end + + test 'should get create if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + api_client = ApiClient.last + assert_redirected_to api_namespace_api_client_path(api_namespace_id: api_client.api_namespace.id, id: api_client.id) + end + + test 'should not get create if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + assert_no_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + api_client = ApiClient.last + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get create if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + assert_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + api_client = ApiClient.last + assert_redirected_to api_namespace_api_client_path(api_namespace_id: api_client.api_namespace.id, id: api_client.id) + end + + test 'should get create if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + api_client = ApiClient.last + assert_redirected_to api_namespace_api_client_path(api_namespace_id: api_client.api_namespace.id, id: api_client.id) + end + + test 'should get create if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + api_client = ApiClient.last + assert_redirected_to api_namespace_api_client_path(api_namespace_id: api_client.api_namespace.id, id: api_client.id) + end + + test 'should not get create if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + assert_no_difference('ApiClient.count') do + post api_namespace_api_clients_url(api_namespace_id: @api_namespace.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, label: "foobar" } } + end + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # UPDATE + # API access for all_namespaces + test 'should get update if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_redirected_to api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + test 'should get update if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_redirected_to api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + test 'should not get update if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get update if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_redirected_to api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + test 'should get update if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_redirected_to api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + test 'should get update if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_redirected_to api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + test 'should not get update if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id), params: { api_client: { authentication_strategy: @api_client.authentication_strategy, bearer_token: @api_client.bearer_token, label: @api_client.label } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # DESTROY + # API access for all_namespaces + test 'should destroy if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + assert_difference('ApiClient.count', -1) do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_redirected_to api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + end + + test 'should destroy if user has full_access_for_api_clients_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_clients_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiClient.count', -1) do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_redirected_to api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + end + + test 'should not destroy if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_clients_only: 'true'}}) + + sign_in(@user) + assert_no_difference('ApiClient.count') do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should destroy if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + assert_difference('ApiClient.count', -1) do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_redirected_to api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + end + + test 'should destroy if user has full_access_for_api_clients_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiClient.count', -1) do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_redirected_to api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + end + + test 'should destroy if user has read_api_clients_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_clients_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiClient.count', -1) do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_redirected_to api_namespace_api_clients_url(api_namespace_id: @api_namespace.id) + end + + test 'should not destroy if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_clients_only: 'true'}}}) + + sign_in(@user) + assert_no_difference('ApiClient.count') do + delete api_namespace_api_client_url(api_namespace_id: @api_client.api_namespace.id, id: @api_client.id) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_clients_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + end diff --git a/test/controllers/admin/comfy/api_forms_controller_test.rb b/test/controllers/admin/comfy/api_forms_controller_test.rb index cda5dc58a..10a1fb331 100644 --- a/test/controllers/admin/comfy/api_forms_controller_test.rb +++ b/test/controllers/admin/comfy/api_forms_controller_test.rb @@ -3,21 +3,192 @@ class Comfy::Admin::ApiFormsControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) @api_namespace = api_namespaces(:one) @api_form = api_forms(:one) end - test "should get edit" do + test "should get edit if permissioned" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + sign_in(@user) + + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :success + + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_form_only: 'true'}}) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :success + end + + test "deny edit if not permissioned" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + sign_in(@user) + + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :redirect + assert_equal "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action.", flash[:alert] + end + + test "should update api_form if permissioned" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + sign_in(@user) + + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) + + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_form_only: 'true'}}) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) + end + + test "deny update api_form if not permissioned" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + sign_in(@user) + + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_response :redirect + assert_equal "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action.", flash[:alert] + end + + # EDIT + # API access for all_namespaces + test 'should get edit if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :success + end + + test 'should get edit if user has full_access_for_api_form_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_form_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :success + end + + test 'should not get edit if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get edit if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :success + end + + test 'should get edit if user has full_access_for_api_form_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_form_only: 'true'}}}) + sign_in(@user) get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) assert_response :success end - test "should update api_form" do + test 'should get edit if user has full_access_for_api_form_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_form_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :success + end + + test 'should not get edit if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_api_form_url(api_namespace_id: @api_namespace.id, id: ApiForm.last.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # UPDATE + # API access for all_namespaces + test 'should get update if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + sign_in(@user) patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) end + + test 'should get update if user has full_access_for_api_form_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_form_only: 'true'}}) + + sign_in(@user) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) + end + + test 'should not get update if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get update if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) + end + + test 'should get update if user has full_access_for_api_form_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_form_only: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) + end + + test 'should get update if user has full_access_for_api_form_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_form_only: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_redirected_to api_namespace_url(@api_form.api_namespace.slug) + end + + test 'should not get update if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + patch api_namespace_api_form_url(@api_form, api_namespace_id: @api_form.api_namespace_id), params: { api_form: { properties: @api_form.properties } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_form_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end end diff --git a/test/controllers/admin/comfy/api_namespaces_controller_test.rb b/test/controllers/admin/comfy/api_namespaces_controller_test.rb index 3bab92fcf..2a7815af6 100755 --- a/test/controllers/admin/comfy/api_namespaces_controller_test.rb +++ b/test/controllers/admin/comfy/api_namespaces_controller_test.rb @@ -3,7 +3,7 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) @api_namespace = api_namespaces(:one) end @@ -14,7 +14,7 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes test "should not get index if signed in but not allowed to manage api" do sign_in(@user) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) get api_namespaces_url assert_response :redirect end @@ -140,14 +140,14 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes test "should not allow duplicate_without_associations if not allowed to manage api" do api_form = api_forms(:one) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) assert_response :redirect - error_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + error_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_duplication are allowed to perform that action." assert_match error_message, request.flash[:alert] end @@ -199,14 +199,14 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes test "should not allow duplicate_with_associations if not allowed to manage api" do api_form = api_forms(:one) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) post duplicate_with_associations_api_namespace_url(id: @api_namespace.id) assert_response :redirect - error_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + error_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_duplication are allowed to perform that action." assert_match error_message, request.flash[:alert] end @@ -367,18 +367,18 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes end test "should deny exporting of api-resources as CSV if the user is not authorized" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) api_namespace = api_namespaces(:namespace_with_all_types) get export_api_resources_api_namespace_url(api_namespace, format: :csv) assert_response :redirect - assert_equal "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action.", flash[:alert] + assert_equal "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action.", flash[:alert] end test "should deny export api_namespace without associations as JSON if user is not authorized" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get export_without_associations_as_json_api_namespace_url(@api_namespace) assert_response :redirect @@ -393,7 +393,7 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes end test "should deny export api_namespace with associations as JSON if user is not authorized" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get export_with_associations_as_json_api_namespace_url(@api_namespace) assert_response :redirect @@ -442,7 +442,7 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes file: fixture_file_upload(json_file.path, 'application/json') } - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) assert_no_difference('ApiNamespace.count') do assert_no_difference('ApiResource.count') do @@ -452,6 +452,7 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes assert_no_difference('NonPrimitiveProperty.count') do post import_as_json_api_namespaces_url, params: payload assert_response :redirect + assert_equal "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action.", flash[:alert] end end end @@ -634,30 +635,2106 @@ class Comfy::Admin::ApiNamespacesControllerTest < ActionDispatch::IntegrationTes end end - test "#show: should allow sorting by dynamic columns" do + # INDEX + # API access for all_namespaces + test "should get index if user has full_access for all namespaces" do sign_in(@user) - api_namespace = api_namespaces(:users) - api_namespace.update(properties: { - last_name: "", - first_name: "" - }) - api_namespace.api_resources.create!({ - properties: { - last_name: "Doe", - first_name: "John", - } - }) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + get api_namespaces_url + assert_response :success + end - assert_equal api_namespace.api_resources.length, 2 - assert_equal api_namespace.api_resources[0].properties['first_name'], "Don" - assert_equal api_namespace.api_resources[1].properties['first_name'], "John" + test "should get index if user has full_read_access for all namespaces" do + sign_in(@user) + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + get api_namespaces_url + assert_response :success + end - get api_namespace_url(api_namespace), params: {q: { s: "first_name desc" }} + test "should get index if user has full_access_api_namespace_only for all namespaces" do + sign_in(@user) + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + get api_namespaces_url assert_response :success + end - assert_select "tbody tr" do |rows| - assert_includes rows[0].to_s, "John" - assert_includes rows[1].to_s, "Don" + test "should get index if user has other access for all namespaces" do + sign_in(@user) + @user.update(api_accessibility: {all_namespaces: {allow_exports: 'true'}}) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has allow_social_share_metadata access for all namespaces" do + sign_in(@user) + @user.update(api_accessibility: {all_namespaces: {allow_social_share_metadata: 'true'}}) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has other access related to api-actions/api-resources/api-clients/api-form/external-api-connection for all namespaces" do + ['read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + end + + test "should get index with all namespaces if user has access for all_namespaces" do + sign_in(@user) + @user.update(api_accessibility: {all_namespaces: {allow_exports: 'true'}}) + get api_namespaces_url + assert_response :success + + # All the ApiNamespaces are fetched in controller. + all_namespaces = @controller.view_assigns['api_namespaces_q'].result + ApiNamespace.all.each do |namespace| + assert_includes all_namespaces, namespace + end + end + + # API access by category + test "should get index if user has category specific full_access for one of the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has category specific full_read_access for one of the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has category specific full_access_api_namespace_only for one of the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has category specific other access for one of the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has category-specific allow_social_share_metadata access for one of the namespaces" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_social_share_metadata: 'true'}}}) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has uncategorized allow_social_share_metadata access for one of the namespaces" do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {allow_social_share_metadata: 'true'}}}) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + + test "should get index if user has other category specific access related to api-actions/api-resources/api-clients/api-form/external-api-connection for namespaces" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][category.label] = {} + access[:namespaces_by_category][category.label][access_name] = 'true' + + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + end + + test "should get index with only the uncategorized namespaces if user has category-specific for uncategorized namespaces" do + category = comfy_cms_categories(:api_namespace_1) + api_namespace_two = api_namespaces(:two) + + # Only two namespaces are uncategorized. + ApiNamespace.where.not(id: [@api_namespace.id, api_namespace_two.id]).each do |namespace| + namespace.update(category_ids: [category.id]) + end + + sign_in(@user) + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {allow_exports: 'true'}}}) + get api_namespaces_url + assert_response :success + + all_namespaces = @controller.view_assigns['api_namespaces_q'].result + # Only the uncategorized ApiNamespaces are fetched in controller. + [@api_namespace, api_namespace_two].each do |namespace| + assert_includes all_namespaces, namespace + end + # The api-namespaces which are categorized are not fetched. + ApiNamespace.where.not(id: [@api_namespace.id, api_namespace_two.id]).each do |namespace| + refute_includes all_namespaces, namespace + end + end + + test "should get index with only the uncategorized and provided category namespaces if user has category-specific for uncategorized and some categorized namespaces" do + category_one = comfy_cms_categories(:api_namespace_1) + category_two = comfy_cms_categories(:api_namespace_2) + + api_namespace_two = api_namespaces(:two) + api_namespace_three = api_namespaces(:three) + api_namespace_four = api_namespaces(:users) + api_namespace_five = api_namespaces(:array_namespace) + api_namespace_six = api_namespaces(:plugin_subdomain_events) + + api_namespace_two.update(category_ids: [category_one.id]) + api_namespace_three.update(category_ids: [category_one.id]) + api_namespace_four.update(category_ids: [category_one.id]) + + expected_namespaces = [@api_namespace, api_namespace_two, api_namespace_three, api_namespace_four, api_namespace_five, api_namespace_six] + + # Other namespaces are categorized to category_two. + ApiNamespace.where.not(id: expected_namespaces.map(&:id)).each do |namespace| + namespace.update(category_ids: [category_two.id]) + end + + sign_in(@user) + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {allow_exports: 'true'}, "#{category_one.label}": {allow_exports: 'true'}}}) + get api_namespaces_url + assert_response :success + + all_namespaces = @controller.view_assigns['api_namespaces_q'].result + # Only the uncategorized & category_one ApiNamespaces are fetched in controller. + expected_namespaces.each do |namespace| + assert_includes all_namespaces, namespace + end + # The api-namespaces which are categorized are not fetched. + ApiNamespace.where.not(id: expected_namespaces.map(&:id)).each do |namespace| + refute_includes all_namespaces, namespace + end + end + + test "should get index with only provided category namespaces if user has category-specific for some categorized namespaces" do + category_one = comfy_cms_categories(:api_namespace_1) + category_two = comfy_cms_categories(:api_namespace_2) + + api_namespace_two = api_namespaces(:two) + api_namespace_three = api_namespaces(:three) + api_namespace_four = api_namespaces(:users) + api_namespace_five = api_namespaces(:array_namespace) + api_namespace_six = api_namespaces(:plugin_subdomain_events) + + api_namespace_two.update(category_ids: [category_one.id]) + api_namespace_three.update(category_ids: [category_one.id]) + api_namespace_four.update(category_ids: [category_one.id]) + + @api_namespace.update(category_ids: [category_two.id]) + api_namespace_five.update(category_ids: [category_two.id]) + api_namespace_six.update(category_ids: [category_two.id]) + # Other namespaces are uncategorized. + + expected_namespaces = [@api_namespace, api_namespace_two, api_namespace_three, api_namespace_four, api_namespace_five, api_namespace_six] + + sign_in(@user) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_two.label}": {allow_exports: 'true'}, "#{category_one.label}": {allow_exports: 'true'}}}) + get api_namespaces_url + assert_response :success + + all_namespaces = @controller.view_assigns['api_namespaces_q'].result + # Only the category_one & category_two ApiNamespaces are fetched in controller. + expected_namespaces.each do |namespace| + assert_includes all_namespaces, namespace + end + # The api-namespaces which are uncategorized are not fetched. + ApiNamespace.where.not(id: expected_namespaces.map(&:id)).each do |namespace| + refute_includes all_namespaces, namespace + end + end + + test "should get index if user has other uncategorized access related to api-actions/api-resources/api-clients/api-form/external-api-connection for namespaces" do + ['read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {uncategorized: {}}} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespaces_url + assert_response :success + end + end + + # NEW + # API access for all_namespace + test "should get new if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_url + assert_response :success + end + + test "should get new if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_url + assert_response :success + end + + test "should not get new if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_url + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should not get new if user has access by category wise" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get new_api_namespace_url + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # CREATE + # API access for all_namespace + test "should create if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + assert_difference('ApiNamespace.count') do + post api_namespaces_url, params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + end + api_namespace = ApiNamespace.last + assert api_namespace.slug + assert_redirected_to api_namespace_url(api_namespace) + end + + test "should create if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiNamespace.count') do + post api_namespaces_url, params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + end + api_namespace = ApiNamespace.last + assert api_namespace.slug + assert_redirected_to api_namespace_url(api_namespace) + end + + test "should not create if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + post api_namespaces_url, params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + end + api_namespace = ApiNamespace.last + assert api_namespace.slug + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should not create if user has access by category wise" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + post api_namespaces_url, params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + end + api_namespace = ApiNamespace.last + assert api_namespace.slug + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # IMPORT_AS_JSON + # API access for all_namespace + test "should import_as_json if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + json_file = Tempfile.new(['api_namespace.json', '.json']) + json_file.write(@api_namespace.export_as_json(include_associations: false)) + json_file.rewind + + payload = { + file: fixture_file_upload(json_file.path, 'application/json') + } + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + post import_as_json_api_namespaces_url, params: payload + assert_response :redirect + end + + success_message = "Api namespace was successfully imported." + assert_match success_message, request.flash[:notice] + assert_not_equal @api_namespace.name, ApiNamespace.last.name + assert_match @api_namespace.name, ApiNamespace.last.name + end + + test "should import_as_json if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + json_file = Tempfile.new(['api_namespace.json', '.json']) + json_file.write(@api_namespace.export_as_json(include_associations: false)) + json_file.rewind + + payload = { + file: fixture_file_upload(json_file.path, 'application/json') + } + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + post import_as_json_api_namespaces_url, params: payload + assert_response :redirect + end + + success_message = "Api namespace was successfully imported." + assert_match success_message, request.flash[:notice] + assert_not_equal @api_namespace.name, ApiNamespace.last.name + assert_match @api_namespace.name, ApiNamespace.last.name + end + + test "should not import_as_json if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + json_file = Tempfile.new(['api_namespace.json', '.json']) + json_file.write(@api_namespace.export_as_json(include_associations: false)) + json_file.rewind + + payload = { + file: fixture_file_upload(json_file.path, 'application/json') + } + + sign_in(@user) + assert_no_difference('ApiNamespace.count', +1) do + post import_as_json_api_namespaces_url, params: payload + assert_response :redirect + end + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should not import_as_json if user has access by category wise" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + json_file = Tempfile.new(['api_namespace.json', '.json']) + json_file.write(@api_namespace.export_as_json(include_associations: false)) + json_file.rewind + + payload = { + file: fixture_file_upload(json_file.path, 'application/json') + } + + sign_in(@user) + assert_no_difference('ApiNamespace.count', +1) do + post import_as_json_api_namespaces_url, params: payload + assert_response :redirect + end + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only for all_namespaces are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # SHOW + # API access for all_namespace + test "should show if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show if user has full_read_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show api-resources section if user has full_access or access related to api-resource for all_namespaces" do + ['full_access', 'full_read_access', 'full_access_for_api_resources_only', 'read_api_resources_only', 'delete_access_for_api_resources_only'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + assert_select 'div#api-resources-list', {count: 1} + end + end + + test "should not show if user has other access for all_namespaces" do + ['delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'allow_social_share_metadata', 'full_access_api_namespace_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + assert_select 'div#api-resources-list', {count: 0} + end + end + + test "should show if user has other access related to namespace for all_namespaces" do + ['allow_exports', 'allow_duplication', 'allow_social_share_metadata'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + end + + test "should show if user has other access related to api-actions/api-resources/api-clients/api-form/external-api-connection for all_namespaces" do + ['read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + end + + # API access by category + test "should show if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show if user has category specific full_read_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show if user has category specific other access related to api-actions/api-resources/api-clients/api-form/external-api-connection for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][category.label]= {} + access[:namespaces_by_category][category.label][access_name] = 'true' + + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + end + + test "should show if user has category-specific other access related to namespace for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['allow_exports', 'allow_duplication', 'allow_social_share_metadata'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][category.label]= {} + access[:namespaces_by_category][category.label][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + end + + test "should show if user has uncategorized access for the namespace with no category" do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show if user has uncategorized access related to api-actions/api-resources/api-clients/api-form/external-api-connection for the namespace" do + ['read_api_resources_only', 'full_access_for_api_resources_only', 'delete_access_for_api_resources_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {uncategorized: {}}} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + end + + test "should show if user has uncategorized other access related to namespace for the namespace" do + ['allow_exports', 'allow_duplication', 'allow_social_share_metadata'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][:uncategorized]= {} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + end + + test "should show if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should show if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + end + + test "should not show if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or delete_access_api_namespace_only or allow_exports or allow_duplication or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should show api-resources section if user has category-specific full_access or access related to api-resource for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['full_access', 'full_read_access', 'full_access_for_api_resources_only', 'read_api_resources_only', 'delete_access_for_api_resources_only'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][:"#{category.label}"]= {} + access[:namespaces_by_category][:"#{category.label}"][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + assert_select 'div#api-resources-list', {count: 1} + end + end + + test "should not show if user has other category-specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'allow_social_share_metadata', 'full_access_api_namespace_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][:"#{category.label}"]= {} + access[:namespaces_by_category][:"#{category.label}"][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + assert_select 'div#api-resources-list', {count: 0} + end + end + + test "should show api-resources section if user has uncategorized full_access or access related to api-resource for the namespace" do + ['full_access', 'full_read_access', 'full_access_for_api_resources_only', 'read_api_resources_only', 'delete_access_for_api_resources_only'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][:uncategorized]= {} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + assert_select 'div#api-resources-list', {count: 1} + end + end + + test "should not show if user has other uncategorized access for the namespace" do + ['delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'allow_social_share_metadata', 'full_access_api_namespace_only', 'read_api_actions_only', 'full_access_for_api_actions_only', 'read_external_api_connections_only', 'full_access_for_external_api_connections_only', 'read_api_clients_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {}} + access[:namespaces_by_category][:uncategorized]= {} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + @user.update(api_accessibility: access) + + sign_in(@user) + get api_namespace_url(@api_namespace) + assert_response :success + assert_select 'div#api-resources-list', {count: 0} + end + end + + # EDIT + # API access for all_namespace + test "should edit if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :success + end + + test "should edit if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :success + end + + test "should not edit if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should edit if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :success + end + + test "should edit if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :success + end + + test "should not edit if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not edit if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_url(@api_namespace) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # UPDATE + # API access for all_namespace + test "should update if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_redirected_to api_namespace_url(@api_namespace) + end + + test "should update if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_redirected_to api_namespace_url(@api_namespace) + end + + test "should not update if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should update if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_redirected_to api_namespace_url(@api_namespace) + end + + test "should update if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_redirected_to api_namespace_url(@api_namespace) + end + + test "should not update if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not update if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + sign_in(@user) + patch api_namespace_url(@api_namespace), params: { api_namespace: { name: @api_namespace.name, namespace_type: @api_namespace.namespace_type, properties: @api_namespace.properties.to_json, requires_authentication: @api_namespace.requires_authentication, version: @api_namespace.version } } + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # DESTROY + # API access for all_namespace + test "should destroy if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + assert_difference('ApiNamespace.count', -1) do + delete api_namespace_url(@api_namespace) + end + + assert_redirected_to api_namespaces_url + end + + test "should destroy if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiNamespace.count', -1) do + delete api_namespace_url(@api_namespace) + end + + assert_redirected_to api_namespaces_url + end + + test "should destroy if user has delete_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {delete_access_api_namespace_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiNamespace.count', -1) do + delete api_namespace_url(@api_namespace) + end + + assert_redirected_to api_namespaces_url + end + + test "should not destroy if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + delete api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or delete_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should destroy if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + assert_difference('ApiNamespace.count', -1) do + delete api_namespace_url(@api_namespace) + end + + assert_redirected_to api_namespaces_url + end + + test "should destroy if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiNamespace.count', -1) do + delete api_namespace_url(@api_namespace) + end + + assert_redirected_to api_namespaces_url + end + + test "should destroy if user has category specific delete_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {delete_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiNamespace.count', -1) do + delete api_namespace_url(@api_namespace) + end + + assert_redirected_to api_namespaces_url + end + + test "should not destroy if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + delete api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or delete_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not destroy if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + delete api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or delete_access_api_namespace_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # DISCARD_FAILED_API_ACTIONS + # API access for all_namespace + test "should discard_failed_api_actions if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size", failed_action_counts do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + end + + test "should discard_failed_api_actions if user has full_access_for_api_actions_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size", failed_action_counts do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + end + + test "should not discard_failed_api_actions if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size" do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not discard_failed_api_actions if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size" do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should discard_failed_api_actions if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size", failed_action_counts do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + end + + test "should discard_failed_api_actions if user has category specific full_access_for_api_actions_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size", failed_action_counts do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + end + + test "should not discard_failed_api_actions if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size" do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not discard_failed_api_actions if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size" do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not discard_failed_api_actions if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'discarded').size" do + post discard_failed_api_actions_api_namespace_url(@api_namespace) + end + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # RERUN_FAILED_API_ACTIONS + # API access for all_namespace + test "should rerun_failed_api_actions if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + assert_response :redirect + end + end + + test "should rerun_failed_api_actions if user has full_access_for_api_actions_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_actions_only: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + assert_response :redirect + end + end + + test "should not rerun_failed_api_actions if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not rerun_failed_api_actions if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should rerun_failed_api_actions if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + assert_response :redirect + end + end + + test "should rerun_failed_api_actions if user has category specific full_access_for_api_actions_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_actions_only: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size", -(failed_action_counts) do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + assert_response :redirect + end + end + + test "should not rerun_failed_api_actions if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not rerun_failed_api_actions if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not rerun_failed_api_actions if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + failed_action = api_actions(:two) + failed_action.update(lifecycle_stage: 'failed') + failed_action_counts = @api_namespace.executed_api_actions.where(lifecycle_stage: 'failed').size + + sign_in(@user) + assert_no_difference "@api_namespace.reload.executed_api_actions.where(lifecycle_stage: 'failed').size" do + post rerun_failed_api_actions_api_namespace_url(@api_namespace) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_actions_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # EXPORT + # API access for all_namespace + test "should export if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should export if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should export if user has allow_exports for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {allow_exports: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should not export if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should export if user has category specific full_access for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should export if user has category specific full_access_api_namespace_only for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should export if user has category specific allow_exports for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should export if user has uncategorized access for the namespace with no category" do + api_namespace = api_namespaces(:namespace_with_all_types) + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {allow_exports: 'true'}}}) + + sign_in(@user) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,#{api_namespace.id}\nname,namespace_with_all_types\nslug,namespace_with_all_types\nversion,1\nnull,\narray,\"[\"\"yes\"\", \"\"no\"\"]\"\nnumber,123\nobject,\"{\"\"a\"\"=>\"\"b\"\", \"\"c\"\"=>\"\"d\"\"}\"\nstring,string\nboolean,true\nrequires_authentication,false\nnamespace_type,create-read-update-delete\ncreated_at,#{api_namespace.created_at}\nupdated_at,#{api_namespace.updated_at}\nsocial_share_metadata,\n" + assert_response :success + assert_equal response.body, expected_csv + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_#{DateTime.now.to_i}.csv" + end + + test "should not export if user has category specific other access for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not export if user has other category specific access for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + sign_in(@user) + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + get export_api_namespace_url(api_namespace, format: :csv) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # EXPORT_API_RESOURCES + # API access for all_namespace + test "should export_api_resources if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should export_api_resources if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should export_api_resources if user has allow_exports for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {allow_exports: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should not export_api_resources if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + api_namespace = api_namespaces(:namespace_with_all_types) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "#show: should allow sorting by dynamic columns" do + sign_in(@user) + api_namespace = api_namespaces(:users) + api_namespace.update(properties: { + last_name: "", + first_name: "" + }) + api_namespace.api_resources.create!({ + properties: { + last_name: "Doe", + first_name: "John", + } + }) + + assert_equal api_namespace.api_resources.length, 2 + assert_equal api_namespace.api_resources[0].properties['first_name'], "Don" + assert_equal api_namespace.api_resources[1].properties['first_name'], "John" + + get api_namespace_url(api_namespace), params: {q: { s: "first_name desc" }} + assert_response :success + + assert_select "tbody tr" do |rows| + assert_includes rows[0].to_s, "John" + assert_includes rows[1].to_s, "Don" + end + end + + # API access by category + test "should export_api_resources if user has category specific full_access for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should export_api_resources if user has category specific full_access_api_namespace_only for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + sign_in(@user) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should export_api_resources if user has category specific allow_exports for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_exports: 'true'}}}) + + sign_in(@user) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should export_api_resources if user has uncategorized access for the namespace with no category" do + api_namespace = api_namespaces(:namespace_with_all_types) + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {allow_exports: 'true'}}}) + + sign_in(@user) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + expected_csv = "id,api_namespace_id,null,array,number,object,string,boolean,created_at,updated_at,user_id\n" \ + "#{resource_one.id},#{api_namespace.id},#{resource_one.properties['null']},#{resource_one.properties['array']},#{resource_one.properties['number']},\"{\"\"a\"\"=>\"\"apple\"\"}\",#{resource_one.properties['string']},\"\",#{resource_one.created_at},#{resource_one.updated_at},#{resource_one.user_id}\n" \ + "#{resource_two.id},#{api_namespace.id},#{resource_two.properties['null']},#{resource_two.properties['array']},#{resource_two.properties['number']},\"{\"\"b\"\"=>\"\"ball\"\"}\",#{resource_two.properties['string']},\"\",#{resource_two.created_at},#{resource_two.updated_at},#{resource_one.user_id}\n" + + assert_response :success + assert_equal expected_csv, response.body + assert_equal response.header['Content-Disposition'], "attachment; filename=api_namespace_#{api_namespace.id}_api_resources_#{DateTime.now.to_i}.csv" + end + + test "should not export_api_resources if user has category specific other access for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not export_api_resources if user has other category specific access for the namespace" do + api_namespace = api_namespaces(:namespace_with_all_types) + category = comfy_cms_categories(:api_namespace_1) + api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + sign_in(@user) + resource_one = api_resources(:resource_with_all_types_one) + resource_two = api_resources(:resource_with_all_types_two) + + stubbed_date = DateTime.new(2022, 1, 1) + DateTime.stubs(:now).returns(stubbed_date) + + get export_api_resources_api_namespace_url(api_namespace, format: :csv) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_exports are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # DUPLICATE_WITHOUT_ASSOCIATIONS + # API access for all_namespace + test "should duplicate_without_associations if user has full_access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should duplicate_without_associations if user has full_access_api_namespace_only for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_api_namespace_only: 'true'}}) + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should duplicate_without_associations if user has allow_exports for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should not duplicate_without_associations if user has other access for all_namespaces" do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + @api_namespace.api_form.destroy + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_duplication are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category + test "should duplicate_without_associations if user has category specific full_access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should duplicate_without_associations if user has category specific full_access_api_namespace_only for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_api_namespace_only: 'true'}}}) + + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should duplicate_without_associations if user has category specific allow_exports for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should duplicate_without_associations if user has uncategorized access for the namespace with no category" do + api_namespace = api_namespaces(:namespace_with_all_types) + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {allow_duplication: 'true'}}}) + + @api_namespace.api_form.destroy + + sign_in(@user) + assert_difference('ApiNamespace.count', +1) do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + success_message = "Api namespace was successfully created." + assert_match success_message, request.flash[:notice] + end + + test "should not duplicate_without_associations if user has category specific other access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + @api_namespace.api_form.destroy + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_duplication are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + test "should not duplicate_without_associations if user has other category specific access for the namespace" do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + category_2 = comfy_cms_categories(:api_namespace_2) + @user.update(api_accessibility: {namespaces_by_category: {"#{category_2.label}": {full_access: 'true'}}}) + + @api_namespace.api_form.destroy + + sign_in(@user) + assert_no_difference('ApiNamespace.count') do + assert_no_difference('ApiResource.count') do + assert_no_difference('ApiAction.count') do + assert_no_difference('ApiClient.count') do + assert_no_difference('ExternalApiClient.count') do + assert_no_difference('NonPrimitiveProperty.count') do + post duplicate_without_associations_api_namespace_url(id: @api_namespace.id) + assert_response :redirect + end + end + end + end + end + end + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_duplication are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # SOCIAL SHARE METADATA + # API access for all_namespaces + test 'social_share_metadata# should return success when the user has full_access/full_access_for_api_namespace_only/allow_social_share_metadata for all_namespaces' do + ['full_access', 'full_access_api_namespace_only', 'allow_social_share_metadata'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + @user.update!(api_accessibility: access) + + payload = {api_namespace: {"social_share_metadata"=>{"title"=>"Array", "description"=>"String", "image"=>"picto"}}} + + sign_in(@user) + patch social_share_metadata_api_namespace_url(@api_namespace), params: payload + assert_response :redirect + + expected_message = 'Social Share Metadata successfully updated.' + assert_equal expected_message, flash[:notice] + assert_equal payload[:api_namespace]['social_share_metadata'], @api_namespace.reload.social_share_metadata + end + end + + test 'social_share_metadata# should deny when the user has other access like full_read_access/delete_access_api_namespace_only/allow_exports/allow_duplication/full_access_for_api_resources_only/full_access_for_api_actions_only/full_access_for_external_api_connections_only/full_access_for_api_clients_only/full_access_for_api_form_only for all_namespaces' do + ['full_read_access', 'delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'full_access_for_api_resources_only', 'full_access_for_api_actions_only', 'full_access_for_external_api_connections_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {all_namespaces: {}} + access[:all_namespaces][access_name] = 'true' + @user.update!(api_accessibility: access) + + payload = {api_namespace: {"social_share_metadata"=>{"title"=>"Array", "description"=>"String", "image"=>"picto"}}} + + sign_in(@user) + patch social_share_metadata_api_namespace_url(@api_namespace), params: payload + assert_response :redirect + + expected_message = 'You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_social_share_metadata are allowed to perform that action.' + assert_equal expected_message, flash[:alert] + refute_equal payload[:api_namespace]['social_share_metadata'], @api_namespace.reload.social_share_metadata + end + end + + # API access by category + test 'social_share_metadata# should return success when the user has category-specific full_access/full_access_for_api_namespace_only/allow_social_share_metadata for a namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['full_access', 'full_access_api_namespace_only', 'allow_social_share_metadata'].each do |access_name| + access = {namespaces_by_category: {"#{category.label}": {}}} + access[:namespaces_by_category][:"#{category.label}"][access_name] = 'true' + @user.update!(api_accessibility: access) + + payload = {api_namespace: {"social_share_metadata"=>{"title"=>"Array", "description"=>"String", "image"=>"picto"}}} + + sign_in(@user) + patch social_share_metadata_api_namespace_url(@api_namespace), params: payload + assert_response :redirect + + expected_message = 'Social Share Metadata successfully updated.' + assert_equal expected_message, flash[:notice] + assert_equal payload[:api_namespace]['social_share_metadata'], @api_namespace.reload.social_share_metadata + end + end + + test 'social_share_metadata# should deny when the user has other category-specific access like full_read_access/delete_access_api_namespace_only/allow_exports/allow_duplication/full_access_for_api_resources_only/full_access_for_api_actions_only/full_access_for_external_api_connections_only/full_access_for_api_clients_only/full_access_for_api_form_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['full_read_access', 'delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'full_access_for_api_resources_only', 'full_access_for_api_actions_only', 'full_access_for_external_api_connections_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {"#{category.label}": {}}} + access[:namespaces_by_category][:"#{category.label}"][access_name] = 'true' + @user.update!(api_accessibility: access) + + payload = {api_namespace: {"social_share_metadata"=>{"title"=>"Array", "description"=>"String", "image"=>"picto"}}} + + sign_in(@user) + patch social_share_metadata_api_namespace_url(@api_namespace), params: payload + assert_response :redirect + + expected_message = 'You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_social_share_metadata are allowed to perform that action.' + assert_equal expected_message, flash[:alert] + refute_equal payload[:api_namespace]['social_share_metadata'], @api_namespace.reload.social_share_metadata + end + end + + test 'social_share_metadata# should return success when the user has uncategorized full_access/full_access_for_api_namespace_only/allow_social_share_metadata for a namespace' do + ['full_access', 'full_access_api_namespace_only', 'allow_social_share_metadata'].each do |access_name| + access = {namespaces_by_category: {uncategorized: {}}} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + @user.update!(api_accessibility: access) + + payload = {api_namespace: {"social_share_metadata"=>{"title"=>"Array", "description"=>"String", "image"=>"picto"}}} + + sign_in(@user) + patch social_share_metadata_api_namespace_url(@api_namespace), params: payload + assert_response :redirect + + expected_message = 'Social Share Metadata successfully updated.' + assert_equal expected_message, flash[:notice] + assert_equal payload[:api_namespace]['social_share_metadata'], @api_namespace.reload.social_share_metadata + end + end + + test 'social_share_metadata# should deny when the user has other uncategorized access like full_read_access/delete_access_api_namespace_only/allow_exports/allow_duplication/full_access_for_api_resources_only/full_access_for_api_actions_only/full_access_for_external_api_connections_only/full_access_for_api_clients_only/full_access_for_api_form_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + + ['full_read_access', 'delete_access_api_namespace_only', 'allow_exports', 'allow_duplication', 'full_access_for_api_resources_only', 'full_access_for_api_actions_only', 'full_access_for_external_api_connections_only', 'full_access_for_api_clients_only', 'full_access_for_api_form_only'].each do |access_name| + access = {namespaces_by_category: {uncategorized: {}}} + access[:namespaces_by_category][:uncategorized][access_name] = 'true' + @user.update!(api_accessibility: access) + + payload = {api_namespace: {"social_share_metadata"=>{"title"=>"Array", "description"=>"String", "image"=>"picto"}}} + + sign_in(@user) + patch social_share_metadata_api_namespace_url(@api_namespace), params: payload + assert_response :redirect + + expected_message = 'You do not have the permission to do that. Only users with full_access or full_access_api_namespace_only or allow_social_share_metadata are allowed to perform that action.' + assert_equal expected_message, flash[:alert] + refute_equal payload[:api_namespace]['social_share_metadata'], @api_namespace.reload.social_share_metadata end end diff --git a/test/controllers/admin/comfy/api_resources_controller_test.rb b/test/controllers/admin/comfy/api_resources_controller_test.rb index b8875c8b1..db05b70c7 100755 --- a/test/controllers/admin/comfy/api_resources_controller_test.rb +++ b/test/controllers/admin/comfy/api_resources_controller_test.rb @@ -3,7 +3,7 @@ class Comfy::Admin::ApiResourcesControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) @api_namespace = api_namespaces(:one) @api_resource = api_resources(:one) @@ -16,6 +16,14 @@ class Comfy::Admin::ApiResourcesControllerTest < ActionDispatch::IntegrationTest assert_response :success end + test "deny new if not permissioned" do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + assert_equal "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action.", flash[:alert] + end + test "should create api_resource" do sign_in(@user) payload_as_stringified_json = "{\"age\":26,\"alive\":true,\"last_name\":\"Teng\",\"first_name\":\"Jennifer\"}" @@ -102,4 +110,442 @@ class Comfy::Admin::ApiResourcesControllerTest < ActionDispatch::IntegrationTest end assert_redirected_to api_namespace_url(id: @api_namespace.id) end + + # SHOW + # API access for all namespaces + test 'should get show if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has full_access_for_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has read_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_resources_only: 'true'}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should not get show if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_resources_only or read_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get show if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has full_access_for_api_resources_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has read_api_resources_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_resources_only: 'true'}}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get show if user has read_api_resources_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_api_resources_only: 'true'}}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should not get show if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_api_resources_only or read_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # NEW + # API access for all_namespaces + test 'should get new if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has full_access_for_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get new if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_resources_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get new if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has full_access_for_api_resources_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has read_api_resources_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get new if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_resources_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_resource_url(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # EDIT + # API access for all_namespaces + test 'should get edit if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get edit if user has full_access_for_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should not get edit if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_resources_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get edit if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get edit if user has full_access_for_api_resources_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should get edit if user has read_api_resources_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :success + end + + test 'should not get edit if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_resources_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_namespace.api_resources.sample.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # UPDATE + # API access for all_namespaces + test 'should get update if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_redirected_to edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) + end + + test 'should get update if user has full_access_for_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_redirected_to edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) + end + + test 'should not get update if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_resources_only: 'true'}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get update if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_redirected_to edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) + end + + test 'should get update if user has full_access_for_api_resources_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_redirected_to edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) + end + + test 'should get update if user has read_api_resources_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_redirected_to edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) + end + + test 'should not get update if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_resources_only: 'true'}}}) + + sign_in(@user) + perform_enqueued_jobs do + patch api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id), params: { api_resource: { properties: @api_resource.properties } }, headers: { 'HTTP_REFERER': edit_api_namespace_resource_url(api_namespace_id: @api_namespace.id, id: @api_resource.id) } + Sidekiq::Worker.drain_all + end + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # DESTROY + # API access for all_namespaces + test 'should destroy if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + assert_difference('ApiResource.count', -1) do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + assert_redirected_to api_namespace_url(id: @api_namespace.id) + end + + test 'should destroy if user has full_access_for_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiResource.count', -1) do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + assert_redirected_to api_namespace_url(id: @api_namespace.id) + end + + test 'should destroy if user has delete_access_for_api_resources_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {delete_access_for_api_resources_only: 'true'}}) + + sign_in(@user) + assert_difference('ApiResource.count', -1) do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + assert_redirected_to api_namespace_url(id: @api_namespace.id) + end + + test 'should not destroy if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_api_resources_only: 'true'}}) + + sign_in(@user) + assert_no_difference('ApiResource.count') do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only or delete_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should destroy if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + assert_difference('ApiResource.count', -1) do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + assert_redirected_to api_namespace_url(id: @api_namespace.id) + end + + test 'should destroy if user has full_access_for_api_resources_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiResource.count', -1) do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + assert_redirected_to api_namespace_url(id: @api_namespace.id) + end + + test 'should destroy if user has delete_access_for_api_resources_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {delete_access_for_api_resources_only: 'true'}}}) + + sign_in(@user) + assert_difference('ApiResource.count', -1) do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + assert_redirected_to api_namespace_url(id: @api_namespace.id) + end + + test 'should not destroy if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_api_resources_only: 'true'}}}) + + sign_in(@user) + assert_no_difference('ApiResource.count') do + delete api_namespace_resource_url(@api_resource, api_namespace_id: @api_resource.api_namespace_id) + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_api_resources_only or delete_access_for_api_resources_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end end diff --git a/test/controllers/admin/comfy/external_api_clients_controller_test.rb b/test/controllers/admin/comfy/external_api_clients_controller_test.rb index 971ee8ece..c45b2478d 100644 --- a/test/controllers/admin/comfy/external_api_clients_controller_test.rb +++ b/test/controllers/admin/comfy/external_api_clients_controller_test.rb @@ -4,7 +4,7 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) @api_client = api_clients(:one) @api_namespace = api_namespaces(:one) @external_api_client = external_api_clients(:test) @@ -63,7 +63,7 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati end test "should not get #index, if signed in but not allowed to manage api" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) assert_response :redirect @@ -84,18 +84,17 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati end test "#new: denies if user not permissioned to manage api" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_response :redirect assert_match expected_message, flash[:alert] end test "#new: allows if permissioned user is signed in" do - @user.update(can_manage_api: true) sign_in(@user) get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) @@ -128,7 +127,6 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati } } - @user.update(can_manage_api: true) sign_in(@user) assert_difference "ExternalApiClient.count", +1 do @@ -191,14 +189,14 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati } } - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) assert_no_difference "ExternalApiClient.count" do post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload end - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_match expected_message, flash[:alert] assert_response :redirect end @@ -212,18 +210,17 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati end test "#show: denies if user not permissioned to manage api" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_external_api_connections_only or read_external_api_connections_only are allowed to perform that action." assert_response :redirect - assert_match expected_message, flash[:alert] + assert_equal expected_message, flash[:alert] end test "#show: allows if permissioned user is signed in" do - @user.update(can_manage_api: true) sign_in(@user) get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) @@ -240,18 +237,17 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati end test "#edit: denies if user not permissioned to manage api" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_response :redirect assert_match expected_message, flash[:alert] end test "#edit: allows if permissioned user is signed in" do - @user.update(can_manage_api: true) sign_in(@user) get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) @@ -284,7 +280,6 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati } } - @user.update(can_manage_api: true) sign_in(@user) patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload @@ -343,12 +338,12 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati } } - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_match expected_message, flash[:alert] assert_response :redirect end @@ -361,25 +356,26 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati expected_message = "You need to sign in or sign up before continuing." assert_response :redirect + assert_redirected_to new_user_session_path assert_match expected_message, flash[:alert] end test "#destroy: denies if user not permissioned to manage api" do - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) assert_no_difference "ExternalApiClient.count" do delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) end - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_response :redirect + assert_redirected_to root_path assert_match expected_message, flash[:alert] end test "#destroy: allows if permissioned user is signed in" do - @user.update(can_manage_api: true) sign_in(@user) assert_difference "ExternalApiClient.count", -1 do @@ -389,6 +385,7 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati expected_message = "Api client was successfully destroyed." assert_response :redirect + assert_redirected_to api_namespace_external_api_clients_path assert_match expected_message, flash[:notice] end @@ -407,12 +404,12 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati test "#stop: denies if user not permissioned to manage api" do @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_response :redirect assert_match expected_message, flash[:alert] @@ -422,7 +419,6 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati test "#stop: allows if permissioned user is signed in" do @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) - @user.update(can_manage_api: true) sign_in(@user) get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) @@ -449,12 +445,12 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati test "#clear_errors: denies if user not permissioned to manage api" do @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_response :redirect assert_match expected_message, flash[:alert] @@ -467,7 +463,6 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati test "#clear_errors: allows if permissioned user is signed in" do @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) - @user.update(can_manage_api: true) sign_in(@user) get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) @@ -494,12 +489,12 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati test "#clear_state: denies if user not permissioned to manage api" do @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) - @user.update(can_manage_api: false) + @user.update(api_accessibility: {}) sign_in(@user) get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) - expected_message = "You do not have the permission to do that. Only users who can_manage_api are allowed to perform that action." + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." assert_response :redirect assert_match expected_message, flash[:alert] @@ -509,7 +504,6 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati test "#clear_state: allows if permissioned user is signed in" do @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) - @user.update(can_manage_api: true) sign_in(@user) get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) @@ -590,4 +584,1418 @@ class Comfy::Admin::ExternalApiClientsControllerTest < ActionDispatch::Integrati assert_match expected_message, vacuum_job_plugin.reload.error_message assert_response :redirect end + + # SHOW + # API access for all namespaces + test 'should get show if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has read_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should not get show if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_external_api_connections_only or read_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get show if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has read_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should get show if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :success + end + + test 'should not get show if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_external_api_connections_only or read_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # INDEX + # API access for all namespaces + test 'should get index if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_read_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_read_access: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has read_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get index if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {allow_duplication: 'true'}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_external_api_connections_only or read_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get index if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_read_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_read_access: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has read_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get index if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get index if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {allow_duplication: 'true'}}}) + + sign_in(@user) + get api_namespace_external_api_clients_path(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_read_access or full_access_for_external_api_connections_only or read_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # NEW + # API access for all_namespaces + test 'should get new if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get new if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get new if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should get new if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :success + end + + test 'should not get new if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get new_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # EDIT + # API access for all_namespaces + test 'should get edit if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :success + end + + test 'should get edit if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :success + end + + test 'should not get edit if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get edit if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :success + end + + test 'should get edit if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :success + end + + test 'should get edit if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :success + end + + test 'should not get edit if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + get edit_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # CREATE + # API access for all_namespaces + test 'should get create if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_difference "ExternalApiClient.count", +1 do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + + expected_message = "Api client was successfully created." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should get create if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_difference "ExternalApiClient.count", +1 do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + + expected_message = "Api client was successfully created." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should not get create if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_no_difference "ExternalApiClient.count" do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get create if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_difference "ExternalApiClient.count", +1 do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + + expected_message = "Api client was successfully created." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should get create if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_difference "ExternalApiClient.count", +1 do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + + expected_message = "Api client was successfully created." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should get create if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_difference "ExternalApiClient.count", +1 do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + + expected_message = "Api client was successfully created." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should not get create if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Create Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + assert_no_difference "ExternalApiClient.count" do + post api_namespace_external_api_clients_url(api_namespace_id: @api_namespace.id), params: payload + end + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # UPDATE + # API access for all_namespaces + test 'should get update if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + expected_message = "Api client was successfully updated." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should get update if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + expected_message = "Api client was successfully updated." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should not get update if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should get update if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + expected_message = "Api client was successfully updated." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should get update if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + expected_message = "Api client was successfully updated." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should get update if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + expected_message = "Api client was successfully updated." + assert_match expected_message, flash[:notice] + assert_response :redirect + end + + test 'should not get update if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + payload = { + external_api_client: { + api_namespace_id: @api_namespace.id, + label: 'Update Test API', + enabled: true, + metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + state_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + error_metadata: { + "api_key": "x-api-key-foo", + "bearer_token": "foo", + "test_object": {'a': 'test string', 'b': [1,2,3]} + }.to_json, + model_definition: "class ExternalApiModelExample; def initialize(parameters); # do init stuff; end; def start; return true; end; def log; return true; end; end; # at the end of the file we have to implicitly return the class; ExternalApiModelExample;" + } + } + + sign_in(@user) + + patch api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id), params: payload + + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # DESTROY + # API access for all_namespaces + test 'should destroy if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + + assert_difference "ExternalApiClient.count", -1 do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + + expected_message = "Api client was successfully destroyed." + + assert_response :redirect + assert_match expected_message, flash[:notice] + end + + test 'should destroy if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + sign_in(@user) + + assert_difference "ExternalApiClient.count", -1 do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + + expected_message = "Api client was successfully destroyed." + + assert_response :redirect + assert_match expected_message, flash[:notice] + end + + test 'should not destroy if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + sign_in(@user) + + assert_no_difference "ExternalApiClient.count" do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should destroy if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + + assert_difference "ExternalApiClient.count", -1 do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + + expected_message = "Api client was successfully destroyed." + + assert_response :redirect + assert_match expected_message, flash[:notice] + end + + test 'should destroy if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + + assert_difference "ExternalApiClient.count", -1 do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + + expected_message = "Api client was successfully destroyed." + + assert_response :redirect + assert_match expected_message, flash[:notice] + end + + test 'should destroy if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + + assert_difference "ExternalApiClient.count", -1 do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + + expected_message = "Api client was successfully destroyed." + + assert_response :redirect + assert_match expected_message, flash[:notice] + end + + test 'should not destroy if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + + assert_no_difference "ExternalApiClient.count" do + delete api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + end + assert_response :redirect + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # START + # API access for all_namespaces + test 'should start if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + end + + test 'should start if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + end + + test 'should not start if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should start if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + end + + test 'should start if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + end + + test 'should start if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + end + + test 'should not start if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + + sign_in(@user) + @external_api_client.update(status: ExternalApiClient::STATUSES[:stopped], enabled: true) + get start_api_namespace_external_api_client_path(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_empty ExternalApiClientJob.jobs + Sidekiq::Worker.drain_all + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # STOP + # API access for all_namespaces + test 'should stop if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + end + + test 'should stop if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + end + + test 'should not stop if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should stop if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + end + + test 'should stop if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + end + + test 'should stop if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + end + + test 'should not stop if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:running]) + + sign_in(@user) + get stop_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + assert_response :redirect + assert_not_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # CLEAR_ERRORS + # API access for all_namespaces + test 'should clear_errors if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + assert_equal 0, @external_api_client.reload.retries + refute @external_api_client.reload.error_message + refute @external_api_client.reload.error_metadata + end + + test 'should clear_errors if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + assert_equal 0, @external_api_client.reload.retries + refute @external_api_client.reload.error_message + refute @external_api_client.reload.error_metadata + end + + test 'should not clear_errors if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:error], @external_api_client.reload.status + assert_equal 3, @external_api_client.reload.retries + assert @external_api_client.reload.error_message + assert @external_api_client.reload.error_metadata + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should clear_errors if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + assert_equal 0, @external_api_client.reload.retries + refute @external_api_client.reload.error_message + refute @external_api_client.reload.error_metadata + end + + test 'should clear_errors if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + assert_equal 0, @external_api_client.reload.retries + refute @external_api_client.reload.error_message + refute @external_api_client.reload.error_metadata + end + + test 'should clear_errors if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:stopped], @external_api_client.reload.status + assert_equal 0, @external_api_client.reload.retries + refute @external_api_client.reload.error_message + refute @external_api_client.reload.error_metadata + end + + test 'should not clear_errors if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + @external_api_client.update(status: ExternalApiClient::STATUSES[:error], error_message: 'test error message', retries: 3, error_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_errors_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert_equal ExternalApiClient::STATUSES[:error], @external_api_client.reload.status + assert_equal 3, @external_api_client.reload.retries + assert @external_api_client.reload.error_message + assert @external_api_client.reload.error_metadata + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # CLEAR_STATE + # API access for all_namespaces + test 'should clear_state if user has full_access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + refute @external_api_client.reload.state_metadata + end + + test 'should clear_state if user has full_access_for_external_api_connections_only for all namespace' do + @user.update(api_accessibility: {all_namespaces: {full_access_for_external_api_connections_only: 'true'}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + refute @external_api_client.reload.state_metadata + end + + test 'should not clear_state if user has other access for all namespace' do + @user.update(api_accessibility: {all_namespaces: {read_external_api_connections_only: 'true'}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert @external_api_client.reload.state_metadata + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end + + # API access by category wise + test 'should clear_state if user has full_access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access: 'true'}}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + refute @external_api_client.reload.state_metadata + end + + test 'should clear_state if user has full_access_for_external_api_connections_only for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {full_access_for_external_api_connections_only: 'true'}}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + refute @external_api_client.reload.state_metadata + end + + test 'should clear_state if user has read_external_api_connections_only for the uncategorized namespace' do + @user.update(api_accessibility: {namespaces_by_category: {uncategorized: {full_access_for_external_api_connections_only: 'true'}}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + refute @external_api_client.reload.state_metadata + end + + test 'should not clear_state if user has other access for the namespace' do + category = comfy_cms_categories(:api_namespace_1) + @api_namespace.update(category_ids: [category.id]) + @user.update(api_accessibility: {namespaces_by_category: {"#{category.label}": {read_external_api_connections_only: 'true'}}}) + @external_api_client.update(state_metadata: { 'testKey': 'testMessage'}) + + sign_in(@user) + + get clear_state_api_namespace_external_api_client_url(api_namespace_id: @api_namespace.id, id: @external_api_client.id) + + assert_response :redirect + assert @external_api_client.reload.state_metadata + + expected_message = "You do not have the permission to do that. Only users with full_access or full_access_for_external_api_connections_only are allowed to perform that action." + assert_equal expected_message, flash[:alert] + end end diff --git a/test/controllers/admin/comfy/users_controller_test.rb b/test/controllers/admin/comfy/users_controller_test.rb index ce388a365..3ae00ff89 100644 --- a/test/controllers/admin/comfy/users_controller_test.rb +++ b/test/controllers/admin/comfy/users_controller_test.rb @@ -37,7 +37,7 @@ class Comfy::Admin::UsersControllerTest < ActionDispatch::IntegrationTest "Can manage email", "Can manage users", "Can manage blog", - "Can manage api", + "Api accessibility", "Can manage app settings", "Can view restricted pages", "Can manage forum", diff --git a/test/controllers/users/sessions_controller_test.rb b/test/controllers/users/sessions_controller_test.rb index f0f6e027f..9d33e9be4 100644 --- a/test/controllers/users/sessions_controller_test.rb +++ b/test/controllers/users/sessions_controller_test.rb @@ -218,14 +218,14 @@ class Users::SessionsControllerTest < ActionDispatch::IntegrationTest post user_session_url(subdomain: @restarone_subdomain.name), params: payload assert_redirected_to api_namespace_url(subdomain: @restarone_subdomain.name, id: api_namespace.id) - # The response will be success if the user can manage api - @restarone_user.update!(can_manage_api: true) + # The response will be success if the user is properly permissioned + @restarone_user.update!(api_accessibility: {all_namespaces: {full_access: 'true'}}) sign_in(@restarone_user) get api_namespace_url(subdomain: @restarone_subdomain.name, id: api_namespace.id) assert_response :success - # The response will be redirected to root_url if the user cannot manage api - @restarone_user.update!(can_manage_api: false) + # The response will be redirected to root_url if the user is not permissioned + @restarone_user.update!(api_accessibility: {}) sign_in(@restarone_user) get api_namespace_url(subdomain: @restarone_subdomain.name, id: api_namespace.id) assert_redirected_to root_url(subdomain: @restarone_subdomain.name) diff --git a/test/helpers/api_accessibility_helper_test.rb b/test/helpers/api_accessibility_helper_test.rb new file mode 100644 index 000000000..42a1b3514 --- /dev/null +++ b/test/helpers/api_accessibility_helper_test.rb @@ -0,0 +1,35 @@ +require 'test_helper' + +class ApiAccessibilityHelperTest < ActionView::TestCase + setup do + @user = users(:public) + end + + test 'should return true/false accordingly if the user has/has not some access in the provided category' do + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) + + assert has_access_to_main_category?(@user.api_accessibility, 'all_namespaces') + refute has_access_to_main_category?(@user.api_accessibility, 'namespaces_by_category') + end + + test 'should return true/false accordingly if the user has/has not some access in the specific category' do + @user.update(api_accessibility: {namespaces_by_category: {test_1: {full_access: 'true'}}}) + + assert has_access_to_specific_category?(@user.api_accessibility, 'test_1') + refute has_access_to_specific_category?(@user.api_accessibility, 'test_2') + end + + test 'should return true/false accordingly if the user has/has not some sub-access in the specific category' do + @user.update(api_accessibility: {namespaces_by_category: {test_1: {full_access: 'true'}}}) + + assert has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'test_1') + refute has_sub_access_to_specific_category?(@user.api_accessibility, 'full_access', 'namespaces_by_category', 'test_2') + end + + test 'should return true/false accordingly if the user has no any sub-access in the specific category' do + @user.update(api_accessibility: {namespaces_by_category: {test_1: {full_access: 'true'}, test_2: {}}}) + + assert has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'test_1') + refute has_no_sub_access_to_specific_category?(@user.api_accessibility, 'namespaces_by_category', 'test_2') + end +end diff --git a/test/plugins/bishop_monitoring_plugin_test.rb b/test/plugins/bishop_monitoring_plugin_test.rb index 826f0c324..18dadb221 100644 --- a/test/plugins/bishop_monitoring_plugin_test.rb +++ b/test/plugins/bishop_monitoring_plugin_test.rb @@ -3,7 +3,7 @@ class BishopMonitoringPluginTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) end test "#BishopMonitoring: sends HTTP request and does not log incident (resource creation + email) if HTTP endpoint error does not occur" do diff --git a/test/plugins/bishop_tls_monitoring_plugin_test.rb b/test/plugins/bishop_tls_monitoring_plugin_test.rb index bfc24e63e..faa5c8317 100644 --- a/test/plugins/bishop_tls_monitoring_plugin_test.rb +++ b/test/plugins/bishop_tls_monitoring_plugin_test.rb @@ -3,7 +3,7 @@ class BishopTlsMonitoringPluginTest < ActionDispatch::IntegrationTest setup do @user = users(:public) - @user.update(can_manage_api: true) + @user.update(api_accessibility: {all_namespaces: {full_access: 'true'}}) WebMock.allow_net_connect!(net_http_connect_on_start: true) end