From Request Tracker Wiki
Jump to navigation Jump to search

Spatially Enabled RT

This uses custom fields to add a spatial field to a ticket. Search results can then be plotted on a map. The examples use a specific map projection and a custom output format that would be better reworked as KML. The spatial entities are stored in the Description field of the custom field.

File:Rt-map-t.png Full size

Load Custom Fields with Spatial Entities in the Description

A custom field named GPS of type 'select one' is created. The name and description are loaded from a database of GPS sites. Here the projection used is New Zealand Metric Grid (NZMG) which is a cartesian projection with Eastings (nzmge) and Northings (nzmgn). These could be a lat/long that is compatible with Google maps.

Name = AKTO.CG (Akitio Station)

Description = 1369:<place name="Akitio" id="1369"><nzmg nzmge="2803121" nzmgn="6068282" /></place>:<delta link="ViewMark&sp=SAKTO"/>

Users can then select familiar site codes (AKTO.CG) that has a spatial element in the description.

Custom Search Results

Create a custom script to parse search results and return an XML file that has tickets with custom fields listed in it. The code below is complicated by the GPS site spatial entity being located at a Place spatial entity so there is some sorting and mapping (seismic sites are also located at a Place).


  / \
 /   \
GPS Seismic

File:Rt-place-t.jpg Full size

The key elements are getting the session, loading the custom field description, and parsing that description for a spatial element.


<%INIT> use RT::Report::Tickets; use RT::CustomFieldValue; use XML::Simple; my $Tickets = RT::Tickets->new($session{'CurrentUser'}); my $cf = RT::CustomFieldValue->new($session{'CurrentUser'}); $r->content_type('text/xml'); $Tickets->FromSQL($ARGS{'Query'}); my %tickets = (); my %places = (); TICKETS: while (my $Ticket = $Tickets->Next()) { <code><pre> my $CustomFieldValues = $Ticket-&gt;CustomFieldValues; my $hasSpatialField = 0; my %ticketSites = (); # Assigns tickets to places and also assigns sites to tickets (by place). # Means that tickets with multiple custom fields will display # at 1..many places and each ticket (at each place) will have the correct # sites listed for that place. FIELD: while (my $c = $CustomFieldValues-&gt;Next) { $cf-&gt;LoadByCols(CustomField =&gt; $c-&gt;CustomField, Name =&gt; $c-&gt;Content); if (grep /\&lt;nzmg nzmge=\"[0-9]+\" nzmgn=\"[0-9]+\" \/\&gt;/, $cf-&gt;Description) { $hasSpatialField = 1; my ($placeId, $place, $deltaLink) = split(/\:/, $cf-&gt;Description); $deltaLink =~ s/\&amp;sp/&amp;amp;sp/g; $places{$placeId} = $place; $ticketSites{$placeId} .= '&lt;site code="' . $cf-&gt;Name . '"&gt;' . $deltaLink . '&lt;/site&gt;'; </pre></code> ; } } <code><pre> unless ($hasSpatialField) { next TICKETS; } foreach my $placeId (keys %ticketSites) { my %ticketOut = &amp;ticketOut($Ticket, $ticketSites{$placeId}); push @{ $tickets{$placeId} }, \%ticketOut; } </pre></code> } # Closes TICKETS: my @places = keys %places; my $OUT = '<results>'; foreach my $placeId (@places) { $OUT .= '<tickets>'; $OUT .= $places{$placeId}; foreach (@{$tickets{$placeId}}) { $OUT .= XMLout($_, RootName => 'ticket', NoIndent => 1, NoAttr => 1, NoEscape => 1); } $OUT .= '</tickets>'; } $OUT .= '</results>'; $m->out($OUT); $m->abort(); sub ticketOut { <code><pre>my ($Ticket, $ticketSites) = @_; my $description = ''; if (defined($Ticket-&gt;Transactions-&gt;First)) { $description = $Ticket-&gt;Transactions-&gt;First-&gt;Content(); } my $due = $Ticket-&gt;Due =~ m/^1970/ ? '' : $Ticket-&gt;Due; my $starts = $Ticket-&gt;Starts =~ m/^1970/ ? '' : $Ticket-&gt;Starts; my %ticketOut; $ticketOut{'sites'} = $ticketSites; $ticketOut{'subject'} = $Ticket-&gt;Subject; $ticketOut{'url'} = $RT::WebURL."Ticket/Display.html?id=".$Ticket-&gt;id; $ticketOut{'created'} = $Ticket-&gt;Created; $ticketOut{'starts'} = $starts; $ticketOut{'due'} = $due; $ticketOut{'priority'} = $Ticket-&gt;Priority; return (%ticketOut); </pre></code>



Map Link

A link to plot the search results on map is added to the end of the search results page (this would probably be better higher up in the navigation). In this case it calls a wrapper page that can re-query the search results via (above) as xml and plot them on a map. Create /rt3/local/html/Search/Results.html


<     RSSAutoDiscovery => $RSSFeedURL,
<     MapAutoDiscovery => $MapFeedURL &>

> RSSAutoDiscovery => $RSSFeedURL &>

< <a href="<%$MapFeedURL%>" target="_map"><&|/l&>Map</&></a> |
< my $MapFeedURL = "/maps/rtmaps.html$ShortQueryString";