mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
[#55382] add connection validation section
- https://community.openproject.org/work_packages/55382 - added new controller for connection validation - added new component to sidebar
This commit is contained in:
@@ -210,6 +210,7 @@ gem "validate_url"
|
||||
|
||||
# Storages support code
|
||||
gem "dry-container"
|
||||
gem "dry-monads"
|
||||
|
||||
# ActiveRecord extension which adds typecasting to store accessors
|
||||
gem "store_attribute", "~> 1.0"
|
||||
|
||||
@@ -476,6 +476,10 @@ GEM
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 1.0, < 2)
|
||||
zeitwerk (~> 2.6)
|
||||
dry-monads (1.6.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
dry-core (~> 1.0, < 2)
|
||||
zeitwerk (~> 2.6)
|
||||
dry-types (1.7.2)
|
||||
bigdecimal (~> 3.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
@@ -1195,6 +1199,7 @@ DEPENDENCIES
|
||||
doorkeeper (~> 5.7.0)
|
||||
dotenv-rails
|
||||
dry-container
|
||||
dry-monads
|
||||
email_validator (~> 2.2.3)
|
||||
equivalent-xml (~> 0.6)
|
||||
erb_lint
|
||||
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
<%#-- copyright
|
||||
OpenProject is an open source project management software.
|
||||
Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 3.
|
||||
|
||||
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
Copyright (C) 2010-2013 the ChiliProject Team
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
++#%>
|
||||
|
||||
<%=
|
||||
component_wrapper do
|
||||
flex_layout do |container|
|
||||
container.with_row do
|
||||
flex_layout do |heading|
|
||||
heading.with_row do
|
||||
render(Primer::Beta::Heading.new(tag: :h4)) { I18n.t("storages.connection_validation.title") }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
container.with_row(mt: 2) do
|
||||
primer_form_with(
|
||||
model: @storage,
|
||||
url: validate_connection_admin_settings_storage_connection_validation_path(@storage),
|
||||
method: :post,
|
||||
data: { turbo: true }
|
||||
) do
|
||||
flex_layout do |form|
|
||||
form.with_row do
|
||||
render(OpTurbo::FrameComponent.new(id: :connection_validation_result))
|
||||
end
|
||||
|
||||
form.with_row(mt: 2) do
|
||||
render(Primer::Beta::Button.new(
|
||||
scheme: :default,
|
||||
block: :true,
|
||||
type: :submit,
|
||||
)) do |button|
|
||||
button.with_leading_visual_icon(icon: "tasklist")
|
||||
I18n.t("storages.connection_validation.action")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
%>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Storages
|
||||
module Admin
|
||||
module Sidebar
|
||||
class ConnectionValidationComponent < ApplicationComponent # rubocop:disable OpenProject/AddPreviewForViewComponent
|
||||
include OpTurbo::Streamable
|
||||
include OpPrimer::ComponentHelpers
|
||||
|
||||
def initialize(storage:)
|
||||
super(storage)
|
||||
@storage = storage
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,7 @@
|
||||
<%=
|
||||
component_wrapper do
|
||||
render(Primer::OpenProject::BorderGrid.new) do |border_grid|
|
||||
border_grid.with_row { render(Storages::Admin::Sidebar::ConnectionValidationComponent.new(storage: @storage)) }
|
||||
border_grid.with_row { render(Storages::Admin::Sidebar::HealthStatusComponent.new(storage: @storage)) }
|
||||
border_grid.with_row { render(Storages::Admin::Sidebar::HealthNotificationsComponent.new(storage: @storage)) }
|
||||
end
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Storages
|
||||
module Admin
|
||||
class ConnectionValidationController < ApplicationController
|
||||
include OpTurbo::ComponentStream
|
||||
include Dry::Monads[:maybe]
|
||||
|
||||
using Peripherals::ServiceResultRefinements
|
||||
|
||||
layout "admin"
|
||||
|
||||
before_action :require_admin
|
||||
|
||||
model_object OneDriveStorage
|
||||
|
||||
before_action :find_model_object, only: %i[validate_connection]
|
||||
|
||||
def validate_connection
|
||||
@result = maybe_is_not_configured
|
||||
.or { drive_id_wrong }
|
||||
.or { tenant_id_wrong }
|
||||
.or { client_id_wrong }
|
||||
.or { client_secret_wrong }
|
||||
.or { request_failed_with_unknown_error }
|
||||
.value_or(ConnectionValidation.new(icon: "check-circle",
|
||||
scheme: :success,
|
||||
description: I18n.t("storages.connection_validation.success")))
|
||||
|
||||
respond_to do |format|
|
||||
format.turbo_stream
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def query
|
||||
@query ||= Peripherals::Registry
|
||||
.resolve("#{@storage.short_provider_type}.queries.files")
|
||||
.call(storage: @storage, auth_strategy:, folder: root_folder)
|
||||
end
|
||||
|
||||
def maybe_is_not_configured
|
||||
return None() if @storage.configured?
|
||||
|
||||
Some(ConnectionValidation.new(icon: :alert,
|
||||
scheme: :warning,
|
||||
description: I18n.t("storages.connection_validation.not_configured")))
|
||||
end
|
||||
|
||||
def drive_id_wrong
|
||||
return None() if query.result != :not_found
|
||||
|
||||
Some(ConnectionValidation.new(icon: :skip,
|
||||
scheme: :danger,
|
||||
description: I18n.t("storages.connection_validation.drive_id_wrong")))
|
||||
end
|
||||
|
||||
def tenant_id_wrong
|
||||
return None() if query.result != :unauthorized
|
||||
|
||||
payload = JSON.parse(query.error_payload)
|
||||
return None() if payload["error"] != "invalid_request"
|
||||
|
||||
tenant_id_string = "Tenant '#{@storage.tenant_id}' not found."
|
||||
return None() unless payload["error_description"].include?(tenant_id_string)
|
||||
|
||||
Some(ConnectionValidation.new(icon: :skip,
|
||||
scheme: :danger,
|
||||
description: I18n.t("storages.connection_validation.tenant_id_wrong")))
|
||||
end
|
||||
|
||||
def client_id_wrong
|
||||
return None() if query.result != :unauthorized
|
||||
|
||||
payload = JSON.parse(query.error_payload)
|
||||
return None() if payload["error"] != "unauthorized_client"
|
||||
|
||||
Some(ConnectionValidation.new(icon: :skip,
|
||||
scheme: :danger,
|
||||
description: I18n.t("storages.connection_validation.client_id_wrong")))
|
||||
end
|
||||
|
||||
def client_secret_wrong
|
||||
return None() if query.result != :unauthorized
|
||||
|
||||
payload = JSON.parse(query.error_payload)
|
||||
return None() if payload["error"] != "invalid_client"
|
||||
|
||||
Some(ConnectionValidation.new(icon: :skip,
|
||||
scheme: :danger,
|
||||
description: I18n.t("storages.connection_validation.client_secret_wrong")))
|
||||
end
|
||||
|
||||
def request_failed_with_unknown_error
|
||||
return None() if query.success?
|
||||
|
||||
Rails.logger.error("Connection validation failed with unknown error:\n\t" \
|
||||
"status: #{query.result}\n\tresponse: #{query.error_payload}")
|
||||
|
||||
Some(ConnectionValidation.new(icon: :skip,
|
||||
scheme: :danger,
|
||||
description: I18n.t("storages.connection_validation.unknown_error")))
|
||||
end
|
||||
|
||||
def find_model_object(object_id = :storage_id)
|
||||
super
|
||||
@storage = @object
|
||||
end
|
||||
|
||||
def root_folder
|
||||
Peripherals::ParentFolder.new("/")
|
||||
end
|
||||
|
||||
def auth_strategy
|
||||
Peripherals::Registry.resolve("#{@storage.short_provider_type}.authentication.userless").call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,33 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module Storages
|
||||
ConnectionValidation = Data.define(:icon, :scheme, :description)
|
||||
end
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
<%#-- copyright
|
||||
OpenProject is an open source project management software.
|
||||
Copyright (C) 2012-2024 the OpenProject GmbH
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License version 3.
|
||||
|
||||
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
Copyright (C) 2010-2013 the ChiliProject Team
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
++#%>
|
||||
|
||||
<%= turbo_stream.update :connection_validation_result do %>
|
||||
<%= render(Primer::Alpha::Banner.new(icon: @result.icon, scheme: @result.scheme)) { @result.description } %>
|
||||
<% end %>
|
||||
@@ -116,6 +116,16 @@ en:
|
||||
subscribe: Subscribe
|
||||
title: Email notifications
|
||||
unsubscribe: Unsubscribe
|
||||
connection_validation:
|
||||
title: Connection validation
|
||||
action: Validate connection
|
||||
not_configured: The connection could not be validated. Please finish configuration first.
|
||||
drive_id_wrong: The configured drive id could not be found. Please check the configuration.
|
||||
tenant_id_wrong: The configured directory (tenant) id is invalid. Please check the configuration.
|
||||
client_id_wrong: The configured OAuth 2 client id is invalid. Please check the configuration.
|
||||
client_secret_wrong: The configured OAuth 2 client secret is invalid. Please check the configuration.
|
||||
unknown_error: The connection could not be validated. An unknown error occurred. Please check the server logs for further information.
|
||||
success: The connection works as expected.
|
||||
help_texts:
|
||||
project_folder: The project folder is the default folder for file uploads for this project. Users can nevertheless still upload files to other locations.
|
||||
instructions:
|
||||
|
||||
@@ -38,11 +38,18 @@ Rails.application.routes.draw do
|
||||
post :finish_setup
|
||||
end
|
||||
|
||||
resource :automatically_managed_project_folders, controller: "/storages/admin/automatically_managed_project_folders",
|
||||
only: %i[new create edit update]
|
||||
resource :automatically_managed_project_folders,
|
||||
controller: "/storages/admin/automatically_managed_project_folders",
|
||||
only: %i[new create edit update]
|
||||
|
||||
resource :access_management, controller: "/storages/admin/access_management", only: %i[new create edit update]
|
||||
|
||||
resource :connection_validation,
|
||||
controller: "/storages/admin/connection_validation",
|
||||
only: [] do
|
||||
post :validate_connection, on: :member
|
||||
end
|
||||
|
||||
get :select_provider, on: :collection
|
||||
|
||||
member do
|
||||
|
||||
Reference in New Issue
Block a user