JSONをCSVに変換するツール json2csvを作りました

JSONをCSVに変換するツールjson2csvを作りました。

マッピング情報を元に、JSONからCSVに変換します。

$ json2csv -i input.json -m mapping.json -o output.csv
Usage: json2csv [flags]

Flags
  -i, --input string     JSON input file path or directory or url
  -m, --mapping string   JSON to CSV mapping file path or url
  -o, --output string    CSV output file path
  -b, --bom              CSV with BOM
  -h, --help             Help

マッピング情報は下記のように書きます。
XPathを使って行の一覧と各カラムを指定するようなイメージです。

{
    "rowsPath": "//items/*",
    "columns": [
        {
            "header": "title",
            "valuePath": "/title"
        },
        {
            "header": "link",
            "valuePath": "/link"
        },
        {
            "header": "description",
            "valuePath": "/description"
        }
    ]
}

JSONからXPathで取得する部分は、antchfx/jsonquery を使っています。JSONとXPathの対応は下記を見るとわかりやすいと思います。

Goで書いているので、Windows/Linux/Macに対応しています。実行ファイルは下記からダウンロードしてください。

ShortcutKey2URLでシークレット(プライベート)ウインドウで開くアクションを追加しました(Chrome版v1.5.0、Firefox版v4.4.0)

要望を受けて、ShortcutKey2URLでIncognitoウインドウで開くアクションを追加しました。(Chromeだとシークレットウインドウ、Firefoxだとプライベートウインドウと呼ばれるもの)

下記の2つのアクションを追加しています。

  • Open url in incognito window シークレットウインドウでURLを開く。
  • Open current tab in incognito window シークレットウインドウで現在のタブを開く。

Firefoxだと、拡張機能の詳細から、「プライベートウィンドウでの実行」を「許可する」に設定しないと実行できないのでご注意ください。

社内勉強会で「40歳過ぎてもエンジニアでいるためにやっていること」というタイトルでLTしました

社内勉強会で「40歳過ぎてもエンジニアでいるためにやっていること」というタイトルで、今まで継続してきたことを発表しました。

定年までエンジニアとしてやっていきたいと思っているので、今後も今までやってきたことを継続出来れば、、と思っています。

Web APIを利用して郵便番号から住所を取得して設定(Redmine View Customize Plugin)

下記問い合わせに対応して、Web APIを利用して郵便番号から住所を取得して設定するサンプルを作成しました。

動作イメージ

下記APIを利用して住所を設定しています。

https://github.com/onozaty/redmine-view-customize-scripts/raw/master/examples/0056.get_address_from_zipcode_with_webapi/result.gif

コード内容は下記にまとめています。

Power Apps+Power Automateを学ぶのに、MICUGの「Power Platform Onboarding Center アプリ開発コース」が良かった

MICUG(マイカグ)で「Power Platform Onboarding Center」というオンラインのハンズオンが定期的に開催されています。

MICUG(マイカグ)は、Microsoft Cloud を話題に相互に交流する事を目的として構成されたエンタープライズコミュニティです。
日々のMicrosoft Cloudを利用する中でより高度な活用、お客様、パートナー企業の相互交流を深め、それぞれの企業が持つ経験やノウハウを共有し、開発者、市民開発者、IT Pro、インフラエンジニア、データサイエンティスト、CCoE(Cloud Center of Excellence)などのクラウド導入管理・展開計画者のコミュニケーションを支えることを大きな目的としています。
MICUG(マイカグ)

アプリ開発コース(Power Apps + Power Automate)を受けたのですが、とっても良かったのでここでも紹介したいと思います。(検索してもあまりヒットしなかった情報で、私も勧められて知ったので)
私が受けたのは第4回で、現在は第5回が開催中です。(1ヵ月周期で開催されています)

Teamsのライブイベントになっていて、事前にTeamsに招待されるような形で参加します。
全部で6回のイベントがスケジュールされており、プラスで最終課題が出されて自主学習を行うような流れになっていました。

  1. キックオフ : 45分
  2. Power Apps 初級ハンズオン : 180分
  3. Power Automate 初級ハンズオン : 180分
  4. Power BI 初級ハンズオン : 180分
  5. Power Apps・Power Automate 中級ハンズオン : 180分
  6. アプリ開発の為の論理思考トレーニング : 180分

