ククログ

株式会社クリアコード > ククログ > Redmineのプラグインの作り方 - UNCプラグインを例にして

Redmineのプラグインの作り方 - UNCプラグインを例にして

阿部です。

UNC形式のパスをクリップボードにコピーするRedmineプラグイン を開発しました。 それを通してRedmineのプラグインを一から作る方法について学んだので、その内容を紹介します。

作ったときの私の知識レベルが以下なので、そのくらいの方であれば参考になる内容だと思います。

  • Redmineは普段利用している
  • RedmineはRuby on Railsで開発されているらしい
    • コードは読んだことがない
    • Ruby on Rails自体は初心者
  • Redmineのプラグイン開発の経験もなし

はじめに

今回開発したプラグインはUNC形式のパスをクリックでクリップボードにコピーできるようにするものです。 そのようにすることでUNC形式のファイルパスを開くまでのステップを少なくすることが狙いです。

近年はセキリティ上の理由からブラウザで file:// URLへのアクセスに制限があるため、この補助機能でファイルが開きやすくなります。

もう少し具体的に機能の説明をすると、 \\server\path\to\file といった文字列のUNC形式のパスを、 以下のキャプチャにあるクリックでパスをコピーするリンクに自動で変換して表示します。

スクリーンショット:表示例

このRedmineのプラグインではそのような表示文字列の自動変換以外にもできることはいろいろありますが、 本記事では「Redmineの投稿内容を加工して表示」するプラグインを一から作る方法について紹介します。

流れ

  1. Redmine本体を動かす
  2. プラグインの雛形生成
  3. プラグイン情報の更新
  4. プラグインの実装

1. Redmine本体を動かす

今回の本題ではありませんので、Redmineを起動するまでのコマンドの列挙に留めます。 以下の通り実行することでRedmineが起動しブラウザで確認できます。

git clone --depth 1 https://github.com/redmine/redmine.git
cd redmine
cat <<EOF > config/database.yml
development:
  adapter: sqlite3
  database: db/redmine.sqlite3
EOF
bundle install
bin/rails generate_secret_token
bin/rails db:migrate
REDMINE_LANG=en bin/rails redmine:load_default_data
bin/rails server

2. プラグインの雛形生成

以下のコマンドでプラグインの雛形を生成します。

bin/rails generate redmine_plugin <plugin_name>

Redmine本体を起動したディレクトリで実行します。

bin/rails generate redmine_plugin UNC
      create  plugins/unc/app
      create  plugins/unc/app/controllers
      create  plugins/unc/app/helpers
      create  plugins/unc/app/models
      create  plugins/unc/app/views
      create  plugins/unc/db/migrate
      create  plugins/unc/lib/tasks
      create  plugins/unc/assets/images
      create  plugins/unc/assets/javascripts
      create  plugins/unc/assets/stylesheets
      create  plugins/unc/config/locales
      create  plugins/unc/test
      create  plugins/unc/test/fixtures
      create  plugins/unc/test/unit
      create  plugins/unc/test/functional
      create  plugins/unc/test/integration
      create  plugins/unc/test/system
      create  plugins/unc/README.rdoc
      create  plugins/unc/init.rb
      create  plugins/unc/config/routes.rb
      create  plugins/unc/config/locales/en.yml
      create  plugins/unc/test/test_helper.rb

plugins ディレクトリ以下に生成されます。

3. プラグイン情報の更新

init.rb を開発するプラグインに合わせて更新します。 以下の内容に更新しました。

Redmine::Plugin.register :unc do
  name 'UNC plugin'
  author 'ClearCode Inc.'
  description 'Improve UNC format path accessibility'
  version '0.0.1'
  url 'https://gitlab.com/redmine-plugin-unc/redmine-plugin-unc'
  author_url 'https://gitlab.com/clear-code'
end

4. プラグインの実装

すべての投稿内容にあるUNC形式のパスを変換したいので、ApplicationHelper#parse_non_pre_blocks を拡張して対応することにしました。

