\input texinfo @c -*-texinfo-*- @c %**start of header @setfilename rt-liber.info @settitle The rt-liberation Manual @c %**end of header @c History: This manual was started on the 6th of April 2009. Yoni @c Rabkin (yrk@gnu.org) is the primary author. @dircategory Emacs @direntry * rt-liberation: (rt-liber). Emacs Interface to RT @end direntry @copying @copyright{} 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2020 Free Software Foundation, Inc. @quotation Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @end quotation @end copying @c For printed material @titlepage @title The rt-liberation Manual @page @vskip 0pt plus 1filll @insertcopying @end titlepage @contents @c END For printed material @ifnottex @node Top, Introduction, (dir), (dir) @top The rt-liberation Manual This is the Manual for the rt-liberation system @insertcopying @menu * Introduction:: Introduction to rt-liberation. * Installation:: Install rt-liberation on the system. * Configuration:: Setup rt-liberation to work on the system. Using rt-liberation * Queries:: Retrieve particular tickets from the server. * Ticket Browser:: Browse the query results. * Ticket Viewer:: Interface to query results. Extensions * Gnus Integration:: Sending email to the RT server via Gnus. * Tracking Updates:: Keeping up to date with ticket changes. * Batch Operations:: Performing operations on batches of tickets. * Local Storage:: Associate arbitrary data with tickets. Copying and license * Copying:: The GNU General Public License gives you permission to redistribute rt-liberation on certain terms; it also explains that there is no warranty. * The GNU FDL:: The license for this documentation. Indices * Concept Index:: * Function Index:: * Variable Index:: * Keybinding Index:: @detailmenu --- The Detailed Node Listing --- Queries * Query Compiler:: Compiling Emacs Lisp to TicketSQL. * Query Language:: A description of the Sexp-based language. Ticket Browser * Ticket Browser Display:: How tickets are displayed in the browser. * Ticket Browser Sorting:: How tickets are sorted in the browser. * Ticket Browser Filtering:: How to filter tickets out of the browser. * Multiple Ticket Browsers:: More than one ticket browser buffer. @end detailmenu @end menu @end ifnottex @c -------------------------------------------------- @node Introduction @chapter Introduction @cindex introduction rt-liberation is a GNU/Emacs package for working with the Request Tracker (henceforth abbreviated as just ``RT'') software from Best Practical Solutions. RT has an interactive Web interface, a command line interface (the ``RT CLI''), and a REST interface. rt-liberation uses the RT REST interface to communicate with the RT server. rt-liberation allows sending search queries to the RT server, browsing the resulting tickets, viewing the tickets' contents and performing operations on the tickets. @c -------------------------------------------------- @node Installation @chapter Installation @cindex installation rt-liberation is available via GNU ELPA. Invoke @kbd{M-x list-packages} and choose to install the rt-liberation package. If you install rt-liberation manually, by copying the code to your machine, instead you'll need to tell Emacs where to find it, and then tell Emacs to load the package: @lisp (add-to-list 'load-path "/PATH/TO/rt-liberation/") @end lisp @lisp (require 'rt-liberation) @end lisp @c -------------------------------------------------- @node Configuration @chapter Configuration @cindex configuration rt-liberation needs to be configured in your ~/.emacs, an ~/.rt-liber file, or similar. Tell rt-liberation where to find the RT server's REST interface: @lisp (setq rt-liber-rest-url "rt.example.org") @end lisp In order to authenticate with the RT server instance you need to provide credentials. rt-liberation looks for these in the variables @var{rt-liber-rest-username} and @var{rt-liber-rest-password}. You can set these directly: @lisp (setq rt-liber-rest-username "someuser" rt-liber-rest-password "somepassword") @end lisp You can also leave these values unset (@code{nil}), in which case rt-liberation will look for the credentials in a Netrc file via the auth-source library (see: @xref{Top,,, auth, Emacs auth-source}), under the machine name "rt-liberation": @example machine rt-liberation login someuser password somepassword @end example rt-liberation can issue a command to ``take'' a ticket (that is, assign it to yourself). For this the variable @var{rt-liber-username} must be set: @lisp (setq rt-liber-username "someuser") @end lisp rt-liberation can launch a Web browser to visit a ticket. For that to work the base URL needs to be set in @var{rt-liber-base-url}. For example: (setq rt-liber-base-url "https://rt.foo.org/") @c -------------------------------------------------- @node Queries @chapter Queries @cindex queries A typical RT server is meant to manage a large amount of tickets. Much more that would be convenient to view all at once. Instead queries are used to view only a subset of the tickets on the server. rt-liberation has its own Sexp-based query language which maps to RT's TicketSQL language. @menu * Query Compiler:: Compiling Emacs Lisp to TicketSQL. * Query Language:: A description of the Sexp-based language. @end menu @c -------------------------------------------------- @node Query Compiler @section Query Compiler @cindex query compiler In order to browse and view tickets a list of needs to be requested from the RT server. Typically the tickets answer some kind of criteria, for example ``tickets no older than a week owned by me which have \``foobar\'' in their subject line''. In RT these criteria are formulated with ``TicketSQL'' queries; a structured query language specific to RT. rt-liberation provides a query compiler function to compile Emacs Lisp symbolic expressions into TicketSQL. The query compiler supports a number of TicketSQL tokens. @c -------------------------------------------------- @node Query Language @section Query Language @cindex query language rt-liberation's Sexp-based query language covers a portion of the TicketSQL language. Here are some of the supported TicketSQL tokens: Boolean tokens as a means of combining query subsections: ``and'', ``or'', ``not''. LIKE attribute tokens: ``subject'', ``content''. For example here is a query with both Boolean and LIKE tokens: @lisp (rt-liber-compile-query (and (queue "bugs") (content "gnu"))) ==> "Queue = 'bugs' AND Content LIKE 'gnu'" @end lisp We can also express negation (note that the compiler produces "!=" and "NOT LIKE" for negation depending on the context): @lisp (rt-liber-compile-query (and (queue "bugs") (not (owner "Nobody")) (not (content "sprigz")) (status "new"))) ==> "Queue = 'licensing' AND Owner != 'Nobody' \ AND Content NOT LIKE 'sprigz' AND Status = 'new'" @end lisp Attribute tokens which match an attribute to a specific field such as: ``owner'', ``status'' and ``queue''. Temporal tokens which limit the search results to tickets within a certain time interval: ``created'' and ``lastupdated''. Note that temporal keywords such as ``created'' always accept two arguments: BEFORE and AFTER. When either BEFORE or AFTER aren't needed, use NIL instead. One of the advantages of being able to express the TicketSQL queries as Emacs Lisp is to be able to express queries using Emacs Lisp functions. Here is a slightly more involved example to illustrate: @lisp (rt-liber-compile-query (and (queue "bugs") (owner "me@@myaddress.com") (status "open") (lastupdated nil (format-time-string "%Y-%m-%d" (seconds-to-time (- (time-to-seconds (current-time)) (* 60 60 24 7))))))) ==> "Queue = 'bugs' AND Owner = 'me@@myaddress.com' AND Status = 'open' AND LastUpdated > '2009-03-30'" @end lisp Here is an example of how the ticket browser and compiler can be used in function calls: @lisp (defun rt-liber-display-ticket (ticket-id) "Display ticket with TICKET-ID in the ticket-browser." (interactive "MTicket ID: ") (rt-liber-browse-query (rt-liber-compile-query (and (queue "complaints") (id ticket-id))))) @end lisp @c -------------------------------------------------- @node Ticket Browser @chapter Ticket Browser @cindex ticket browser The ticket browser is a special buffer which provides a convenient interface to the results of a server query. The ticket browser can be started by invoking: (rt-liber-browse-query QUERY), where QUERY is a TicketSQL query. The TicketSQL query can be entered manually as a string or as the return value of the query compiler. @deffn Function rt-liber-browse-query QUERY &optional NEW Runs QUERY against the server and launches the browser. If NEW is non-nil then the query results will be displayed in a new buffer, otherwise the query results will override the contents of the existing ticket browser buffer. If NEW is a string then that will be the name of the new buffer. @end deffn The TicketSQL query can be the return value of the query compiler. For example: @lisp (rt-liber-browse-query (rt-liber-compile-query (and (queue "bugs") (content "gnu"))) @end lisp Since the return value of the query compiler is just a TicketSQL string, the following is equivalent: @lisp (rt-liber-browse-query "Queue = 'bugs' AND Content LIKE 'gnu'") @end lisp The ticket browser defines a number of commands: @table @kbd @item q @kindex q (ticket browser) @findex rt-liber-browser-mode-quit Bury the ticket browser buffer. @item n @kindex n (ticket browser) @findex rt-liber-next-ticket-in-browser Move point to the next ticket. @item p @kindex p (ticket browser) @findex rt-liber-previous-ticket-in-browser Move point to the previous ticket. @item RET @kindex RET (ticket browser) @findex rt-liber-display-ticket-at-point Visit the ticket at point in the @xref{Ticket Viewer}. @item g @kindex g (ticket browser) @findex revert-buffer Refresh the contents of the browser buffer. @item G @kindex G (ticket browser) @findex rt-liber-browser-refresh-and-return Refresh the contents of the browser buffer. Return point to the current ticket after the refresh (if possible). @item s @kindex s (ticket browser) @findex rt-liber-browser-mark-as-spam Mark the ticket as spam. @item S @kindex S (ticket browser) @findex rt-liber-multi-delete-spam Delete marked tickets as spam (requires rt-liberation-multi package). @item a @kindex a (ticket browser) @findex rt-liber-browser-assign Assign the ticket to a user. @item r @kindex r (ticket browser) @findex rt-liber-browser-resolve Mark the ticket as ``resolved''. @item o @kindex o (ticket browser) @findex rt-liber-browser-open Mark the ticket as ``open''. @item t @kindex t (ticket browser) @findex rt-liber-browser-take-ticket-at-point Assign the ticket at point to @var{rt-liber-username}. @item SPC @kindex SPC (ticket browser) @findex scroll-up Scroll the text of the ticket browser upward. @item DEL @kindex DEL (ticket browser) @findex scroll-down Scroll the text of the ticket browser downward. @item m @kindex m (ticket browser) @findex rt-liber-browser-move Move the ticket to a different queue. @item P @kindex P (ticket browser) @findex rt-liber-browser-prioritize Set the numerical priority level of the ticket at point. @end table @menu * Ticket Browser Display:: How tickets are displayed in the browser. * Ticket Browser Sorting:: How tickets are sorted in the browser. * Ticket Browser Filtering:: How to filter tickets out of the browser. * Multiple Ticket Browsers:: More than one ticket browser buffer. @end menu @c -------------------------------------------------- @node Ticket Browser Display @section Ticket Browser Display @cindex ticket browser display function The ticket browser displays the tickets in the browser by calling @dfn{rt-liber-ticketlist-browser-redraw-f} which can be changed and customized. Any implementation of @dfn{rt-liber-ticketlist-browser-redraw-f} must leave point at the end of the ticket text. The ticket data itself can be displayed using rt-liberation ticket format string %-sequences: @table @asis @item %i ID number of the ticket in the RT database. @item %s Subject line. @item %c Ticket creation time. The format to display the time is specified in the variable @var{rt-liber-browser-time-format-string}. @item %S Ticket status (``open'', ``new'' etc.) @item %r Whether the ticket is resolved. @item %R Requestor/s @item %C Creator of the ticket. @item %o Owner of the ticket. @item %q The queue originating the ticket. @item %p The numerical priority of the ticket @end table Here is an example implementation of @dfn{rt-liber-ticketlist-browser-redraw-f} showing the use of the %-sequences. Note the use of text properties to add color to ticket text. The use of text properties as opposed to font-locking is meant to ease customization because otherwise any change in ticket display would break the font-locking regular expressions. @lisp (defun rt-liber-ticketlist-browser-redraw-f (ticket) "Display TICKET." (insert (rt-liber-format "[%c] %i" ticket)) (add-text-properties (point-at-bol) (point-at-eol) '(face rt-liber-ticket-face)) (newline) (insert (rt-liber-format " [%S] %s" ticket)) (newline) (insert (rt-liber-format " %o <== %R" ticket))) @end lisp The function @dfn{rt-liber-high-priority-p} can be used to apply a different face or text to a ticket if it is high priority. A ticket is considered high priority if its value is strictly higher than @var{rt-liber-browser-priority-cutoff} @c -------------------------------------------------- @node Ticket Browser Sorting @section Ticket Browser Sorting @cindex ticket browser sorting The tickets in the browser are displayed by default in reverse chronological order. Ticket sorting is done by a call to @dfn{rt-liber-browser-default-sorting-function}. Other sorting orders can be used by binding @dfn{rt-liber-browser-default-sorting-function} to a different function. To ease writing such functions rt-liberation provides two predicate functions to perform comparisons between ticket objects: @defun rt-liber-lex-lessthan-p a b field Return true if A is lexicographically less than B in FIELD. Here is an example of sorting tickets lexicographically by owner name using @dfn{rt-liber-lex-lessthan-p} (note that you can feed @dfn{rt-liber-lex-lessthan-p} a date/time string and it will sort it just fine except that it wouldn't make any sense): @lisp (defun rt-liber-sort-by-owner (ticket-list) "Sort TICKET-LIST lexicographically by owner." (rt-liber-sort-ticket-list ticket-list #'(lambda (a b) (rt-liber-lex-lessthan-p a b "Owner")))) @end lisp @end defun @defun rt-liber-time-lessthan-p a b field Return t if A is chronologically less than B in FIELD. Here is an example of sorting tickets lexicographically by owner name using @dfn{rt-liber-time-lessthan-p} (note that feeding @dfn{rt-liber-time-lessthan-p} anything but a date/time string, in this case ``Created'' contains a date, will result in an error being signaled). @lisp (defun rt-liber-sort-by-time-created (ticket-list) "Sort TICKET-LIST in reverse chronological order." (reverse (rt-liber-sort-ticket-list ticket-list #'(lambda (a b) (rt-liber-time-lessthan-p a b "Created"))))) @end lisp @end defun @c ------------------------------------------------------------------- @node Ticket Browser Filtering @section Ticket Browser Filtering @cindex ticket browser filtering filter The Ticket Browser can also filter out (that is, not display) certain tickets based on particular criteria. This probably shouldn't be used instead of a properly formed RT query, but when used in conjunction with correctly formulated queries it becomes a powerful tool. During ticket display processing the Ticket Browser will call the function pointed to by @var{rt-liber-browser-default-filter-function} on each ticket, passing the function the ticket alist as a single argument. The function is set by default to @dfn{rt-liber-default-filter-f}, which is a function which will display all tickets and filter none. If any tickets are filtered, the Ticket Browser will display the filtered ticket count at the bottom ticket listing. Here is a simple example of how to filter out all of the tickets which have a status of ``deleted''. First we define a custom filter function. Note how it accepts a single argument, which is the ticket alist, and returns nil if the ticket is to be filtered. @lisp (defun rt-liber-browser-deleted-filter (ticket) (not (and ticket (string= (cdr (assoc "Status" ticket)) "deleted")))) @end lisp Then we assign that function to be our default filtering function: @lisp (setq rt-liber-browser-default-filter-function 'rt-liber-browser-deleted-filter) @end lisp @c ------------------------------------------------------------------- @node Multiple Ticket Browsers @section Multiple Ticket Browsers @cindex ticket browser multiple buffer It is sometimes useful to rename the ticket browser buffer to something more informative than the default @var{rt-liber-browser-buffer-name}, especially if there are multiple ticket browsers. Changing a ticket browser's name can be done normally with `rename-buffer', but it is also possible to name the ticket browser when it is created. In the following example two ticket browser buffers will be created displaying the query results and named ``*updated by supervisor*'' and ``*new tickets*'' respectively: @lisp (defun rt-liber-daily-rounds () (interactive) (rt-liber-browse-query (rt-liber-compile-query (and (queue "complaints") (owner "lem.e.tweakit") (status "open") (lastupdatedby "molly.manager"))) "*updated by supervisor*") (rt-liber-browse-query (rt-liber-compile-query (and (queue "complaints") (owner "Nobody") (status "new"))) "*new tickets*")) @end lisp @c -------------------------------------------------- @node Ticket Viewer @chapter Ticket Viewer @cindex ticket viewer The ticket viewer is an interface for viewing the contents of a ticket and for sending answers. The ticket viewer provides key-bindings to help compose emails to send to the RT email interface. The key-bindings for composing email described below are generic, what actually happens when you invoke them depends on the email-backend system you have installed into rt-liberation. @file{rt-liberation-gnus.el} provides integration with Gnus, @xref{Gnus Integration}. @table @kbd @item q @kindex q (ticket viewer) @findex rt-liber-viewer2-mode-quit Bury the ticket viewer buffer. @item n @kindex n (ticket viewer) @findex rt-liber-viewer2-next-section-in Move to the next section in ticket. @item N @kindex N (ticket viewer) @findex rt-liber-viewer2-last-section-in Move to the last section. @item p @kindex p (ticket viewer) @findex rt-liber-viewer2-previous-section-in Move point to the previous section in ticket. @item V @kindex V (ticket viewer) @findex rt-liber-viewer-visit-in-browser Visit the current ticket in a Web browser. @item M @kindex M (ticket viewer) @findex rt-liber-viewer2-answer Compose an answer to the current ticket. The content section around point will be inserted into the email body and commented out. @item C @kindex C (ticket viewer) @findex rt-liber-viewer2-comment Comment on the ticket using the current context @item g @kindex g (ticket viewer) @findex revert-buffer Refresh and redisplay the current ticket. @item SPC @kindex SPC (ticket viewer) @findex scroll-up Scroll text of ticket viewer upward. @item DEL @kindex DEL (ticket viewer) @findex scroll-down Scroll text of ticket viewer downward. @item h @kindex h (ticket viewer) @findex rt-liber-viewer-show-ticket-browser Display the associated ticket in the ticket browser. @end table @c -------------------------------------------------- @node Gnus Integration @chapter Gnus Integration @cindex Gnus Integration The file @file{rt-liberation-gnus.el} implements integration with Gnus for composing emails. To enable the feature, `require' it after loading rt-liberation: @lisp (require 'rt-liberation-gnus) @end lisp In order for rt-liberation-gnus to be useful a few variables need to be specialized. The following is example code which sets these variables. Below is a thorough description of those variables. @lisp (setq rt-liber-gnus-comment-address "our-rtserver-comment@@ourserver.org" rt-liber-gnus-address "our-rtserver@@ourserver.org" rt-liber-gnus-subject-name "ourserver.org") @end lisp @defopt rt-liber-gnus-address @var{rt-liber-gnus-address} is the email address which is configured in the RT server email interface for sending a response to the ticket's requestor. @end defopt @defopt rt-liber-gnus-comment-address @var{rt-liber-gnus-comment-address} is the email address which is configured in the RT server email interface for adding a comment under the ticket in question. @end defopt @defopt rt-liber-gnus-subject-name @var{rt-liber-gnus-subject-name} is a string, typically included at the beginning of the square brackets in the subject. The string is a part of the subject line which helps the RT server recognize the email. @end defopt Gnus posting styles controlled by @var{gnus-posting-styles} can be customized for rt-liberation-gnus by using the variable @var{rt-liber-gnus-p}, which is only non-nil when rt-liberation-gnus launches a Gnus message buffer. Here is example code which uses @var{rt-liber-gnus-p} to override the signature in the default posting style with one special to rt-liberation. Headers can be added and removed in a similar manner. @lisp (setq gnus-posting-styles '((".*" (name "Lemm E. Hackitt") (address "Lemm@@hack.it") (signature-file "~/sig.txt") ("X-Ethics" "Use GNU")) (rt-liber-gnus-p (signature-file "~/rt-liber-sig.txt")))) @end lisp Once rt-liberation-gnus is loaded and customized the key-bindings in the Viewer will be able to call into it, @xref{Ticket Viewer}. @c -------------------------------------------------- @node Tracking Updates @chapter Tracking Updates @cindex Tracking Updates The functions in @file{rt-liberation-update.el} help keep up with updates to the ticket database. To enable the feature, `require' it after loading rt-liberation: @lisp (require 'rt-liberation-update) @end lisp Then set @var{rt-liber-update-default-queue} to be the name of the queue to watch for updates. For example: @lisp (setq rt-liber-update-default-queue "complaints") @end lisp @defun rt-liber-update &optional no-update @code{rt-liber-update} is an interactive function which runs a query against the RT server asking for the tickets which have been updated since the time @code{rt-liber-update} was last run (each time it runs, it leaves a time-stamp). If no time-stamp is found, for instance when you run @code{rt-liber-update} for the first time, today's date is used. With the NO-UPDATE prefix, @code{rt-liber-update} will not update the time-stamp so that the next invocation will produce the same result. @end defun @c -------------------------------------------------- @node Batch Operations @chapter Batch Operations @cindex Batch Operations The extension @file{rt-liberation-multi.el} implements performing batch operations on groups of tickets. It works in two stages: First mark an arbitrary number of tickets within the same buffer then call a batch operation function on them. The batch operation functions work the same way as function which work on single tickets only that they iterate through all of the marked tickets. To enable batch operations first load @file{rt-liberation-multi.el}: @lisp (require 'rt-liberation-storage) @end lisp @table @kbd @item M @kindex M (ticket browser) @findex rt-liber-mark-ticket-at-point Mark the ticket at point for future action. If the ticket at point is already marked then unmark it. @end table @defun rt-liber-multi-set-status-open Set the status of all the marked tickets to ``open''. @end defun @defun rt-liber-multi-set-status-resolved Set the status of all the marked tickets to ``resolved. @end defun @defun rt-liber-multi-assign name Assign all of the marked tickets to NAME. @end defun @defun rt-liber-multi-flag-as-spam-and-delete Set the status of all the marked tickets to ``is-spam'' and delete. @end defun @c -------------------------------------------------- @node Local Storage @chapter Local Storage @cindex Local Storage @file{rt-liberation-storage.el} implements associating arbitrary ancillary data with tickets. The data is stored locally and is not sent to the RT server. To enable local storage first load @file{rt-liberation-storage.el}: @lisp (require 'rt-liberation-storage) @end lisp Then enable the display of ancillary data with: @lisp (setq rt-liber-anc-p t) @end lisp The associated data is edited and displayed in the ticket browser with the following command key: @table @kbd @item A @kindex A (ticket browser) @findex rt-liber-browser-ancillary-text Associate text with the ticket at point. You will be prompted to enter a string of text. @end table Once text is associated with a ticket it will be displayed alongside that ticket in the ticket browser. This particular feature lends itself to creating private annotations about tickets. The implementation distributed with rt-liberation allows associating text with tickets but is not limited to text. The same implementation can be extended to associate any arbitrary data with any ticket. @c -------------------------------------------------- @c including the relevant licenses @include gpl.texi @include fdl.texi @c -------------------------------------------------- @node Concept Index @unnumbered Concept Index @printindex cp @c -------------------------------------------------- @node Function Index @unnumbered Function Index @printindex fn @c -------------------------------------------------- @node Variable Index @unnumbered Variable Index @printindex vr @c -------------------------------------------------- @node Keybinding Index @unnumbered Keybinding Index @printindex ky @bye