「Trac」:修訂間差異

出自Gea-Suan Lin's Wiki
跳至導覽 跳至搜尋
本頁面具有訪問限制。如果您看見此訊息,這代表您沒有訪問本頁面的權限。
行 74: 行 74:
* [https://trac-hacks.org/wiki/AccountManagerPlugin AccountManagerPlugin – Trac Hacks - Plugins Macros etc.]
* [https://trac-hacks.org/wiki/AccountManagerPlugin AccountManagerPlugin – Trac Hacks - Plugins Macros etc.]
** 可以吃HTML Form Login,而不侷限在HTTP authentication。
** 可以吃HTML Form Login,而不侷限在HTTP authentication。
* [https://trac-hacks.org/wiki/BlueFlatTheme BlueFlatTheme – Trac Hacks - Plugins Macros etc.]
** 目前Trac上少數支援Responsive Design的Theme,需要使用ThemeEnginePlugin安裝並啟用。
* [https://trac-hacks.org/wiki/DuplicateTicketSearchPlugin DuplicateTicketSearchPlugin – Trac Hacks - Plugins Macros etc.]
* [https://trac-hacks.org/wiki/DuplicateTicketSearchPlugin DuplicateTicketSearchPlugin – Trac Hacks - Plugins Macros etc.]
** 在開新票時可以拉出有哪些是可能重複的票(尤其是已經關掉的票)。
** 在開新票時可以拉出有哪些是可能重複的票(尤其是已經關掉的票)。
行 82: 行 84:
* [https://trac-hacks.org/wiki/SubticketsPlugin SubticketsPlugin – Trac Hacks - Plugins Macros etc.]
* [https://trac-hacks.org/wiki/SubticketsPlugin SubticketsPlugin – Trac Hacks - Plugins Macros etc.]
** 子母票的延伸套件,基本上是必備項目。
** 子母票的延伸套件,基本上是必備項目。
* [https://trac-hacks.org/wiki/ThemeEnginePlugin ThemeEnginePlugin – Trac Hacks - Plugins Macros etc.]
** Theme的套件管理工具,配合BlueFlatTheme用的。
* [https://trac-hacks.org/wiki/TracCronPlugin TracCronPlugin – Trac Hacks - Plugins Macros etc.]
* [https://trac-hacks.org/wiki/TracCronPlugin TracCronPlugin – Trac Hacks - Plugins Macros etc.]
** 定時跑任務,但其實沒很好用... 目前主要是拿來每天寄信通知有哪些票過期。
** 定時跑任務,但其實沒很好用... 目前主要是拿來每天寄信通知有哪些票過期。

於 2018年11月4日 (日) 15:04 的修訂

Trac是一套問題追蹤系統英語:Issue tracking system)。

簡介

優點

  • 簡單,專注在事情的記錄上,而不是限制行為上。

缺點

  • 目前還是不支援Python 3。

安裝

我是將Python裝在www-data這個使用者的pyenv裡面(權限會是www-data:www-data)。在裝完Python後,用pip安裝以下套件:

$ pip install Trac
$ pip install ​Pygments
$ pip install mysql-python

使用MySQL作為後端資料庫時,建議用utf8mb4作為基礎,這樣資料庫可以存所有範圍的Unicode字元[1],另外建立獨立的使用者供Trac使用:

CREATE DATABASE trac DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
GRANT ALL ON trac.* TO `trac`@`localhost` IDENTIFIED BY 'password_here';

這樣在安裝Trac時的連線設定會是mysql://trac:password_here@localhost/trac(需要自己修改對應欄位)。

在安裝套件時,軟體本體常常會放在Subversion的伺服器內,在透過pip或是easy_install時會呼叫Subversion,所以會需要安裝對應的軟體:

# apt install subversion

另外要建立目錄,並且讓Trac可以寫入:

# mkdir trac/files
# chown www-data:www-data trac/files

然後是Trac的FastCGI檔案,放在Trac的project目錄下,並且用chmod 755 trac.fcgi改成可執行:

#!/usr/bin/env python

import os
from trac.web.main import dispatch_request
import trac.web._fcgi

num = 2
sockaddr = '/var/run/trac/trac.sock'
os.environ['TRAC_ENV'] = os.path.dirname(__file__)

fcgiserv = trac.web._fcgi.WSGIServer(dispatch_request, bindAddress = sockaddr, umask = 7)

num -= 1
while num > 0:
    num -= 1
    if 0 == os.fork():
        break

fcgiserv.run()

另外Systemd的設定檔讓Trac在開機時以FastCGI模式跑起來,這個檔案放在/lib/systemd/system/rsyslog.service並連結到/etc/systemd/system/multi-user.target.wants/trac.service下(要記得把裡面的/srv/trac.example.com/trac/改成自己的目錄:

[Unit]
Description=trac fcgi daemon

[Service]
Type=simple
ExecStartPre=/bin/sh -c "/bin/mkdir -p /var/run/trac; /bin/chown www-data:www-data /var/run/trac; /bin/chmod 0755 /var/run/trac"
ExecStart=/bin/su - www-data -c "exec /srv/trac.example.com/trac/trac.fcgi"

[Install]
WantedBy=multi-user.target

目前有安裝的

除了基本安裝外,還會安裝這些套件:

目前Trac 1.2版的安裝方式是:

#!/bin/bash
pip install svn+https://trac-hacks.org/svn/duplicateticketsearchplugin/trunk/
pip install svn+https://trac-hacks.org/svn/graphvizplugin/branches/1.2/
pip install git+https://github.com/trac-hacks/trac-subtickets-plugin.git
pip install TracCronPlugin
pip install svn+https://trac-hacks.org/svn/tracwysiwygplugin/0.12/
pip install TracXMLRPC

以前有安裝的

以前會安裝,但現在因為自己用而沒有裝上(沒有需求或是不想裝):

設定

權限

Trac預設的權限設定過於嚴格,只給內部使用的情境下,建議對authenticated群組加上:

  • TICKET_EDIT_CC
  • TICKET_EDIT_DESCRIPTION

trac.ini

我自己的Report不想分頁(預設是一頁100筆),所以設為:

[report]
items_per_page = 0

讓系統吃code.jquery.com所提供的jQuery以及jQuery UI[2],稍微降低伺服器的負載,另外也有機會與外部網站共用cache。目前的Trac 1.2.2版本可以這樣設:

[trac]
jquery_location = https://code.jquery.com/jquery-1.12.4.min.js
jquery_ui_location = https://code.jquery.com/ui/1.12.1/jquery-ui.min.js
jquery_ui_theme_location = https://code.jquery.com/ui/1.12.1/themes/start/jquery-ui.css

另外因為我們不太用Trac內建的Wiki,但又關不掉,所以只能針對沒找到的頁面就不要產生連結了:

[wiki]
ignore_missing_pages = enabled

site.html

templates/site.html裡做了一些事情進行客製化。

對於外部引用,不要 洩漏Referrer

<head>
    <meta name="referrer" content="no-referrer" />
    ...
</head>

CSS

  • 全部使用sans-serif字型。
  • 修正button因為CSS效果而有時會按不到的問題。
  • 針對code block內一行過長時自動換行。
  • 針對今天到期與過期的票用不同的標示標出(配合下方的JavaScript)。
  • 將已經關掉的票變淡(配合下方的JavaScript)。
  • 讓編輯區域使用等寬字型。
  • 讓可用範圍變寬。
  • 讓圖片不要超過螢幕寬度。
    <style type="text/css">
    <!--
    body, th, tr {
        font-family: sans-serif;
    }
    input[type=button]:active, input[type=submit]:active,
    input[type=reset]:active {
        position: relative;
        top: 0;
        left: 0;
    }
    pre {
        white-space: pre-wrap;
    }
    table.tickets tr.duedate_overdue {
        font-weight: bold;
    }
    table.tickets tr.duedate_today {
        border: 2px solid;
    }
    table.subtickets tr.ticket_closed, .closed.ticket {
        opacity: 0.5;
    }
    textarea {
        font-family: monospace;
    }
    #content.ticket {
        width: 78em;
    }
    #main img {
        max-width: 100%;
    }
    -->
    </style>

JavaScript

  • 用JavaScript針對今天到期以及過期的票增加CSS。
  • 將新票裡的Due Date改為零點零分零秒。
  • 增加button,讓關票可以直接點擊。
  • 將票裡的attachments與modify內容展開。
  • 將開票人的資訊放到Action欄位裡,比較好確認這張票的情況。
  • 將日曆選擇器中,關閉動畫效果[3],另外將每週的第一天設為星期天[3],並且允許選擇其他月份的日期[3]

head的地方先加入strftime套件,後面會用到:

    <script src="https://cdn.jsdelivr.net/npm/strftime@0.10.0/strftime.min.js"></script>

這段程式碼則會放在</body>結尾前:

    <script>
    <!--
    // Run immediately.
    (function($) {
        // Due date css handling
        var d = new Date();
        var today = (new Date(d.getTime() - d.getTimezoneOffset() * 60000)).toISOString().slice(0, 10);
        document.querySelectorAll('table.tickets td.due_date').forEach(function(el) {
            var due = el.innerText.trim();
            if (due < today) {
                el.parentElement.classList.add('duedate_overdue');
            } else if (due === today) {
                el.parentElement.classList.add('duedate_today');
            }
        });

        // Due date (newticket) set to 00:00:00 (in UTC)
        if ($('form[action$="/newticket#ticket"]').length > 0) {
            do {
                let el = $('#field-due_date');
                let t = el.val();

                if ('Z' === t.slice(-1)) {
                    console.log(t);
                    t = new Date(Date.parse(t) + 86400000);
                    t = strftime('%Y-%m-%dT00:00:00Z', t);
                    el.val(t);
                    break;
                }

                let a = t.match(/\+(\d\d:\d\d)$/);
                if (null !== a) {
                    let tz = a[1];
                    let new_str = 'T' + tz + ':00+' + tz;
                    t = new Date(Date.parse(t) + 86400000);
                    t = strftime('%Y-%m-%d' + new_str, t);
                    el.val(t);
                    break;
                }
            } while (false);
        }

        // Accept & start buttons
        $('#action_accept, #action_start').each(function(){
            var v = $(this).val();

            var that = this;
            var b = $('<button/>').click(function(e){
                var v = $(this).val();
                $(that).click();
                $('#propertyform input[name="submit"]').click();
                e.preventDefault();
            });
            b.attr('value', v).text(v);

            $(this).closest('div').append(b);
        });

        // Resolve with Buttons
        $('#action_resolve_resolve_resolution option').each(function(){
            var v = $(this).val();

            var b = $('<button/>').click( function(e){
                var v = $(this).val();
                $('#action_resolve').click();
                $('#action_resolve_resolve_resolution').attr('disabled', false);
                $('#action_resolve_resolve_resolution').find('option[value="' + v + '"]').attr('selected', 'selected');
                $('#propertyform input[name="submit"]').click();
                e.preventDefault();
            });
            b.attr('value', v).text(v);

            $(this).closest('div').append(b);
        });

        // Closed tickets handling
        $('tr:has(a.closed)').addClass('ticket_closed');

        // 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 + ')</span>');
            });
        }
    })(jQuery);

    // Run after content loaded.
    jQuery(function() {
        // Layout
        jQuery('#attachments').removeClass('collapsed');
        jQuery('#modify').parent().removeClass('collapsed');

        // Datepicker
        if ($.datepicker) {
            $.datepicker.setDefaults({
                firstDay: 0,
                selectOtherMonths: true,
                showAnim: '',
                showOtherMonths: true
            });
        }
    });
    //-->
    </script>

其他

刪除使用者時可能會需要手動到以下表格清除資料(清完後需要重跑Trac,因為Trac會讀出來cache一份),避免autocomplete之類的套件仍然顯示:

  • auth_cookie
  • session
  • session_attribute

著名使用單位

  • Django
  • FFmpeg
  • nginx
  • Tor
  • WebKit
  • WordPress
  • jQuery

相關連結

參考資料

外部連結