« workflowの図化における日本語 | Main | XML-RPC Pluginで関数を追加する »

2008.09.19

XML-RPC Pluginでチケット作成日時を指定する

 Trac以外で管理している修正依頼等をXML-RPC Pluginで取り込む場合、そのままの状態だとチケットの作成日時はXML-RPCで実際に取り込んだ日時になってしまいます。ただ、場合によっては、初期の作成日時(Trac以外で管理している際の作成日時)で取り込みたいというような場合も。

 Tracで定義されているクラスの関数(ticket/model.py ファイル内の insert)を見てみると、引数にwhen=Noneと定義されており、それがセットされている場合はその日時を用いてチケットを作成するようになっているようです。ってことは、その値をセットしてあげることができれば、好きな作成日時のチケットを作成することができるようになるはず・・・。
 ってことで、XML-RPC Pluginの r3074 のソースを元に手を加えてみました。

+++ xmlrpcplugin/trunk/tracrpc/util.py
@@ -5,6 +5,10 @@
     """ Convert xmlrpclib.DateTime string representation to UNIX timestamp. """
     return time.mktime(time.strptime('%s UTC' % datetime.value, '%Y%m%dT%H:%M:%S %Z')) - time.timezone

+def to_timestamp2(datetime):
+    """ Convert xmlrpclib.DateTime string representation to UNIX timestamp. """
+    return time.mktime(time.strptime('%s UTC' % datetime.value, '%Y%m%dT%H:%M:%S %Z'))
+
 def to_datetime(dt):
     """ Convert a datetime.datetime object to a xmlrpclib DateTime object """
     return xmlrpclib.DateTime(dt.utctimetuple())
\ No newline at end of file

+++ xmlrpcplugin/trunk/tracrpc/ticket.py
@@ -2,7 +2,7 @@
 from trac.core import *
 from trac.perm import PermissionCache
 from tracrpc.api import IXMLRPCHandler, expose_rpc
-from tracrpc.util import to_timestamp, to_datetime
+from tracrpc.util import to_timestamp, to_datetime, to_timestamp2
 import trac.ticket.model as model
 import trac.ticket.query as query
 from trac.ticket.api import TicketSystem
@@ -28,14 +28,16 @@
         yield ('TICKET_VIEW', ((list, xmlrpclib.DateTime),), self.getRecentChanges)
         yield ('TICKET_VIEW', ((list, int),), self.getAvailableActions)
         yield ('TICKET_VIEW', ((list, int),), self.get)
