Redmine wikiマクロを作成する方法５（特定のユーザーのチケット状態の確認）

# Redmine wikiマクロを作成する方法５（特定のユーザーのチケット状態の確認）

[Redmine Advent Calendar 2024](https://adventar.org/calendars/10311)の13日目の記事として作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/6ef9fdff-d835-94bb-98a9-f7aacb5b3883.png)


今年のRedmine Advent Calendarに空白が多く残っており、クリスマスが過ぎる前までになんとか空白の日付の記事を書いて、空白の日付を埋めることを優先して記事を作成しました。そのため、濃くない内容の記事になるかもしれませんが、ご容赦ください。


## 完成形
今回の開発では、下図のように、wikiマクロで特定のユーザーのチケット状態を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/f1ff239e-67b7-7a04-f226-cc4d34eb404d.png)



* * *
## 背景

Redmineには自作のwikiマクロを作成して登録することができます。
その方法としてはプラグインを作成しますがwikiマクロの登録のためのプラグインは比較的開発が簡単であるため、プラグインを作ったことがない方でも簡単に試してみることができるメリットがあります。

wikiマクロでは色々な処理をすることができるためRedmineの構造を理解したり、Rubyを理解したり、プラグインの仕組みを理解したりするためには良い教材になるかと思います。
今年のRedmine Advent Calendarを通して、何回かに分けてwikiマクロの作り方を紹介したいと思います。

今回の記事では「Redmine wikiマクロを作成する方法５」として「特定のユーザーのチケット状態の確認」する方法を説明します。


## 前提条件：
使用するwikiマクロ登録用プラグインは[Redmine wikiマクロを作成する方法１](https://qiita.com/yam_asaki/items/1dfd349e078fc6d0f764)で説明したプラグインを使用します。/plugins/wiki_macro_plugin/init.rbの「init.rb」ファイルにwikiマクロを登録します。


---

### 1. **マクロを実装**

1. /plugins/wiki_macro_plugin/init.rbの「`init.rb`」ファイルを編集して、Wikiマクロを登録します：
   ```ruby
   Redmine::Plugin.register :wiki_macro_plugin do
    省略
   end

    Redmine::WikiFormatting::Macros.register do
      desc "Show tasks assigned to a specific user"
      macro :user_tasks do |obj, args|
        user = User.find_by_login(args.first)
        if user
          issues = Issue.open.where(assigned_to_id: user.id).visible
          if issues.any?
            calendar = "#{user.name}のタスク<br>"
            calendar << "<table border='1' style='border-collapse: collapse; width: 100%;'>"
            calendar << "<tr><th>#</th><th>題名</th><th>開始日</th><th>期日</th><th>状態</th><th>進捗率</th></tr>"
          
            issues.each do |issue|
              days_info = if issue.due_date
                            days_left = (issue.due_date - Date.today).to_i
                            if days_left > 0
                              "期日まで #{days_left}日"
                            elsif days_left == 0
                              "今日が期日"
                            else
                              "<font color='red'>#{days_left.abs}日 遅れ</font>"
                            end
                          else
                            "期日未設定"
                          end
          
              calendar << "<tr>"
              calendar << "<td>#{link_to("##{issue.id}", issue_path(issue))}</td>"
              calendar << "<td>#{issue.subject}</td>"
              calendar << "<td>#{issue.start_date || 'N/A'}</td>"
              calendar << "<td>#{issue.due_date || 'N/A'}</td>"
              calendar << "<td>#{days_info}</td>"
              calendar << "<td>#{issue.done_ratio}%</td>"
              calendar << "</tr>"
            end
          
            calendar << "</table>"
            calendar.html_safe
          else
            "タスクがありません。"
          end
        else
          "User not found."
        end
      end
    end
   ```

以下、コードを1行ずつ解説します。

---

```ruby
Redmine::WikiFormatting::Macros.register do
```
- **説明**: Redmineに新しいWikiマクロを登録するための宣言です。このブロック内でカスタムマクロを定義します。

---

```ruby
  desc "Show tasks assigned to a specific user"
```
- **説明**: マクロの説明を定義します。

---

```ruby
  macro :user_tasks do |obj, args|
```
- **説明**: `:user_tasks`という名前のWikiマクロを定義します。
- **引数**:
  - `obj`: 現在のWikiページやプロジェクトなどのコンテキストオブジェクト。
  - `args`: マクロに渡された引数の配列。

---

```ruby
    user = User.find_by_login(args.first)
```
- **説明**: 引数から取得したユーザーログイン名でユーザーを検索します。

---

```ruby
    if user
```
- **説明**: ユーザーが見つかった場合の処理を開始します。

---

```ruby
      issues = Issue.open.where(assigned_to_id: user.id).visible
```
- **説明**: 指定されたユーザーに割り当てられた、現在「オープン」状態のタスクを取得します。また、ユーザーが閲覧可能なタスクのみを含めます。

---

```ruby
      if issues.any?
```
- **説明**: 該当するタスクが存在する場合の処理を開始します。

---

```ruby
        calendar = "#{user.name}のタスク<br>"
```
- **説明**: カレンダー形式の出力用に、ユーザー名を含むタイトルを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/6db2dd84-7256-bd60-5589-b8c71af4a05d.png)

