アドオン開発の第一歩として、以下のような単純な機能を持つ「スケルトン」アドオンを実装します。
スケルトンは以下の機能を持つものとします。
- 任意のプロジェクトにてスケルトンを有効化可能
- スケルトンは
param_1というパラメータを持ち、プロジェクトごとに異なる値を設定することができる param_1パラメータはプロジェクトのアドオン設定画面で設定することができる
本ドキュメントの実施にあたり、以下の前提条件を満たしているものとします。
- RDM-osf.ioリポジトリをフォークし、ローカル環境にcloneしていること
- 特に指定がない限りはdevelopブランチからアドオン開発用ブランチ(例えば、
feature/myskelton-addon)を作成し作業する - アドオン開発用ブランチには定期的にdevelopブランチをpullして変更を取り込む
- 特に指定がない限りはdevelopブランチからアドオン開発用ブランチ(例えば、
- cloneしたアドオン開発用ブランチで、 開発環境の準備 のガイドに従い、開発用RDMを起動していること
RDMにおいてアドオンはDjangoアプリケーションの形式で記述されます。以下のようなファイルおよびクラスから構成されます。
典型的なファイル配置は以下のようになります。
/addons/アドオン名/
├── __init__.py ... モジュールの定義
├── apps.py ... アプリケーションの定義
├── models.py ... モデルの定義
├── requirements.txt ... 利用するPythonモジュールの定義
├── routes.py ... View(Routes)の定義
├── settings ... 設定を定義するモジュール。ここにlocal.pyを配置することでカスタマイズできる。
│ ├── defaults.py ... デフォルト設定の定義
│ └── __init__.py ... 設定の定義
├── static ... Webブラウザから読み込むことを想定した静的ファイル
│ ├── comicon.png ... アドオンのアイコン
│ └── node-cfg.js ... Node設定を定義するJavaScriptファイル
├── templates ... テンプレートディレクトリ
│ └── node_settings.mako ... Node設定パネル
├── tests ... テストコード
│ ├── conftest.py
│ ├── factories.py
│ ├── test_model.py
│ ├── test_view.py
│ └── utils.py
└── views.py ... View(Views)の定義
アドオンはDjangoの作法に従い、Model-Viewアーキテクチャにより実装します。それぞれの責務は以下のように分担されます。
- Model ... ユーザとNode(プロジェクト)それぞれに対応したモデルを実装する。それぞれのモデルには認証情報やプロジェクト固有の情報を格納することができる
- View ... アドオンに応じた設定、データ取得、保存処理など、HTTP上のエンドポイント(パス)を定義する
Modelはフレームワークにより自動的にそれぞれの利用者、プロジェクトに対応して生成、管理され、永続化されるのに対し、Viewはアプリケーションがロードされる際に構築されます。 フレームワークによりそれぞれのライフサイクルが適切に管理されるので、アドオン開発者は機能面の実装に注力することができます。
Node(プロジェクト)に関する情報や、ユーザごとの情報(認証情報等)を記録、管理したい場合、Modelを定義します。
UserSettingsは利用者ごとにインスタンスが生成され、永続化されます。また、NodeSettingsはプロジェクトごとにインスタンスが生成、永続化されます。これらのインスタンスの生成や破棄をアドオンのコードが行うことは原則としてありません。
スケルトンの場合、以下のようにNodeに関するModelを定義します。
NodeSettingsは永続化すべきプロパティと、各種setterとgetterを定義しています。
ViewはFlaskのPluggable Viewsのように、サービス上のパスと処理の関係を定義します。定義はRoutesとViewsの2種類の要素から構成されます。
- Routes ... View処理をどのパスにマッピングし、どのような形式で出力するか。出力にはJSON形式や、HTMLのテンプレートを指定することができる
- Views ... View処理の内容
Routesは以下のようにパスとMethod(GET, POST, PUT, DELETE, ...)と、その組み合わせに対してどの関数を実行するか、その実行結果をどのように出力するかを定義します。
各View処理には、その処理の実行における前提をPythonのデコレータの形で記述することができます。指定可能なデコレータには以下のようなものがあります。
framework.auth.decorators.must_be_logged_in... ユーザがログインしている状態である場合にのみ呼び出し可能であることを宣言する。引数にはauthパラメータが追加され、認証しているユーザに関する情報を得ることができるwebsite.project.decorators.must_have_addon... アドオンに関する情報を必要とすることを宣言する。第1引数にはアドオン名を(例ではmyskelton)、第2引数には'user'か'node'のいずれかを定義する。('node'にした場合は、パスは /project// から始める必要がある)website.project.decorators.must_have_permission... 必要なパーミッションを宣言する。引数には'write', 'read', 'admin'のいずれかを指定する。
スケルトンの場合、以下のようにRoutesとViewsを定義します。
コンテキストに応じてデコレータを宣言しておくことで、Viewの処理の中でModel(利用者が操作対象としているUserやNode)を参照することができます。
Routes, Viewsを使うことでさまざまなAPIやインタフェースを定義することができますが、アドオンが持つ利用者用設定画面(認証情報の入力画面)とプロジェクト用設定画面(プロジェクトでアドオンを有効化した場合の設定画面)はフレームワークによってあらかじめテンプレート化されています。
このファイルは、テンプレート言語 mako で記述されます。
テンプレートを動的に操作するためのJavaScriptのライブラリにはKnockout.jsを利用することができます。JavaScriptコードについては、アドオンのstaticディレクトリにて定義することができます。
また、staticディレクトリにはアドオンのアイコンを定義する必要があります。
アドオンの動作を環境によりカスタマイズ可能にするため、settingsモジュールを用意します。
RDMのアプリケーション設定と同様に、settingsディレクトリ内に local.py ファイルを定義することで、アドオンの動作をカスタマイズできるようになります。
設定値は defaults.py で定義します。スケルトンの場合、以下のように定義します。
アドオンのユニットテストを定義します。スケルトンの場合、以下のようにModelのテスト(test_model.py)とViewのテスト(test_view.py)を定義しています。
Migrationsファイルは、Modelの内容をRDBのテーブルに対応づけをするために使用します。Modelの内容はバージョンによって変化しますから、各バージョンごとに適切にテーブルの変更がなされるよう、Migrationsファイルを適切に定義する必要があります。
スケルトンの場合、空の __init__.py を定義しています。
Migrationsファイルの作成にて作成方法を説明します。
ここでは、 myskelton という識別名のアドオンの実装を例に説明します。
スケルトンコードの例を addons/myskelton ディレクトリにコピーします。ファイルの構成で示したツリー構造となるようにコピーしてください。
このスケルトンでは、アドオン名(識別名)をmyskeltonとしています。
識別名はモジュール名と一致させる必要がありますので、myskelton以外の名前にしたい場合は、addons/(識別名) ディレクトリにスケルトンコードを配置するようにしてください。
また、この名前を変更したい場合は、以下のコードを変更する必要があります。
また、アドオンの完全名を My Skelton としています。これは、Web UIでの表示等に使われます。この名前を変更したい場合は、以下のコードを変更する必要があります。
追加したアドオンをRDMに認識させるために、RDMのコードをいくつか変更します。
addons.json に、アドオンに関する情報を追加します。このファイルはJSONファイル形式であり、キーごとに以下の値を登録します。
変更例はサンプル addons.json を参照してください。
-
addons... 利用可能なアドオン一覧。必ず登録する -
addons_default... プロジェクト作成時にデフォルトで有効になるアドオン一覧 -
addons_archivable... アドオンごとのアーカイブに関する情報 -
addons_commentable... コメント可能なアドオン一覧 -
addons_description... アドオン名と説明の定義"myskelton": "My Skelton Addon is ..." -
addons_url... アドオンの関連URLの定義"myskelton": "https://dummy.nii.ac.jp/myskelton"
framework/addons/data/addons.json に、アドオン登録時のメッセージリソースを登録します。
addons オブジェクトに、アドオンの完全名(AddonAppConfig.full_name に相当)をキーとして情報を登録します。
変更例はサンプル addons.json を参照してください。
この定義ファイルの内容は画面表示のためだけに利用され、動作には影響しません。
"My Skelton": {
"Permissions": {
"status": "none",
"text": "The GakuNin RDM does not affect the permissions of My Skelton."
},
"View / download file versions": {
"status": "none",
"text": "The My Skelton add-on does not provide Storage Features."
},
"Add / update files": {
"status": "none",
"text": "The My Skelton add-on does not provide Storage Features."
},
"Delete files": {
"status": "none",
"text": "The My Skelton add-on does not provide Storage Features."
},
"Logs": {
"status": "none",
"text": "The My Skelton add-on does not provide Storage Features."
},
"Forking": {
"status": "partial",
"text": "Forking a project or component copies information about linked My Skelton but the GakuNin RDM does not affect authentication of My Skelton."
},
"Registering": {
"status": "none",
"text": "My Skelton information will not be registered."
}
}
このメッセージの国際化については 国際化メッセージファイルの作成を参照してください。
Dockerfile に、アドオン関連のファイルコピー定義を追加します。
変更例はサンプル Dockerfile を参照してください。
-
requirements.txtのコピー
COPY ./addons/myskelton/requirements.txt ./addons/myskelton/ -
staticディレクトリの変更
COPY ./addons/myskelton/static/ ./addons/myskelton/static/
api/base/settings/defaults.py の INSTALLED_APPS にアドオン名を追加します。
変更例はサンプル defaults.py を参照してください。
'addons.myskelton',
Modelで定義したプロパティがRDBに保存されるよう、makemigrationsコマンドを実行します。このコマンドを実行すると、 addons/myskelton/migrations にPythonファイルが作成されます。
$ docker compose run --rm web python3 manage.py makemigrations
上記の出力中に以下の出力が現れれば成功です。現れない場合、RDMがアドオンを認識していない可能性があります。特にaddons.json, api/base/settings/defaults.pyの設定が漏れていないかどうかを確認してください。
Migrations for 'addons_myskelton':
addons/myskelton/migrations/0001_initial.py
- Create model NodeSettings
国際化メッセージファイルの定義ファイルは以下のコマンドで生成することができます。
このセクションの実施時は各サービスを停止状態にしてください。
# framework/addons/data/addons.jsonに定義されたメッセージをJavaScriptファイルへと変換する
$ docker compose run --rm web python3 -m scripts.generate_addons_translations
# メッセージ定義テンプレートファイル website/translations/js_messages.pot を更新する
$ docker compose run --rm web pybabel extract -F ./website/settings/babel_js.cfg -o ./website/translations/js_messages.pot .
# メッセージ定義ファイル website/translations/ja/LC_MESSAGES/js_messages.po を更新する
$ docker compose run --rm web pybabel update -i ./website/translations/js_messages.pot -o ./website/translations/en/LC_MESSAGES/js_messages.po -l en
$ docker compose run --rm web pybabel update -i ./website/translations/js_messages.pot -o ./website/translations/ja/LC_MESSAGES/js_messages.po -l ja
上記を実行すると、website/translations/ja/LC_MESSAGES/js_messages.poにある英語メッセージと日本語メッセージの対応づけが更新されます。
変更例のサンプル js_messages.po を参考に日本語メッセージを追加してください。
#: scripts/translations/messages_addonsJson.js:45
msgid ""
"\n"
"\n"
"<h3>My Skelton Add-on Terms</h3>\n"
"\n"
...
msgstr ""
"\n"
"\n"
"<h3>My Skelton アドオン規約</h3>\n"
"\n"
"<table class=\"table table-bordered table-addon-terms\">\n"
...
このメッセージを追加後、assetsサービスの再起動時にメッセージ定義が反映されます。
これでアドオンのコードの作成は完了です。以下のコマンドで追加した addons/myskelton のユニットテストを実行してみましょう。
$ docker compose run --rm web invoke test_module -m addons/myskelton/tests/
スケルトン アドオンを動作確認をしてみましょう。 アドオンには新規に定義されたModelが含まれていますので、Migrations定義をサービス中のPostgreSQLサービスに反映しましょう。
$ docker compose run --rm web python3 manage.py migrate
また、新規にJavaScriptファイルを追加したので、新たなファイルがロード対象となるように、RDM-osf.ioをイメージとしたサービスの再起動を実施します。
$ docker compose restart assets web api
これでサービスへの反映は完了です。スケルトン アドオンを試すには、以下のような操作を実施します。
これで、node_settings.makoで定義したNode設定画面が現れます。テキストボックスに入力した値が param_1 プロパティに反映される様子が確認できるはずです。
以上でスケルトンアドオンの動作確認は完了です!



