用 Amazon SES 發 Trac 通知信的問題

Trac 在發 ticket 的通知信時,會定義自己的 Message-ID,另外後續變更的通知信件會增加 References 欄位,讓 mail client 可以配對起來 (變成一個 thread)。

Amazon SES 會把原來的 Message-ID 改掉,使用自己的 Message-ID 欄位,可是 References 欄位仍然維持不變... 這就導致 mail client 無法將第一封信 (只有被改過的 Message-ID) 與後續的信件 (References 所指到的信件不存在) 配對起來,只剩下後續的信件因為有相同的 References,所以 mail client 可以正確的配對起來。

所以我就決定生一個 workaround plugin,只要是沒有 References 的信件 (像是每張 ticket 的第一封信),就從 Message-ID 複製一份到 References 裡,這樣就可以讓後續的通知信件與第一封也連結起來了。另外評估這個 workaround 的副作用應該還好,所以就不判斷是不是 ticket 的通知信了...

這就是 trac-references-mail-decorator 這個套件的由來...

Trac 1.4

剛剛看到 Trac 出了 1.4 的消息,雖然還是在用 Python 2:「Release Notes for Trac 1.4 Jinja Release」。

其中一個比較大的改變是 template engine 換掉了,從 Edgewall 自家的 Genshi 換到 Jinja2 上,目前看起來兩者都可以用,但可以預期現有的 template 要找時間換過去:「5 times speed-up when rendering query results, thanks to the migration from Genshi to Jinja2.」。

其他的改變應該還好,找個週末來把自己的 Trac 備份起來測試好了...

在手機上看 Trac 的套件

這邊講的是 Safari 這些瀏覽器看 Trac,而不是講 app...

這次從高雄回來,在高鐵上想說用手機看看 Trac,發現桌機版的界面是會動,但在手機上不太好用,所以找看看有什麼套件可以改善...

回到家後找到 BlueFlatTheme 這套 (需要透過 ThemeEnginePlugin 啟用),標語是「A responsive, flat, blue theme using Bootstrap」,拿官方的 screenshot 可以看出來有特地為了寬度比較窄的情況調整:

裝好後用手機測了一下,還是有不滿意的地方,不過改善不少了,先這樣撐著...

在 DHCP 的情境下強制指定 DNS servers

我在 Vultr 上的 Trac 自動開票程式有時候會爛掉,沒把票開出來,把 stderr 輸出到檔案後發現是找不到 hostname:

socket.gaierror: [Errno -3] Temporary failure in name resolution

看了看 /etc/resolv.conf 發現系統使用的 DNS server 設定是透過 DHCP 取得設定的。但 Vultr 只有提供一組 DNS server,當查不到東西時就爆掉了... 所以找了一下,看到「How to override the DHCP-provided nameserver?」這篇,但裡面是用「增加到前面的方式」,跟我想要改成只用 1.1.1.11.0.0.1 不太一樣。

知道目錄後拿關鍵字去 dhclient.conf 的 manpage 裡面找,就可以看到四種設定方式:

        default [ option declaration ] ;
        supersede [ option declaration ] ;
        prepend [ option declaration ] ;
        append [ option declaration ] ;

這四組看名字就大概知道用途了。接下來就是把對應的 interface 查出來以後,用 supersede 就搞定了:

    supersede domain-name-servers 1.1.1.1, 1.0.0.1;

重開機測試可以確認 /etc/resolv.conf 的內容改變了。接下來再來觀察看看還會不會有狀況...

DefaultCcPlugin 改 Component 不會增加 Cc 列表的問題...

TracDefaultCcPlugin 裡有個很喜歡用的 feature:改 component 後會自動增加該 component 的 cc list。但這在 Changeset 13747 被「修正」掉了:

0.3dev: Only append to CC field when ticket is created. Fixes #11624.
Previously the CC field would be modified on Preview and during any ticket change, however these would often go undetected since the field is de-duplicated on save.

而這個 plugin 還是用 Subversion 管理,本來找了一堆 svn2git 的工具,後來發現 Git 所以靠 git-svn 拉下來再改,然後再丟出來:「gslin/defaultccplugin」。

Trac 關票時的資訊...

Trac 關票時一般都是由開票的人關 (i.e. Reporter),今天遇到的情況是這樣,在關票時的畫面上你會不知道是誰開的:

只要往上一點拉就會看到 Reporter 資訊 XD 這通常會發生在螢幕沒打直的人,直接拉到最下方的情況 XD

試著用 CSS 的 position: sticky 但抓不太到要的效果,決定還是開 jQuery 下去解決 XD

        // Copy reporter information to action section
        if ($('#action_resolve_resolve_resolution').length > 0) {
            var reporter = $('#h_reporter').parent().find('.trac-author, .trac-author-user')[0].outerHTML;

            $('#action_resolve_resolve_resolution').each(function(){
                $(this).parent().append('<span class="hint">(This ticket is created by ' + reporter + ')');
            });
        }

