[freeside-commits] branch FREESIDE_4_BRANCH updated. a4ef172f50a0f4705126f940e3836a9df64980c4

Mark Wells mark at 420.am
Thu May 26 10:04:48 PDT 2016


The branch, FREESIDE_4_BRANCH has been updated
       via  a4ef172f50a0f4705126f940e3836a9df64980c4 (commit)
      from  1f51760c05378128ad74bfd4a08c400a03457206 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit a4ef172f50a0f4705126f940e3836a9df64980c4
Author: Mark Wells <mark at freeside.biz>
Date:   Wed May 25 16:29:05 2016 -0700

    indicator on the top bar for new activity on tickets, #41670

diff --git a/httemplate/elements/header-full.html b/httemplate/elements/header-full.html
index 699f82c..db38eaf 100644
--- a/httemplate/elements/header-full.html
+++ b/httemplate/elements/header-full.html
@@ -67,6 +67,9 @@ Example:
         <td align=left BGCOLOR="#ffffff"> <!-- valign="top" -->
           <font size=6><% $company_name || 'ExampleCo' %></font>
         </td>
+        <td align="right" BGCOLOR="#ffffff">
+          <& notify-tickets.html &>
+        </td>
         <td align=right valign=top BGCOLOR="#ffffff"><FONT SIZE="-1">Logged in as <b><% $FS::CurrentUser::CurrentUser->username |h %> </b> <FONT SIZE="-2"><a href="<%$fsurl%>loginout/logout.html">logout</a></FONT><br></FONT><FONT SIZE="-2"><a href="<%$fsurl%>pref/pref.html" STYLE="color: #000000">Preferences</a>
 %         if ( $conf->config("ticket_system")
 %              && FS::TicketSystem->access_right(\%session, 'ModifySelf') ) {
diff --git a/httemplate/elements/notify-tickets.html b/httemplate/elements/notify-tickets.html
new file mode 100644
index 0000000..f7db52e
--- /dev/null
+++ b/httemplate/elements/notify-tickets.html
@@ -0,0 +1,37 @@
+% if ($enabled) {
+<style>
+.dot {
+  border-radius: 50%;
+  border: 1px solid black;
+  width: 1ex;
+  height: 1ex;
+  display: inline-block;
+}
+</style>
+<div style="font-weight: bold; vertical-align: bottom; text-align: left">
+%   if ( $UnrepliedTickets->Count > 0 ) {
+  <a href="<% $fsurl %>rt/Search/UnrepliedTickets.html">
+    <div class="dot" style="background-color: green"></div>
+    <% emt('New activity on [quant,_1,ticket]', $UnrepliedTickets->Count) %>
+  </a>
+%   } else {
+  <% emt('No new activity on tickets') %>
+%   }
+</div>
+% }
+<%init>
+use Class::Load 'load_class';
+
+my $enabled = $FS::TicketSystem::system eq 'RT_Internal';
+my $UnrepliedTickets;
+if ($enabled) {
+  my $class = 'RT::Search::UnrepliedTickets';
+  load_class($class);
+  my $session = FS::TicketSystem->session;
+  my $CurrentUser = $session->{CurrentUser};
+  $UnrepliedTickets = RT::Tickets->new($CurrentUser);
+  my $search = $class->new(TicketsObj => $UnrepliedTickets);
+warn Dumper $search;
+  $search->Prepare;
+}
+</%init>
diff --git a/rt/lib/RT/Search/UnrepliedTickets.pm b/rt/lib/RT/Search/UnrepliedTickets.pm
new file mode 100644
index 0000000..a996901
--- /dev/null
+++ b/rt/lib/RT/Search/UnrepliedTickets.pm
@@ -0,0 +1,62 @@
+=head1 NAME
+
+  RT::Search::UnrepliedTickets
+
+=head1 SYNOPSIS
+
+=head1 DESCRIPTION
+
+Find all unresolved tickets owned by the current user where the last correspondence
+from a requestor (or ticket creation) is more recent than the last
+correspondence from a non-requestor (if there is any).
+
+=head1 METHODS
+
+=cut
+
+package RT::Search::UnrepliedTickets;
+
+use strict;
+use warnings;
+use base qw(RT::Search);
+
+
+sub Describe  {
+  my $self = shift;
+  return ($self->loc("Tickets awaiting a reply"));
+}
+
+sub Prepare  {
+  my $self = shift;
+
+  my $TicketsObj = $self->TicketsObj;
+  $TicketsObj->Limit(
+    FIELD => 'Owner',
+    VALUE => $TicketsObj->CurrentUser->id
+  );
+  $TicketsObj->Limit(
+    FIELD => 'Status',
+    OPERATOR => '!=',
+    VALUE => 'resolved'
+  );
+  my $txn_alias = $TicketsObj->JoinTransactions;
+  $TicketsObj->Limit(
+    ALIAS => $txn_alias,
+    FIELD => 'Created',
+    OPERATOR => '>',
+    VALUE => 'COALESCE(main.Told,\'1970-01-01\')',
+    QUOTEVALUE => 0,
+  );
+  $TicketsObj->Limit(
+    ALIAS => $txn_alias,
+    FIELD => 'Type',
+    OPERATOR => 'IN',
+    VALUE => [ 'Correspond', 'Create' ],
+  );
+
+  return(1);
+}
+
+RT::Base->_ImportOverlays();
+
+1;
diff --git a/rt/share/html/Search/UnrepliedTickets.html b/rt/share/html/Search/UnrepliedTickets.html
new file mode 100755
index 0000000..37f94e0
--- /dev/null
+++ b/rt/share/html/Search/UnrepliedTickets.html
@@ -0,0 +1,156 @@
+%# false laziness with Results.html; basically this is the same thing but with
+%# a hardcoded RT::Tickets object instead of a Query param
+
+<& /Elements/Header, Title => $title,
+    Refresh => $refresh,
+    LinkRel => \%link_rel &>
+
+% $m->callback( ARGSRef => \%ARGS, Format => \$Format, CallbackName => 'BeforeResults' );
+
+<& /Elements/CollectionList, 
+    Class => 'RT::Tickets',
+    Collection => $session{tickets},
+    TotalFound => $ticketcount,
+    AllowSorting => 1,
+    OrderBy => $OrderBy,
+    Order => $Order,
+    Rows => $Rows,
+    Page => $Page,
+    Format => $Format,
+    BaseURL => $BaseURL,
+    SavedSearchId => $ARGS{'SavedSearchId'},
+    SavedChartSearchId => $ARGS{'SavedChartSearchId'},
+    PassArguments => [qw(Format Rows Page Order OrderBy SavedSearchId SavedChartSearchId)],
+&>
+% $m->callback( ARGSRef => \%ARGS, CallbackName => 'AfterResults' );
+
+% my %hiddens = (Format => $Format, Rows => $Rows, OrderBy => $OrderBy, Order => $Order, HideResults => $HideResults, Page => $Page, SavedChartSearchId => $SavedChartSearchId );
+<div align="right" class="refresh">
+<form method="get" action="<%RT->Config->Get('WebPath')%>/Search/UnrepliedTickets.html">
+% foreach my $key (keys(%hiddens)) {
+<input type="hidden" class="hidden" name="<%$key%>" value="<% defined($hiddens{$key})?$hiddens{$key}:'' %>" />
+% }
+<& /Elements/Refresh, Name => 'TicketsRefreshInterval', Default => $session{'tickets_refresh_interval'}||RT->Config->Get('SearchResultsRefreshInterval', $session{'CurrentUser'}) &>
+<input type="submit" class="button" value="<&|/l&>Change</&>" />
+</form>
+</div>
+<%INIT>
+$m->callback( ARGSRef => \%ARGS, CallbackName => 'Initial' );
+
+# Read from user preferences
+my $prefs = $session{'CurrentUser'}->UserObj->Preferences("SearchDisplay") || {};
+
+# These variables are what define a search_hash; this is also
+# where we give sane defaults.
+$Format      ||= $prefs->{'Format'} || RT->Config->Get('DefaultSearchResultFormat');
+$Order       ||= $prefs->{'Order'} || RT->Config->Get('DefaultSearchResultOrder');
+$OrderBy     ||= $prefs->{'OrderBy'} || RT->Config->Get('DefaultSearchResultOrderBy');
+
+# In this case the search UI isn't available, so trust the defaults.
+
+# Some forms pass in "RowsPerPage" rather than "Rows"
+# We call it RowsPerPage everywhere else.
+
+if ( defined $prefs->{'RowsPerPage'} ) {
+    $Rows = $prefs->{'RowsPerPage'};
+} else {
+    $Rows = 50;
+}
+$Page = 1 unless $Page && $Page > 0;
+
+use RT::Search::UnrepliedTickets;
+
+$session{'i'}++;
+$session{'tickets'} = RT::Tickets->new($session{'CurrentUser'}) ;
+my $search = RT::Search::UnrepliedTickets->new( TicketsObj => $session{'tickets'} );
+$search->Prepare;
+
+if ($OrderBy =~ /\|/) {
+    # Multiple Sorts
+    my @OrderBy = split /\|/,$OrderBy;
+    my @Order = split /\|/,$Order;
+    $session{'tickets'}->OrderByCols(
+        map { { FIELD => $OrderBy[$_], ORDER => $Order[$_] } } ( 0
+        .. $#OrderBy ) );; 
+} else {
+    $session{'tickets'}->OrderBy(FIELD => $OrderBy, ORDER => $Order); 
+}
+$session{'tickets'}->RowsPerPage( $Rows ) if $Rows;
+$session{'tickets'}->GotoPage( $Page - 1 );
+
+# use this to set a CSRF token applying to the search, so that the user can come
+# back to this page without triggering a referrer check
+$session{'CurrentSearchHash'} = {
+    Format      => $Format,
+    Page        => $Page,
+    Order       => $Order,
+    OrderBy     => $OrderBy,
+    RowsPerPage => $Rows
+};
+
+
+my $ticketcount = $session{tickets}->CountAll();
+my $title = loc('New activity on [quant,_1,ticket,tickets]', $ticketcount);
+
+# pass this through on pagination links
+my $QueryString = "?".$m->comp('/Elements/QueryString',
+                               Format => $Format,
+                               Rows => $Rows,
+                               OrderBy => $OrderBy,
+                               Order => $Order,
+                               Page => $Page);
+
+if ($ARGS{'TicketsRefreshInterval'}) {
+    $session{'tickets_refresh_interval'} = $ARGS{'TicketsRefreshInterval'};
+}
+
+my $refresh = $session{'tickets_refresh_interval'}
+    || RT->Config->Get('SearchResultsRefreshInterval', $session{'CurrentUser'} );
+
+# Check $m->request_args, not $DECODED_ARGS, to avoid creating a new CSRF token on each refresh
+if (RT->Config->Get('RestrictReferrer') and $refresh and not $m->request_args->{CSRF_Token}) {
+    my $token = RT::Interface::Web::StoreRequestToken( $session{'CurrentSearchHash'} );
+    $m->notes->{RefreshURL} = RT->Config->Get('WebURL')
+        . "Search/UnrepliedTickets.html?CSRF_Token="
+            . $token;
+}
+
+my %link_rel;
+my $genpage = sub {
+    return $m->comp(
+        '/Elements/QueryString',
+        Format  => $Format,
+        Rows    => $Rows,
+        OrderBy => $OrderBy,
+        Order   => $Order,
+        Page    => shift(@_),
+    );
+};
+
+if ( RT->Config->Get('SearchResultsAutoRedirect') && $ticketcount == 1 &&
+    $session{tickets}->First ) {
+# $ticketcount is not always precise unless $UseSQLForACLChecks is set to true,
+# check $session{tickets}->First here is to make sure the ticket is there.
+    RT::Interface::Web::Redirect( RT->Config->Get('WebURL')
+            ."Ticket/Display.html?id=". $session{tickets}->First->id );
+}
+
+my $BaseURL = RT->Config->Get('WebPath')."/Search/UnrepliedTickets.html?";
+$link_rel{first} = $BaseURL . $genpage->(1)         if $Page > 1;
+$link_rel{prev}  = $BaseURL . $genpage->($Page - 1) if $Page > 1;
+$link_rel{next}  = $BaseURL . $genpage->($Page + 1) if ($Page * $Rows) < $ticketcount;
+$link_rel{last}  = $BaseURL . $genpage->(POSIX::ceil($ticketcount/$Rows)) if $Rows and ($Page * $Rows) < $ticketcount;
+</%INIT>
+<%CLEANUP>
+$session{'tickets'}->PrepForSerialization();
+</%CLEANUP>
+<%ARGS>
+$HideResults => 0
+$Rows => undef
+$Page => 1
+$OrderBy => undef
+$Order => undef
+$SavedSearchId => undef
+$SavedChartSearchId => undef
+$Format => undef
+</%ARGS>

-----------------------------------------------------------------------

Summary of changes:
 httemplate/elements/header-full.html               |    3 +
 httemplate/elements/notify-tickets.html            |   37 +++++++
 rt/lib/RT/Search/UnrepliedTickets.pm               |   62 +++++++++++
 .../Search/{Results.html => UnrepliedTickets.html} |  117 +++++---------------
 4 files changed, 130 insertions(+), 89 deletions(-)
 create mode 100644 httemplate/elements/notify-tickets.html
 create mode 100644 rt/lib/RT/Search/UnrepliedTickets.pm
 copy rt/share/html/Search/{Results.html => UnrepliedTickets.html} (53%)




More information about the freeside-commits mailing list