NotionRubyMapping で有効期限に対応: hkob の雑記録 (43)

はじめに

hkob の雑記録の第43回目は、データベースに追加された有効期限プロパティを NotionRubyMapping で対応する作業を記録していきます。今回も作業しながらログを残していく雑記録になります。

有効期限プロパティ

また、田原さんが見つけていました。これまで Wiki にしかなかった有効期限が通常のデータベースでも使えるようになったそうです。

ただ、私のところでは確認できず、田原さんのところでも消えていたとのことです。ただ、今後復活する可能性もありますし、Wiki データベースには存在するので、NotionRubyMapping で対応したいと思います。

Wiki テストデータ作成

テストで呼び出すために Wiki データベースを作成します。

Wiki データベース

その中の1ページに「有効期限」をつけています。

Wiki 内ページ

このページの URL を取得しておきます。

https://www.notion.so/hkob/Wiki-page-197d8e4e98ab80d7b0cad8a33a1cbfba?pvs=4

実際に NotionRubyMapping でこのページにアクセスしてみます。有効期限にアクセスすると「verification」プロパティがないとエラーになりました。

irb(main):001> load "/Users/hkob/bin/include_nrm.rb"
=> true
irb(main):002> page = Page.find "https://www.notion.so/hkob/Wiki-page-197d8e4e98ab80d7b0cad8a33a1cbfba?pvs=4"
=> NotionRubyMapping::Page-197d8e4e98ab80d7b0cad8a33a1cbfba
irb(main):003> page.properties["有効期限"]
/Users/hkob/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/notion_ruby_mapping-0.8.8/lib/notion_ruby_mapping/properties/property.rb:122:in `create_from_json': Irregular property type: verification (StandardError)
  from /Users/hkob/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/notion_ruby_mapping-0.8.8/lib/notion_ruby_mapping/controllers/property_cache.rb:20:in `[]'
  from (irb):3:in `<main>'
    from <internal:kernel>:187:in `loop'
  from /Users/hkob/.rbenv/versions/3.3.4/lib/ruby/gems/3.3.0/gems/irb-1.14.2/exe/irb:9:in `<top (required)>'
  from /Users/hkob/.rbenv/versions/3.3.4/bin/irb:25:in `load'
    from /Users/hkob/.rbenv/versions/3.3.4/bin/irb:25:in `<main>'

page json の取得

まず、テストを作成するために、fixtures データを取得します。まずはページ全体を取得します。既存の top ページを取得するスクリプトをコピーして修正します。

cd spec/fixtures
cp retrieve_page_{top,wiki}.sh

スクリプトは以下のようになります。

curl 'https://api.notion.com/v1/pages/197d8e4e98ab80d7b0cad8a33a1cbfba' \
  -H 'Notion-Version: 2022-06-28' \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"''

make することで、自動的にシェルから json を作成します。

touch *.json; make
sh retrieve_page_wiki.sh > retrieve_page_wiki.json
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1956    0  1956    0     0   5091      0 --:--:-- --:--:-- --:--:--  5080
sleep 1

今回、確認したい有効期限を括り出してみると以下のようになっています。通常、id は一時的な文字列の組み合わせのものが用意されますが、verification という固定値になっています。これは複数個の設置されることがないためだと思われます。ページタイトルも title という固定値でした。

        "有効期限": {
            "id": "verification",
            "type": "verification",
            "verification": {
                "state": "verified",
                "verified_by": {
                    "object": "user",
                    "id": "2200a911-6a96-44bb-bd38-6bfb1e01b9f6",
                    "name": "Hiroyuki KOBAYASHI",
                    "avatar_url": "https://s3-us-west-2.amazonaws.com/public.notion-static.com/166af4f6-0b35-4664-bf0d-0850068dddaa/my-notion-face-portrait.png",
                    "type": "person",
                    "person": {
                        "email": "hkob@metro-cit.ac.jp"
                    }
                },
                "date": {
                    "start": "2025-02-10T15:00:00.000Z",
                    "end": "2025-02-17T15:00:00.000Z",
                    "time_zone": null
                }
            }
        },

同じように property 取得のスクリプトも作成してみます。固定プロパティな点が同じなので、title のものを雛形に作成してみます。

cp retrieve_property_{title,verification}.sh 

スクリプトは以下のようになりました。

curl 'https://api.notion.com/v1/pages/197d8e4e98ab80d7b0cad8a33a1cbfba/properties/title' \
    -H 'Notion-Version: 2022-06-28' \
    -H 'Authorization: Bearer '"$NOTION_API_KEY"''

先ほどと同様に make します。

touch *.json; make
sh retrieve_property_verification.sh > retrieve_property_verification.json
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   487  100   487    0     0   1149      0 --:--:-- --:--:-- --:--:--  1151
sleep 1

無事に property_item が取得できました。

{
    "object": "property_item",
    "type": "verification",
    "id": "verification",
    "verification": {
        "state": "verified",
        "verified_by": {
            "object": "user",
            "id": "2200a911-6a96-44bb-bd38-6bfb1e01b9f6"
        },
        "date": {
            "start": "2025-02-10T15:00:00.000Z",
            "end": "2025-02-17T15:00:00.000Z",
            "time_zone": null
        }
    },
    "request_id": "6e4c8157-d152-4e3a-8ffd-45cfadd9148a"
}

verification_property_spec.rb の作成

verification の Property については、ここに記載されていました。現状では取得のみでデータベースの更新でプロパティを追加したり、ページプロパティとして値を更新したりすることはできないようです。

developers.notion.com

status_property_spec.rb を雛形として、データベースプロパティの作成部分、ページプロパティの更新処理の部分のテストを外せば良さそうです。実装も status をコピーして雛形だけにします。

cd ~/Dropbox/ruby/notion_ruby_mapping
cp spec/notion_ruby_mapping/properties/{status,verification}_property_spec.rb
cp lib/notion_ruby_mapping/properties/{status,verification}_property.rb 

プロパティの作成、更新を除くとテストは以下のようになりました。

# frozen_string_literal: true

module NotionRubyMapping
  RSpec.describe VerificationProperty do
    tc = TestConnection.instance
    let(:no_content_json) { {"id" => "verification"} }
    let(:verification_database_id) { TestConnection::WIKI_DATABASE_ID }
    let(:verification_page_id) { TestConnection::WIKI_PAGE_ID }
    let(:property_cache_verification) { PropertyCache.new base_type: :page, page_id: verification_page_id }

    context "Page property" do
      retrieve_verification = {
        "vp" => {
          "type" => "verification",
          "verification" => {
            "state" => "verified",
            "verified_by" => {"id" => "2200a911-6a96-44bb-bd38-6bfb1e01b9f6", "object" => "user"},
            "date" => {
              "start" => "2025-02-10T15:00:00.000Z",
              "end" => "2025-02-17T15:00:00.000Z",
              "time_zone" => nil,
            },
          },
        },
      }
      context "created by new" do
        let(:target) { VerificationProperty.new "vp" }
        it_behaves_like :property_values_json, {"vp" => {"verification" => {}, "type" => "verification"}}
        it_behaves_like :will_not_update
        it_behaves_like :assert_different_property, :update_property_schema_json

        describe "update_from_json" do
          before { target.update_from_json(tc.read_json("retrieve_property_verification")) }
          it_behaves_like :will_not_update
          it_behaves_like :property_values_json, retrieve_verification
          it_behaves_like :assert_different_property, :update_property_schema_json
        end
      end

      context "created from json" do
        let(:target) { Property.create_from_json "vp", tc.read_json("retrieve_property_verification") }
        it_behaves_like :has_name_as, "vp"
        it_behaves_like :will_not_update
        it_behaves_like :property_values_json, retrieve_verification
        it_behaves_like :assert_different_property, :update_property_schema_json
      end

      context "created from json (no content)" do
        let(:target) { Property.create_from_json "vp", no_content_json, :page, property_cache_verification }
        it_behaves_like :has_name_as, "vp"
        it_behaves_like :will_not_update
        it { expect(target.contents?).to be_falsey }
        it_behaves_like :assert_different_property, :update_property_schema_json

        # hook property_values_json / verification to retrieve a property item
        it_behaves_like :property_values_json, retrieve_verification
      end
    end
  end
end

verification_property.rb の実装

verification は何もしないので、ほとんど中身はないです。

# frozen_string_literal: true

module NotionRubyMapping
  # Status property
  class VerificationProperty < Property
    TYPE = "verification"

    ### Public announced methods

    ## Common methods

    # @see https://www.notion.so/hkob/StatusProperty-c8b2c83019bc42edbc1527386c7ef453#bdb34c0aeaa74729887da087d0bd8022
    def verification
      @json
    end

    ## Page property only methods

    ## Page property only methods

    ### Not public announced methods

    ## Common methods

    # @param [String] name Property name
    # @param [Boolean, Hash] json
    def initialize(name, will_update: false, base_type: :page, property_id: nil, property_cache: nil, json: {})
      super name, will_update: will_update, base_type: base_type, property_id: property_id,
                  property_cache: property_cache
      @json = json
    end

    ## Page property only methods

    # @return [Hash]
    def property_values_json
      assert_page_property __method__
      {@name => {"verification" => @json, "type" => "verification"}}
    end
  end
end

property.rb の更新

property.rb の中で json の type からプロパティクラスを取得する部分を追記すればいいはずです。

        klass = {
          "button" => ButtonProperty,
          "checkbox" => CheckboxProperty,
          "created_time" => CreatedTimeProperty,
          "date" => DateProperty,
          "formula" => FormulaProperty,
          "last_edited_time" => LastEditedTimeProperty,
          "rollup" => RollupProperty,
          "email" => EmailProperty,
          "files" => FilesProperty,
          "created_by" => CreatedByProperty,
          "last_edited_by" => LastEditedByProperty,
          "multi_select" => MultiSelectProperty,
          "relation" => RelationProperty,
          "number" => NumberProperty,
          "people" => PeopleProperty,
          "phone_number" => PhoneNumberProperty,
          "select" => SelectProperty,
          "status" => StatusProperty,
          "title" => TitleProperty,
          "rich_text" => RichTextProperty,
          "unique_id" => UniqueIdProperty,
          "url" => UrlProperty,
          "verification" => VerificationProperty,
        }[type]
        raise StandardError, "Irregular property type: #{type}" unless klass

        answer = klass.new name, property_id: input_json["id"], json: input_json[type], base_type: base_type,
                                 property_cache: property_cache
        answer = answer.retrieve_page_property if answer.is_a?(RelationProperty) && input_json["has_more"] == true
        answer

動作確認

動作は RSpec で確認しました。とりあえず今回のコードを追加しましたが、テストは全部成功したようです。

Finished in 0.89355 seconds (files took 0.8587 seconds to load)
2364 examples, 0 failures

ただ、一度取り込んだ JSON はそろそろ取得し直したほうがいいかと思っています。近々一つずつ更新していこうと思います。

ローカルパッケージを作成してインストール

まず、local build してみます。

rake build
notion_ruby_mapping 0.8.9 built to pkg/notion_ruby_mapping-0.8.9.gem.

作成したパッケージをローカルインストールしてみます。

gem install pkg/notion_ruby_mapping-0.8.9.gem
Successfully installed notion_ruby_mapping-0.8.9
Parsing documentation for notion_ruby_mapping-0.8.9
Done installing documentation for notion_ruby_mapping after 0 seconds
1 gem installed

実際にテスト

インストールしたバージョンで先ほどと同様に有効期限プロパティにアクセスしてみます。今度はちゃんと取得できたようです。

irb(main):001> load "/Users/hkob/bin/include_nrm.rb"
=> true
irb(main):002> page = Page.find "https://www.notion.so/hkob/Wiki-page-197d8e4e98ab80d7b0cad8a33a1cbfba?pvs=4"
=> NotionRubyMapping::Page-197d8e4e98ab80d7b0cad8a33a1cbfba
irb(main):003> page.properties["有効期限"]
=> 
#<NotionRubyMapping::VerificationProperty:0x000000011c46e250
 @base_type=:page,
 @create=false,
 @json=
  {"state"=>"verified",
   "verified_by"=>
    {"object"=>"user",
     "id"=>"2200a911-6a96-44bb-bd38-6bfb1e01b9f6",
     "name"=>"Hiroyuki KOBAYASHI",
     "avatar_url"=>
      "https://s3-us-west-2.amazonaws.com/public.notion-static.com/166af4f6-0b35-4664-bf0d-0850068dddaa/my-notion-face-portrait.png",
     "type"=>"person",
     "person"=>{"email"=>"hkob@metro-cit.ac.jp"}},
   "date"=>{"start"=>"2025-02-10T15:00:00.000Z", "end"=>"2025-02-17T15:00:00.000Z", "time_zone"=>nil}},
 @name="有効期限",
 @new_name=nil,
 @property_cache=PropertyCache,
 @property_id="verification",
 @query=nil,
 @remove=false,
 @will_update=false>

gem としてリリース

とりあえず動いているようなので、version 0.8.9 として正式にリリースします。

rake release
notion_ruby_mapping 0.8.9 built to pkg/notion_ruby_mapping-0.8.9.gem.
Tagged v0.8.9.
Pushed git commits and release tag.
Pushing gem to https://rubygems.org...
You have enabled multi-factor authentication. Please enter OTP code.
Code:   109697
Successfully registered gem: notion_ruby_mapping (0.8.9)
Pushed notion_ruby_mapping 0.8.9 to rubygems.org

RubyGem のサイトで更新されていることを確認しました。

rubygems.org

Github でリリース

Github のタグは gem のリリース時に自動で設定してくれるのですが、Github 側でリリースも出しておきます。

github.com

おわりに

今日は、熊倉さんからの以下のポストがあって、リリースにこぎ着けました。9月以来更新していなかったので、約半年ぶりのリリースになりました。ありがとうございます。

hkob.notion.site