-        yield ('TICKET_CREATE', ((int, str, str), (int, str, str, dict), (int, str, str, dict, bool)), self.create)
-        yield ('TICKET_ADMIN', ((list, int, str), (list, int, str, dict), (list, int, str, dict, bool)), self.update)
+        yield ('TICKET_CREATE', ((int, str, str), (int, str, str, dict), (int, str, str, dict, bool), (int, str, str, dict, bool, xmlrpclib.DateTime)), self.create)
+        yield ('TICKET_ADMIN', ((list, int, str), (list, int, str, dict), (list, int, str, dict, bool), (list, int, str, dict, bool, xmlrpclib.DateTime)), self.update)
         yield ('TICKET_ADMIN', ((None, int),), self.delete)
         yield ('TICKET_VIEW', ((dict, int), (dict, int, int)), self.changeLog)
         yield ('TICKET_VIEW', ((list, int),), self.listAttachments)
         yield ('TICKET_VIEW', ((xmlrpclib.Binary, int, str),), self.getAttachment)
         yield ('TICKET_APPEND',
-                 ((str, int, str, str, xmlrpclib.Binary, bool),
+                 ((str, int, str, str, xmlrpclib.Binary, bool, str, xmlrpclib.DateTime),
+                 (str, int, str, str, xmlrpclib.Binary, bool, str),
+                 (str, int, str, str, xmlrpclib.Binary, bool),
                 (str, int, str, str, xmlrpclib.Binary)),
                self.putAttachment)
         yield ('TICKET_ADMIN', ((bool, int, str),), self.deleteAttachment)
@@ -74,7 +76,7 @@
         return (t.id, to_datetime(t.time_created),
                 to_datetime(t.time_changed), t.values)

-    def create(self, req, summary, description, attributes = {}, notify=False):
+    def create(self, req, summary, description, attributes = {}, notify=False, created=None):
         """ Create a new ticket, returning the ticket ID. """
         t = model.Ticket(self.env)
         t['status'] = 'new'
@@ -83,7 +85,10 @@
         t['reporter'] = req.authname or 'anonymous'
         for k, v in attributes.iteritems():
             t[k] = v
-        t.insert()
+        if created:
+            t.insert(datetime.fromtimestamp(to_timestamp2(created), utc))
+        else:
+            t.insert()

         if notify:
             try:
@@ -95,14 +100,24 @@

         return t.id

-    def update(self, req, id, comment, attributes = {}, notify=False):
+    def update(self, req, id, comment, attributes = {}, notify=False, updated=None):
         """ Update a ticket, returning the new ticket in the same form as getTicket(). """
-        now = datetime.now(utc)
+        if updated:
+            now = datetime.fromtimestamp(to_timestamp2(updated), utc)
+        else:
+            now = datetime.now(utc)

+        author = req.authname or 'anonymous'
+    if attributes.has_key('author'):
+            author = attributes['author']
+            del attributes['author']
         t = model.Ticket(self.env, id)
         for k, v in attributes.iteritems():
             t[k] = v
-        t.save_changes(req.authname or 'anonymous', comment)
+        if updated:
+            t.save_changes(author, comment, datetime.fromtimestamp(to_timestamp2(updated), utc))
+        else:
+            t.save_changes(author, comment)

         if notify:
             try:
@@ -138,7 +153,7 @@
         attachment = Attachment(self.env, 'ticket', ticket, filename)
         return xmlrpclib.Binary(attachment.open().read())

-    def putAttachment(self, req, ticket, filename, description, data, replace=True):
+    def putAttachment(self, req, ticket, filename, description, data, replace=True, author=None, updated=None):
         """ Add an attachment, optionally (and defaulting to) overwriting an
         existing one. Returns filename."""
         if not model.Ticket(self.env, ticket).exists:
@@ -150,9 +165,15 @@
             except TracError:
                 pass
         attachment = Attachment(self.env, 'ticket', ticket)
-        attachment.author = req.authname or 'anonymous'
+        if author:
+            attachment.author = author
+        else:
+            attachment.author = req.authname or 'anonymous'
         attachment.description = description
-        attachment.insert(filename, StringIO(data.data), len(data.data))
+        if updated:
+            attachment.insert(filename, StringIO(data.data), len(data.data), to_timestamp2(updated))
+        else:
+            attachment.insert(filename, StringIO(data.data), len(data.data))
         return attachment.filename

     def deleteAttachment(self, req, ticket, filename):

 ちなみに、ついでにticket.updateおよびticket.putAttachmentも同様に改造してみました(^^; また、update/putAttachmentにおいては、authorも明示的に指定できるようにしています。

ticket.create => booleanの引数の次にDateを指定して呼び出すと、チケットの作成日がその日時になります。
ticket.update => booleanの引数の次にDateを指定して呼び出すと、チケットの更新日がその日時になります。また、構造体(Javaの場合はMap)に対してauthorというキーで値をセットしておくと、それをauthorとして採用します。
ticket.putAttachment => booleanの引数に続けて、String、Dateを指定して呼び出すと、それぞれauthor、(添付ファイルの)登録日時としてセットされます。

 なお、チケットの更新の際は、日時の情報もpkeyに含まれていたような気がしますので、明示的に日時を指定する場合はその点に注意が必要かも知れません。

#Pythonの日付に関する取り扱いがよくわかっていないので、とりあえず動く状態での修正です。もしかしたら、もっときれいな書き方があるのかも・・・(特に、to_timestamp2 の定義など)。

※2008/9/21 修正&補足
update処理の際のauthorチェックを修正(authorが指定されているかどうかはhas_key('author')で行わなければならない)。サーバの設定(?)に寄っては、to_timestamp2は不要なようです(タイムゾーンを反映させればOK)。このあたりに関しては、勉強不足なのでよくわかっておりません・・・。

|

« workflowの図化における日本語 | Main | XML-RPC Pluginで関数を追加する »

Subversion・Trac・etc.」カテゴリの記事

Comments

Post a comment



(Not displayed with comment.)


Comments are moderated, and will not appear on this weblog until the author has approved them.



TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/3959/42509206

Listed below are links to weblogs that reference XML-RPC Pluginでチケット作成日時を指定する:

« workflowの図化における日本語 | Main | XML-RPC Pluginで関数を追加する »