opf/openproject

View on GitHub
modules/bim/lib/open_project/bim/engine.rb

Summary

Maintainability
A
0 mins
Test Coverage
#-- 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.
#++

require "open_project/plugins"

module OpenProject::Bim
  class Engine < ::Rails::Engine
    engine_name :openproject_bim

    include OpenProject::Plugins::ActsAsOpEngine

    register "openproject-bim",
             author_url: "https://www.openproject.org",
             bundled: true,
             settings: {
               default: {}
             } do
      project_module(:bim,
                     dependencies: :work_package_tracking,
                     if: ->(*) { OpenProject::Configuration.bim? }) do
        permission :view_ifc_models,
                   {
                     "bim/ifc_models/ifc_models": %i[index show defaults],
                     "bim/ifc_models/ifc_viewer": %i[show]
                   },
                   permissible_on: :project,
                   contract_actions: { ifc_models: %i[read] }
        permission :manage_ifc_models,
                   { "bim/ifc_models/ifc_models": %i[index show destroy edit update create new] },
                   permissible_on: :project,
                   dependencies: %i[view_ifc_models],
                   contract_actions: { ifc_models: %i[create update destroy] }
        permission :view_linked_issues,
                   { "bim/bcf/issues": %i[index] },
                   permissible_on: :project,
                   dependencies: %i[view_work_packages],
                   contract_actions: { bcf: %i[read] }
        permission :manage_bcf,
                   { "bim/bcf/issues": %i[index upload prepare_import configure_import perform_import] },
                   permissible_on: :project,
                   dependencies: %i[view_linked_issues
                                    view_work_packages
                                    add_work_packages
                                    edit_work_packages],
                   contract_actions: { bcf: %i[create update] }
        permission :delete_bcf,
                   {},
                   permissible_on: :project,
                   dependencies: %i[view_linked_issues
                                    manage_bcf
                                    view_work_packages
                                    add_work_packages
                                    edit_work_packages
                                    delete_work_packages],
                   contract_actions: { bcf: %i[destroy] }
        permission :save_bcf_queries,
                   {},
                   permissible_on: :project,
                   dependencies: %i[save_queries]
        permission :manage_public_bcf_queries,
                   {},
                   permissible_on: :project,
                   dependencies: %i[manage_public_queries save_bcf_queries]
      end

      Rails.application.reloader.to_prepare do
        OpenProject::AccessControl
          .permission(:view_work_packages)
          .controller_actions << "bim/bcf/issues/redirect_to_bcf_issues_list"
      end

      ::Redmine::MenuManager.map(:project_menu) do |menu|
        menu.push(:ifc_models,
                  { controller: "/bim/ifc_models/ifc_models", action: "defaults" },
                  caption: :"bcf.label_bcf",
                  after: :work_packages,
                  icon: "bcf",
                  badge: :label_new)

        menu.push :ifc_viewer_panels,
                  { controller: "/bim/ifc_models/ifc_models", action: "defaults" },
                  parent: :ifc_models,
                  partial: "/bim/ifc_models/ifc_models/panels"
      end
    end

    class_inflection_override("v2_1" => "V2_1")

    assets %w(bim/logo_openproject_bim_big.png bim/logo_openproject_bim_big_coloured.png)

    patches %i[Attachment WorkPackage Type Journal RootSeeder Project FogFileUploader]

    patch_with_namespace :OpenProject, :CustomStyles, :ColorThemes
    patch_with_namespace :API, :V3, :Activities, :ActivityRepresenter
    patch_with_namespace :API, :V3, :WorkPackages, :EagerLoading, :Checksum

    patch_with_namespace :DemoData, :QueryBuilder
    patch_with_namespace :DemoData, :ProjectSeeder
    patch_with_namespace :DemoData, :WorkPackageSeeder
    patch_with_namespace :DemoData, :WorkPackageBoardSeeder

    extend_api_response(:v3, :work_packages, :work_package) do
      include API::Bim::Utilities::PathHelper

      link :bcfTopic,
           cache_if: -> { current_user.allowed_in_project?(:view_linked_issues, represented.project) } do
        next unless represented.bcf_issue?

        {
          href: bcf_v2_1_paths.topic(represented.project.identifier, represented.bcf_issue.uuid)
        }
      end

      link :convertBCF,
           cache_if: -> { current_user.allowed_in_project?(:manage_bcf, represented.project) } do
        next if represented.bcf_issue? || represented.project.nil?

        {
          href: bcf_v2_1_paths.topics(represented.project.identifier),
          title: "Convert to BCF",
          payload: { reference_links: [api_v3_paths.work_package(represented.id)] },
          method: :post
        }
      end

      links :bcfViewpoints,
            cache_if: -> { current_user.allowed_in_project?(:view_linked_issues, represented.project) } do
        next unless represented.bcf_issue?

        represented.bcf_issue.viewpoints.map do |viewpoint|
          {
            href: bcf_v2_1_paths.viewpoint(represented.project.identifier, represented.bcf_issue.uuid, viewpoint.uuid)
          }
        end
      end
    end

    extend_api_response(:v3, :work_packages, :work_package_collection) do
      require_relative "patches/api/v3/export_formats"

      prepend Patches::API::V3::ExportFormats
    end

    extend_api_response(:v3, :work_packages, :schema, :work_package_schema) do
      schema :bcf_thumbnail,
             type: "BCF Thumbnail",
             required: false,
             writable: false,
             show_if: ->(*) { represented&.project&.module_enabled?(:bim) }
    end

    extend_api_response(:v3, :activities, :activity) do
      include API::Bim::Utilities::PathHelper

      links :bcfViewpoints do
        journable = represented.journable
        next unless current_user.allowed_in_project?(:view_linked_issues, represented.project) &&
          represented.bcf_comment.present? && journable.bcf_issue?

        # There will only be one viewpoint per comment but we nevertheless return a collection here so that it is more
        # similar to the work package representer.
        Array(represented.bcf_comment.viewpoint).map do |viewpoint|
          {
            href: bcf_v2_1_paths.viewpoint(journable.project.identifier,
                                           journable.bcf_issue.uuid,
                                           viewpoint.uuid)
          }
        end
      end
    end

    add_api_path :bcf_xml do |project_id|
      "#{project(project_id)}/bcf_xml"
    end

    config.to_prepare do
      OpenProject::Bim::Hooks::Hook
    end

    initializer "bim.bcf.register_mimetypes" do
      Mime::Type.register "application/octet-stream", :bcf unless Mime::Type.lookup_by_extension(:bcf)
      Mime::Type.register "application/octet-stream", :bcfzip unless Mime::Type.lookup_by_extension(:bcfzip)
    end

    config.to_prepare do
      Doorkeeper.configuration.scopes.add(:bcf_v2_1)

      unless defined? OpenProject::Authentication::Scope::BCF_V2_1
        OpenProject::Authentication::Scope::BCF_V2_1 = :bcf_v2_1
      end

      OpenProject::Authentication.update_strategies(OpenProject::Authentication::Scope::BCF_V2_1,
                                                    store: false) do |_strategies|
        %i[oauth session]
      end
    end
    config.to_prepare do
      ::Exports::Register.register do
        list ::WorkPackage, OpenProject::Bim::BcfXml::Exporter
        formatter ::WorkPackage, OpenProject::Bim::WorkPackage::Exporter::Formatters::BcfThumbnail
      end

      ::Queries::Register.register(::Query) do
        filter ::Bim::Queries::WorkPackages::Filter::BcfIssueAssociatedFilter

        select ::Bim::Queries::WorkPackages::Selects::BcfThumbnailSelect
      end

      ::API::Root.class_eval do
        content_type :binary, "application/octet-stream"
        default_format :binary
        version "v1", using: :path do
          mount ::API::Bim::BcfXml::V1::BcfXmlAPI
        end
      end
    end

    add_view :Bim,
             contract_strategy: "Bim::Views::ContractStrategy"
  end
end