當下寫得很隨性,之後也許會再改... (會更新到「Trac - Gea-Suan Lin's Wiki」這邊)

Trac 的 DuplicateTicketSearchPlugin

DuplicateTicketSearchPluginTrac 的 plugin,在開新票時會搜尋系統內可能重複開過的票給出建議。

之前在寫 wiki 上的「Trac」條目時沒寫到,大概是最早的時候都沒裝,後來有人找出來要我裝的東西,所以印象沒那麼深刻。剛剛是在找 Trac + Elasticsearch 有沒有現成的方案可以搭,結果先看到這個...

產生的效果是這樣,在改變 summary 後會出現 (focus 從 summary 移開時):

當然就算裝了還是難免會重複開 (尤其組織夠大的時候),但算是有幫助的東西...

Trac 1.2 上惡搞 TracTicketReferencePlugin 讓他會動...

TracTicketReferencePlugin 是個 Trac 上設定 ticket 之間關聯性的 plugin,與子母票有比較強烈的關係不同,有些人喜歡把相關的資料都掛在這邊。先前用都是在 Trac 1.0 上用,也沒什麼問題,最近在 Trac 1.2 上跑發現直接有 js error...

原因是 TracTicketReferencePlugin 用到 jQuery.live(),而這個函式在 jQuery 1.7 被宣告 deprecated,在 jQuery 1.9 被正式拔掉了。而 Trac 1.0 用的是 jQuery 1.7,所以不會有問題;Trac 1.2 用的是 jQuery 1.12,於是就爛掉了...

剛好就是昨天,有人在作者的 repository 上發 issue 出來 (另外也提供了 patch):「t2y / trac.plugins.ticketref / issues / #9 - JavaScript errors with Trac 1.2 — Bitbucket」。雖然 patch 本身不算難,但我實在懶的查 Mercurial 的操作,於是決定用 workaround 解...

想法是讓 jQuery.live() 會動,這點在 jQuery 官方出的 Migrate 就可以達到 (需要用 1.4.1 版,而不是 3.0.1 版),於是第一步就是在 site.html 內直接先下手為強,讀 jQuery 後馬上讀 Migrate:

  <!--! Add site-specific style sheet -->
  <head py:match="head" py:attrs="select('@*')">
    <script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
    <script src="https://code.jquery.com/jquery-migrate-1.4.1.min.js"></script>
    ${select('*|comment()|text()')}

但 Trac 還是會再載入一次的 jQuery 而蓋過去,所以我們要讓 Trac 不會載入,在 trac.ini 內的 jquery_location 設定讓他讀一個空的 js 檔:

jquery_location = site/null.js

然後生一個空的 trac/htdocs/null.js 讓他讀。

最後開一張票追蹤,看什麼時候官方放新版,再把這串 workaround 拔掉...

在 nginx 環境中把 Trac 裝到子目錄下的設法

以前的「Nginx + FastCGI + Trac」提到給的範例是把 Trac 裝在 / 下的方法。如果是裝在 /trac 或是其他路徑時就需要修改了。

一開始試著改會出現這樣的錯誤:

No handler matched request to /trac/report/7

然後研究調整後,發現 Trac 純粹是吃 FastCGI 給的參數去判斷要怎麼處理 url routing,在 trac.ini 內 url 相關參數主要還是用在其他地方... (像是信件通知時用的 url)

首先是把檔案簡化,這是 2016 年寫的:

    location / {
        auth_basic "trac realm";
        auth_basic_user_file /srv/domain.example.com/.htpasswd;

        include fastcgi.conf;
        fastcgi_param AUTH_USER $remote_user;
        fastcgi_param HTTPS on;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        fastcgi_param REMOTE_USER $remote_user;
        fastcgi_param SCRIPT_NAME "";
        fastcgi_pass unix:/var/run/trac/trac.sock;
    }

發現現在 fastcgi.conf 內都會處理 HTTPS 了,所以拿掉 HTTPS 的處理,然後把 location 的判斷改用 regex 去抓 /trac 後的東西,所以先變成這樣:

    location ~ /trac(/.*) {
        auth_basic "trac realm";
        auth_basic_user_file /srv/domain.example.com/.htpasswd;

        include fastcgi.conf;
        fastcgi_param AUTH_USER $remote_user;
        fastcgi_param PATH_INFO $fastcgi_script_name;
        fastcgi_param REMOTE_USER $remote_user;
        fastcgi_param SCRIPT_NAME "";
        fastcgi_pass unix:/var/run/trac/trac.sock;
    }

最後是把 PATH_INFO 改傳 $1 (在 / 的情境下 $fastcgi_script_name 剛好就會是 routing 用的 PATH_INFO 資訊,所以當時直接拿來用),把 SCRIPT_NAME 改成 /trac

也就是跟 Trac 說基底在 /trac,後面的路徑才是你的 routing engine 要處理的東西,所以變成:

    location ~ /trac(/.*) {
        auth_basic "trac realm";
        auth_basic_user_file /srv/domain.example.com/.htpasswd;

        include fastcgi.conf;
        fastcgi_param AUTH_USER $remote_user;
        fastcgi_param PATH_INFO $1;
        fastcgi_param REMOTE_USER $remote_user;
        fastcgi_param SCRIPT_NAME "/trac";
        fastcgi_pass unix:/var/run/trac/trac.sock;
    }

沒寫下來就會花不少時間重新摸...