ApplicationHelper#parse_non_pre_blocks は、表示するHTMLのうち <pre> タグ以外の要素(= マークアップ言語としてMarkdownを使っている場合は ```` で囲まれたところ以外)に対して ブロックで受け取った変換処理を行うメソッドです。 そこにUNC形式のパスを変換する処理を追加する方針です。

このメソッドを Module#prepend を使って拡張します。 (Redmineのドキュメントにある Plugin Internals > Extending the Redmine Core に相当する方法です。)

実際のコードが30行もないので掲載して簡単に解説します。

module Unc
  module ApplicationHelperMixin
    def link_unc_path(path)
      link_to_function(
        "(#{l(:copy_unc_path)}) #{path}",
        'copyTextToClipboard(this)',
        class: 'icon icon-copy-link',
        data: {'clipboard-text' => path}
      )
    end

    def parse_unc_paths(text)
      text.gsub!(/"(\\\\.+?)"|\\\\[^\s<]+/) do |matched|
        link_unc_path($1 || matched)
      end
    end

    def parse_non_pre_blocks(text, obj, macros, options={})
      super do |txt|
        yield txt
        parse_unc_paths(txt)
      end
    end
  end
end

ApplicationHelper.prepend(Unc::ApplicationHelperMixin)
  • link_unc_path
    • クリップボードへコピーするリンクのHTMLを生成するメソッド
    • クリップボードへコピーするJavaScriptがRedmineに含まれていたので活用
    • Redmineにある類似のメソッドを参考にしました ApplicationHelper#copy_object_url_link
  • parse_unc_paths
    • 投稿テキストに含まれるUNC形式のパスを link_unc_path が返すHTMLに置換
  • parse_non_pre_blocks
    • super が受け取ったブロックを実行し、その後で parse_unc_paths の処理を実行
  • ApplicationHelper.prepend(Unc::ApplicationHelperMixin)
    • ApplicationHelperUnc::ApplicationHelperMixin を追加して、parse_non_pre_blocks を上書き

最後に Unc::ApplicationHelperMixin の読み込みを init.rb へ追加して完了です。

追加後の init.rb は以下の通りです。

Redmine::Plugin.register :unc do
  name 'UNC plugin'
  author 'ClearCode Inc.'
  description 'Improve UNC format path accessibility'
  version '0.0.1'
  url 'https://gitlab.com/redmine-plugin-unc/redmine-plugin-unc'
  author_url 'https://gitlab.com/clear-code'
end

# Load.
Unc::ApplicationHelperMixin

最後の1行がポイントで Unc::ApplicationHelperMixin により lib/unc/application_helper_mixin.rb が読み込まれ、 その中で ApplicationHelper.prepend(Unc::ApplicationHelperMixin) が実行されます。 その結果、このプラグインで変更した処理がRedmineに組み込まれます。

まとめ

UNC形式のパスをクリップボードにコピーするRedmineプラグインを一から作る方法を紹介しました。 「Redmineの投稿内容を加工して表示」するプラグインを開発するときに役立つと思います。

違う機能のプラグインを開発する場合は方法が変わりますので、 Plugin Tutorial を参考にご対応ください。

なお、この機能はクリアコードが提供しているRedmineサポート契約の中で開発しました。 クリアコードが提供するRedmineサポートではお客さんが必要としている機能を理解した上で 汎用的なプラグインとして対応することが多いです。 その際、プラグインは自由なソフトウェアとして開発し広く公開します。 汎用的な機能のため、お客さんの機密情報などが含まれることがなく、 お客さんにとってデメリットはありません。 また他のお客さんでも使うことになったら、メンテナンス費用を 按分できるコストメリットもあります。

プラグインではなくRedmine本体を改良した方がよさそうな場合もあります。 その時はお客さんが使っているRedmineにパッチを当ててもらうのではなく、 Redmine本体に機能を提案してRedmine本体に取り込んでもらえるようにします。 自分たちでパッチを当てるよりもRedmine本体に入っていた方がアップデートが楽になり、 メンテナンスコストが下がるからです。 ただ、Redmine本体の開発をコントロールすることはできないので、 一時的にプラグインで対処したりパッチを当ててもらうということはあります。

そのようなRedmineサポートがよい方はお問い合わせフォームよりご連絡ください。

参考: Redmineのドキュメント