---

```ruby
        calendar << "<table border='1' style='border-collapse: collapse; width: 100%;'>"
```
- **説明**: タスクを表形式で表示するためのHTMLテーブルの開始タグを作成します。

---

```ruby
        calendar << "<tr><th>#</th><th>題名</th><th>開始日</th><th>期日</th><th>状態</th><th>進捗率</th></tr>"
```
- **説明**: テーブルのヘッダー行を追加します。
  - **列名**: タスクID、題名、開始日、期日、状態、進捗率。
  - ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/1eebbead-a549-f5eb-e232-e992849a916a.png)


---

```ruby
        issues.each do |issue|
```
- **説明**: 取得したタスク（`issues`）を1件ずつ処理します。

---

```ruby
          days_info = if issue.due_date
```
- **説明**: タスクの期日が設定されているか確認します。

---

```ruby
            days_left = (issue.due_date - Date.today).to_i
```
- **説明**: 今日の日付を基準に、期日までの日数を計算します。

---

```ruby
            if days_left > 0
              "期日まで #{days_left}日"
```
- **説明**: 期日が将来の場合、残りの日数を表示します。

---

```ruby
            elsif days_left == 0
              "今日が期日"
```
- **説明**: 期日が今日の場合、「今日が期日」というメッセージを表示します。

---

```ruby
            else
              "<font color='red'>#{days_left.abs}日 遅れ</font>"
```
- **説明**: 期日が過去の場合、遅延日数を赤字で表示します。

---

```ruby
            end
          else
            "期日未設定"
```
- **説明**: 期日が設定されていない場合、「期日未設定」というメッセージを表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/8d1cebef-095b-6b70-185f-09fba2fa8696.png)

---

```ruby
          calendar << "<tr>"
```
- **説明**: 新しいテーブル行を開始します。

---

```ruby
          calendar << "<td>#{link_to("##{issue.id}", issue_path(issue))}</td>"
```
- **説明**: タスクIDを表示し、クリックするとそのタスク詳細ページに移動できるリンクを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/c80ccc15-3fb7-5b65-b053-3c14d8b27c09.png)

---

```ruby
          calendar << "<td>#{issue.subject}</td>"
```
- **説明**: タスクの題名（`subject`）を表示します。

---

```ruby
          calendar << "<td>#{issue.start_date || 'N/A'}</td>"
```
- **説明**: タスクの開始日を表示します。開始日が未設定の場合は「N/A」を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/3936266d-2708-4d1d-dea4-d9562cf3dafd.png)

---

```ruby
          calendar << "<td>#{issue.due_date || 'N/A'}</td>"
```
- **説明**: タスクの期日を表示します。期日が未設定の場合は「N/A」を表示します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/d8a63265-4145-04d4-59f4-f789f659e618.png)

---

```ruby
          calendar << "<td>#{days_info}</td>"
```
- **説明**: 計算した期日情報（残り日数、遅延など）を表示します。

---

```ruby
          calendar << "<td>#{issue.done_ratio}%</td>"
```
- **説明**: タスクの進捗率（`done_ratio`）をパーセントで表示します。

---

```ruby
          calendar << "</tr>"
```
- **説明**: テーブル行の終了タグを追加します。

---

```ruby
        end
```
- **説明**: タスクごとの繰り返し処理を終了します。

---

```ruby
        calendar << "</table>"
```
- **説明**: HTMLテーブルの終了タグを追加します。

---

```ruby
        calendar.html_safe
```
- **説明**: HTMLの内容をそのまま出力するよう指定します（エスケープを無効化）。

---

```ruby
      else
        "タスクがありません。"
```
- **説明**: 該当するタスクがない場合のメッセージを返します。

---

```ruby
    else
      "User not found."
```
- **説明**: ユーザーが見つからない場合のエラーメッセージを返します。

---

```ruby
  end
end
```
- **説明**: マクロ定義の終了部分です。












---

### 2. **マクロの使い方:**

wikiページで下記の形式でwikiマクロを実行します。
   
   ```ruby
    {{user_tasks(username)}}
   ```

   - usernameに表示させたいユーザーの「ログインID」をを引数として渡します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/7977be8d-ab6a-7212-9d18-6d5ee40aeb2c.png)