ハンズオンは録画されているので、後から観たり、途中で止めたりといったことが可能です。
自分は結局リアルタイムで受けたのは初回だけで、その後は遅れて観るような形にしました。
再生速度は1.75にして、わからなかったところがあったら止めて確認する、、といった感じで、ちょうど実際の時間と同じくらいになる感じでした。

ハンズオンとしてわかりやすいのと、「Power AppsやPower Automateだとこうする/こう考える」といった、考え方が学べたのが良かったです。
CRUD操作が出来る画面や承認フローは簡単に作れるようになったのと、応用も効かせられるようになったかなと思います。

Maildir形式のメールボックスの統計情報を出力するツール(maildir-stats)を作りました

Dovecot+Postfixで構成されたメールサーバ上のメール容量を計測したくて、Maildir形式のメールボックスの統計情報を出力するツールmaildir-stats をGoで作りました。

1ユーザ分の情報を出力するuserコマンドと、全ユーザの情報を出良くするusersコマンドをサブコマンドとして提供しています。

user

1ユーザ分のMaildirを指定します。
サマリの情報+フォルダ毎、年毎、月毎の情報を出力できます。

$ maildir-stats user -d /home/user1/Maildir -f -y -m

[Summary]
Number of mails : 10
Total size      : 3,340 byte

[Folder]
  Name   | Number of mails | Total size(byte)  
---------+-----------------+-------------------
         |               4 |               10  
  A      |               2 |               30  
  B      |               2 |              300  
  C      |               0 |                0  
  XXXXXX |               2 |            3,000  

[Year]
  Year | Number of mails | Total size(byte)  
-------+-----------------+-------------------
  2022 |               3 |            3,003  
  2023 |               7 |              337  

[Month]
  Month   | Number of mails | Total size(byte)  
----------+-----------------+-------------------
  2022-11 |               1 |            2,000  
  2022-12 |               2 |            1,003  
  2023-01 |               3 |              320  
  2023-02 |               2 |                5  
  2023-03 |               2 |               12  

users

ユーザのホームディレクトリからのMaildir名を指定します。ユーザの情報は /etc/passwd から取得します。
サマリの情報+ユーザ毎、年毎、月毎の情報を出力できます。

$ maildir-stats users -d Maildir -u -y -m

[Summary]
Number of mails : 11
Total size      : 6,321 byte

[User]
  Name  | Number of mails | Total size(byte)  
--------+-----------------+-------------------
  user1 |               6 |               21  
  user2 |               2 |              300  
  user3 |               3 |            6,000  
  user4 |               0 |                0  

[Year]
  Year | Number of mails | Total size(byte)  
-------+-----------------+-------------------
  2021 |               2 |              300  
  2022 |               6 |            3,014  
  2023 |               3 |            3,007  

[Month]
  Month   | Number of mails | Total size(byte)  
----------+-----------------+-------------------
  2021-12 |               2 |              300  
  2022-11 |               3 |            1,006  
  2022-12 |               3 |            2,008  
  2023-01 |               2 |            3,003  
  2023-02 |               1 |                4  

おわりに

詳しいオプションなどはREADMEをご参照ください。

Redmine: View customize plugin の v3.3.0 をリリースしました

View customize plugin の v3.3.0 をリリースしました。

挿入位置として「チケット一覧のコンテキストメニュー」を追加しています。(マージリクエストをいただきました)

コンテキストメニューに対してカスタマイズする際には、下記のサンプルのような感じでちょっと面倒だったのですが、、

$(function() {

  // Replace the show function in jQuery to add processing when the context menu is shown
  jQuery.fn._show = jQuery.fn.show;

  jQuery.fn.show = function() {
    if (this.attr('id') == 'context-menu') {
      const a = $('#context-menu a[href*="status_id%5D=6"]');
      a.attr('href', a.attr('href') + '&issue%5Bfixed_version_id%5D=none');
    }

    return jQuery.fn._show.apply(this, arguments);
  };
});

下記のようにシンプルに書くことができます。

const a = $('#context-menu a[href*="status_id%5D=6"]');
a.attr('href', a.attr('href') + '&issue%5Bfixed_version_id%5D=none');