下図のようにwikiマクロの実行結果が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/5355a71b-f6f5-cb7f-97d1-b27d7b7f243d.png)

「＃」欄のチケット番号をクリックすると、該当のチケットの詳細ページに移動できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3633321/054baeb6-72c6-4b8d-8763-a5f47ea2ce77.png)

* * *
## 感想

* wikiマクロ登録用のプラグインがあれば、簡単にwikiマクロを登録できることが分かります。
* 特定のユーザーが担当しているチケットの開始日、期日、状態、進捗率を一覧で確認することができます。
* 特定のユーザーが担当しているチケットの取得など、Redmineプラグインで必要な要素技術の習得に寄与します。
* 該当のチケットの詳細ページに簡単に移動することが可能。
* 引数としてプロジェクト情報は与えていないため、プロジェクトに関係なく該当ユーザーが担当している全てのチケットが表示されてしまいます。セキュリティ上、よろしくないので、引数にプロジェクトを指定して、該当プロジェクトでのみの、特定のユーザーのチケット情報が表示されるように、今後、改善の余地はある。


* * *
### この記事の作成者の紹介
* * *
山崎進
* Redmine、Jquery、JavaScript,Rails、Ruby、SQL、VBA、RPAの開発を行なっています。
* 自動化、業務の効率化に高い関心があります。
* 下記の媒体で情報を発信しています。Redmineのプラグインの開発などに対応が可能ですので、お気軽にご連絡ください。

　* Qiita：https://qiita.com/ankosoft
　* Twitter：https://twitter.com/yamasaki24
　* Redmine Advent Calendarで記事投稿
　* redmine.tokyoで講演多数
　* Redmine Japan Vol.1 前夜祭、Redmine Japan Vol.3で講演
　* https://ankosoft.co.jp/blog/
　* https://technology.ankosoft.co.jp/

* * *
### 関連記事（2024年のRedmine Advent Calendarの記事です。）

 *　[Redmine wikiマクロを作成する方法１](https://qiita.com/yam_asaki/items/1dfd349e078fc6d0f764)

 *　[Redmine wikiマクロを作成する方法２（完了チケットの割合をグラフで表示）](https://qiita.com/yam_asaki/items/5e09143f93104c5590a1)

 *　[Redmine wikiマクロを作成する方法３（ステータスごとのチケットの割合をグラフで表示）](https://qiita.com/yam_asaki/items/ff108e081dc421fe2b10)

 *　[Redmine wikiマクロを作成する方法４（ステータスごとのチケットの割合を一つのグラフで表示）](https://qiita.com/yam_asaki/items/d0f0bba1b0caa892bd46)

 *　[Redmine wikiマクロを作成する方法５（特定のユーザーのチケット状態の確認）](https://qiita.com/yam_asaki/items/4138dc71505c7c33f63f)

 *　[Redmine wikiマクロを作成する方法６（プロジェクトに所属する全てのユーザーのチケット状態の確認）](https://qiita.com/yam_asaki/items/e80f9252a50caee14f1d)

### 関連記事（2023年のRedmine Advent Calendarの記事です。）

 *　[JqueryでRedmineのメニューにアイコンを入れる方法](https://qiita.com/yam_asaki/items/32097598cb0a653dd916)

 *　[JqueryでRedmineのメニューを閉じたり開いたりする方法](https://qiita.com/yam_asaki/items/5ac4a1127beeed53059c)

　*　[JqueryでRedmineの「活動ページ」をもっと便利に(タイトルを開閉したり、曜日を入れたり)](https://qiita.com/yam_asaki/items/718513b52b30b30f65bc)

　*　[JqueryでRedmineの「活動ページ」をもっと便利に②(フィルタリング機能と移動機能)](https://qiita.com/yam_asaki/items/2428610fd89bc73ce0ab)

　*　[JqueryでRedmineの「wikiページ」をもっと便利に(フィルタリング機能と移動機能)](https://qiita.com/yam_asaki/items/a6a32c45dbbc72a28836)

　*　[JqueryでRedmineの「チケットページ」をもっと便利に(年ごと、月ごと、四半期ごとの集計機能の開発)](https://qiita.com/yam_asaki/items/176d07588793b3e66b5d)

　*　[RedmineのパスワードやログインIDを忘れた時の復旧方法](https://qiita.com/yam_asaki/items/6881c92b30dc85f589ad)

　*　[「rails console」を使ってRedmine上のスケジュールを一括変更する方法](https://qiita.com/yam_asaki/items/1d41dc8653773f3522e6)