[Bps-public-commit] rt-extension-mobileui branch, master, created. 23b6ba001b09a7e45f067b523a1fcec190ae6538

Jesse Vincent jesse at bestpractical.com
Wed Jul 14 18:51:55 EDT 2010


The branch, master has been created
        at  23b6ba001b09a7e45f067b523a1fcec190ae6538 (commit)

- Log -----------------------------------------------------------------
commit 9832f64e9fc3daf8f86f5376c92644fce27ebb68
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Tue Jul 13 10:12:36 2010 +0200

    Initial import of ongoing work

diff --git a/html/Callbacks/RT-Extension-MobileUI/Elements/Login/Header b/html/Callbacks/RT-Extension-MobileUI/Elements/Login/Header
new file mode 100644
index 0000000..43f0b23
--- /dev/null
+++ b/html/Callbacks/RT-Extension-MobileUI/Elements/Login/Header
@@ -0,0 +1,5 @@
+<%init>
+return unless ($m->request_comp->path() =~ m{^/m(?:\/|$)});
+$m->comp('/m/login',%ARGS);
+$m->abort;
+</%init>
diff --git a/html/Callbacks/RT-Extension-MobileUI/index.html/Initial b/html/Callbacks/RT-Extension-MobileUI/index.html/Initial
new file mode 100644
index 0000000..39df5e8
--- /dev/null
+++ b/html/Callbacks/RT-Extension-MobileUI/index.html/Initial
@@ -0,0 +1,5 @@
+<%init>
+if (($ENV{'HTTP_USER_AGENT'} || '') !~ /(?:hiptop|Blazer|Novarra|Vagabond|SonyEricsson|Symbian|NetFront|UP.Browser|UP.Link|Windows CE|MIDP|J2ME|DoCoMo|J-PHONE|PalmOS|PalmSource|iPhone|iPod|AvantGo|Nokia|Android)/io && !$session{'NotMobile'})  {
+    RT::Interface::Web::Redirect('/m');
+}
+</%init>
diff --git a/html/m/_elements/footer b/html/m/_elements/footer
new file mode 100644
index 0000000..308b1d0
--- /dev/null
+++ b/html/m/_elements/footer
@@ -0,0 +1,2 @@
+</body>
+</html>
diff --git a/html/m/_elements/header b/html/m/_elements/header
new file mode 100644
index 0000000..678b075
--- /dev/null
+++ b/html/m/_elements/header
@@ -0,0 +1,2 @@
+<html>
+<body>
diff --git a/html/m/_elements/menu b/html/m/_elements/menu
new file mode 100644
index 0000000..34cb93d
--- /dev/null
+++ b/html/m/_elements/menu
@@ -0,0 +1,30 @@
+<ul class="menu">
+% for my $item (@menu) {
+<li><a href="<%$item->{url}%>"><%$item->{label}%></li>
+% }
+</ul>
+<%init>
+my @menu = ( 
+{ label =>  loc("My tickets"),
+  url => '/m/tickets/owned'
+},
+ {
+    label => loc("My requests"),
+    url => '/m/tickets/requested'
+    },
+ {
+    label => loc("All tickets"),
+    url => '/m/tickets/all'
+    },
+{
+    label => loc("New ticket"),
+    url => '/m/ticket/create',
+},
+{
+    label => loc("Logout"),
+    url => '/m/logout',
+}
+
+
+);
+</%init>
diff --git a/html/m/_elements/ticket_list b/html/m/_elements/ticket_list
new file mode 100644
index 0000000..2cc6594
--- /dev/null
+++ b/html/m/_elements/ticket_list
@@ -0,0 +1,18 @@
+<%args>
+$query => ''
+$page => ''
+</%args>
+<%init>
+</%init>
+<&| /m/_elements/wrapper &>
+<& /Elements/CollectionList,
+    Query => $query,
+    OrderBy => 'id',
+    Order => 'desc',
+    Rows => '25',
+    Page => $page,
+    Format => q{'<a href="__WebPath__/m/ticket/show?id=__id__">__id__</a>','<a href="__WebPath__/m/ticket/show?id=__id__">Subject</a>',Status,Requestors,Owner,Priority},
+    Class => 'RT::Tickets',
+    BaseURL => '/m/list/'
+&>
+</&>
diff --git a/html/m/_elements/wrapper b/html/m/_elements/wrapper
new file mode 100644
index 0000000..f0da9e3
--- /dev/null
+++ b/html/m/_elements/wrapper
@@ -0,0 +1,6 @@
+<%init>
+$m->comp('header');
+$m->out($m->content);
+$m->comp('footer');
+$m->abort();
+</%init>
diff --git a/html/m/dhandler b/html/m/dhandler
new file mode 100644
index 0000000..d5d9dd1
--- /dev/null
+++ b/html/m/dhandler
@@ -0,0 +1,6 @@
+%# %$HTML::Mason::Commands::r->status(404);
+%# fix this sometime
+<&| _elements/wrapper &>
+<h1><%loc("Page not found")%></h1>
+<& _elements/menu &>
+</&>
diff --git a/html/m/index.html b/html/m/index.html
new file mode 100644
index 0000000..6ca1217
--- /dev/null
+++ b/html/m/index.html
@@ -0,0 +1,4 @@
+<&| _elements/wrapper &>
+<%loc("RT for [_1]",RT->Config->Get('rtname'))%>
+<& _elements/menu &>
+</&>
diff --git a/html/m/login b/html/m/login
new file mode 100644
index 0000000..aed5393
--- /dev/null
+++ b/html/m/login
@@ -0,0 +1,82 @@
+<%INIT>
+my $req_uri;
+
+if (UNIVERSAL::can($r, 'uri') and $r->uri =~ m{.*/(.*)}) {
+    $req_uri = $1;
+}
+
+my $form_action = defined $goto             ? $goto
+                : defined $req_uri          ? $req_uri
+                :                             RT->Config->Get('WebPath')
+                ;
+
+# sanitize $form_action
+my $uri = URI->new($form_action);
+
+# You get undef scheme with a relative uri like "/Search/Build.html"
+unless (!defined($uri->scheme) || $uri->scheme eq 'http' || $uri->scheme eq 'https') {
+    $form_action = RT->Config->Get('WebPath');
+}
+
+# Make sure we're logging in to the same domain
+# You can get an undef authority with a relative uri like "index.html"
+my $uri_base_url = URI->new(RT->Config->Get('WebBaseURL'));
+unless (!defined($uri->authority) || $uri->authority eq $uri_base_url->authority) {
+    $form_action = RT->Config->Get('WebPath');
+}
+</%INIT>
+<&| /m/_elements/wrapper &>
+
+
+<div id="body" class="login-body">
+% if ($Error) {
+<&| "/Widgets/TitleBox", title => loc('Error'), hideable => 0, class => 'error'  &>
+<% $Error %>
+</&>
+% }
+
+
+<div id="login-box">
+<&| /Widgets/TitleBox, title => loc('Login'), titleright => $RT::VERSION, hideable => 0 &>
+
+% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) {
+<form id="login" name="login" method="post" action="<% $form_action %>">
+
+<div class="input-row">
+    <span class="label"><&|/l&>Username</&>:</span>
+    <span class="input"><input name="user" value="<%$user%>" id="user" /></span>
+</div>
+
+<div class="input-row">
+    <span class="label"><&|/l&>Password</&>:</span>
+    <span class="input"><input type="password" name="pass" autocomplete="off" /></span>
+</div>
+
+<div class="button-row">
+    <span class="input"><input type="submit" class="button" value="<&|/l&>Login</&>" /></span>
+</div>
+
+% foreach my $key (keys %ARGS) {
+%  if (($key ne 'user') and ($key ne 'pass')) {
+% 	if (ref($ARGS{$key}) =~ /ARRAY/) {
+% 		foreach my $val (@{$ARGS{$key}}) {
+<input type="hidden" class="hidden" name="<%$key %>" value="<% $val %>" />
+% 		}
+% 	}
+%	else {
+<input type="hidden" class="hidden" name="<% $key %>" value="<% $ARGS{$key} %>" />
+% 	}
+%  }
+% }
+</form>
+% }
+</&>
+</div><!-- #login-box -->
+</div><!-- #login-body -->
+</&>
+<%ARGS>
+$user => ""
+$pass => undef
+$goto => undef
+$Error => undef
+</%ARGS>
diff --git a/html/m/logout b/html/m/logout
new file mode 100644
index 0000000..ce2e9cc
--- /dev/null
+++ b/html/m/logout
@@ -0,0 +1,8 @@
+<%init>
+if (keys %session) {
+    tied(%session)->delete;
+    $session{'CurrentUser'} = RT::CurrentUser->new;
+}
+RT::Interface::Web::Redirect('/');
+
+</%init>
diff --git a/html/m/ticket/create b/html/m/ticket/create
new file mode 100644
index 0000000..e69de29
diff --git a/html/m/ticket/history b/html/m/ticket/history
new file mode 100644
index 0000000..6dbd3fd
--- /dev/null
+++ b/html/m/ticket/history
@@ -0,0 +1,24 @@
+<%args>
+$id => undef
+</%args>
+<%init>
+my $t = RT::Ticket->new($session{CurrentUser});
+$t->Load($id);
+my $history = $t->Transactions()->ItemsArrayRef;
+</%init>
+<&| /m/_elements/wrapper &>
+<ul>
+% for my $entry (@$history) {
+<li>
+<% $entry->CreatedAsString() %>
+ <& /Elements/ShowUser, User => $entry->CreatorObj &> 
+<%$entry->BriefDescription%>
+% if ($entry->Type !~ /EmailRecord/) {
+<div class="txn-content">
+<%$entry->Content%>
+</div>
+% }
+</li>
+% }
+</ul>
+</&>
diff --git a/html/m/ticket/modify b/html/m/ticket/modify
new file mode 100644
index 0000000..e69de29
diff --git a/html/m/ticket/reply b/html/m/ticket/reply
new file mode 100644
index 0000000..e69de29
diff --git a/html/m/ticket/show b/html/m/ticket/show
new file mode 100644
index 0000000..701f52c
--- /dev/null
+++ b/html/m/ticket/show
@@ -0,0 +1,61 @@
+<%args>
+$id => undef
+</%args>
+<%init>
+my $t = RT::Ticket->new($session{CurrentUser});
+$t->Load($id);
+</%init>
+<&| /m/_elements/wrapper &>
+
+
+    <&| /Widgets/TitleBox, title => loc('The Basics'),
+        class => 'ticket-info-basics',
+    &>
+        <& /Ticket/Elements/ShowBasics, Ticket => $t &>
+    </&>
+
+% if ($t->CustomFields->First) {
+    <&| /Widgets/TitleBox, title => loc('Custom Fields'),
+        title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$t->Id,
+        class => 'ticket-info-cfs',
+    &>
+        <& /Ticket/Elements/ShowCustomFields, Ticket => $t &>
+    </&>
+% }
+
+    <&| /Widgets/TitleBox, title => loc('People'),
+        class => 'ticket-info-people',
+    &>
+        <& /Ticket/Elements/ShowPeople, Ticket => $t &>
+    </&>
+
+    <& /Ticket/Elements/ShowAttachments, Ticket => $t &>
+
+    <& /Ticket/Elements/ShowRequestor, Ticket => $t &>
+
+% if ( RT->Config->Get('EnableReminders') ) {
+    <&|/Widgets/TitleBox, title => loc("Reminders"),
+        class => 'ticket-info-reminders',
+    &>
+        <table><tr><td>
+            <form action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post">
+                <& /Ticket/Elements/Reminders, Ticket => $t, ShowCompleted => 0 &>
+                <div align="right"><input type="submit" class="button" value="<&|/l&>Save</&>" /></div>
+            </form>
+        </td></tr></table>
+    </&>
+% }
+
+    <&| /Widgets/TitleBox, title => loc("Dates"),
+        class => 'ticket-info-dates',
+    &>
+        <& /Ticket/Elements/ShowDates, Ticket => $t &>
+    </&>
+
+    <&| /Widgets/TitleBox, title => loc('Links'),
+        class => 'ticket-info-links',
+    &>
+        <& /Elements/ShowLinks, Ticket => $t &>
+    </&>
+
+</&>
diff --git a/html/m/tickets/all b/html/m/tickets/all
new file mode 100644
index 0000000..b17bc29
--- /dev/null
+++ b/html/m/tickets/all
@@ -0,0 +1,4 @@
+<%init>
+ $m->comp('../_elements/ticket_list', %ARGS, query => 'id > 0' );
+$m->abort();
+</%init>
diff --git a/html/m/tickets/owned b/html/m/tickets/owned
new file mode 100644
index 0000000..00d63f4
--- /dev/null
+++ b/html/m/tickets/owned
@@ -0,0 +1,4 @@
+<%init>
+ $m->comp('../_elements/ticket_list', %ARGS, query => 'Owner = "'.$session{CurrentUser}->Name.'" AND (Status != "resolved" AND Status != "rejected" AND Status != "stalled")'); 
+$m->abort();
+</%init>
diff --git a/html/m/tickets/requested b/html/m/tickets/requested
new file mode 100644
index 0000000..3043e05
--- /dev/null
+++ b/html/m/tickets/requested
@@ -0,0 +1,4 @@
+<%init>
+ $m->comp('../_elements/ticket_list', %ARGS, query => 'Requestors.EmailAddress = "'.$session{CurrentUser}->EmailAddress.'" AND (Status != "resolved" AND Status != "rejected" AND Status != "stalled")'); 
+$m->abort();
+</%init>
diff --git a/lib/RT/Extension/MobileUI.pm b/lib/RT/Extension/MobileUI.pm
new file mode 100644
index 0000000..332e3d1
--- /dev/null
+++ b/lib/RT/Extension/MobileUI.pm
@@ -0,0 +1,8 @@
+use warnings;
+use strict;
+
+package RT::Extension::MobileUI;
+
+my $VERSION = 1;
+
+1;

commit 23b6ba001b09a7e45f067b523a1fcec190ae6538
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Thu Jul 15 00:50:04 2010 +0200

    ticket creation, beginnings of ui

diff --git a/html/m/_elements/header b/html/m/_elements/header
index 678b075..8655c34 100644
--- a/html/m/_elements/header
+++ b/html/m/_elements/header
@@ -1,2 +1,5 @@
 <html>
+<head>
+<link rel="stylesheet" type="text/css" href="<%RT->Config->Get('WebPath')|n%>/m/style.css"/>
+</head>
 <body>
diff --git a/html/m/_elements/menu b/html/m/_elements/menu
index 34cb93d..9bfb339 100644
--- a/html/m/_elements/menu
+++ b/html/m/_elements/menu
@@ -1,8 +1,10 @@
+<&| /Widgets/TitleBox &>
 <ul class="menu">
 % for my $item (@menu) {
 <li><a href="<%$item->{url}%>"><%$item->{label}%></li>
 % }
 </ul>
+</&>
 <%init>
 my @menu = ( 
 { label =>  loc("My tickets"),
diff --git a/html/m/_elements/ticket_list b/html/m/_elements/ticket_list
index 2cc6594..c51abbb 100644
--- a/html/m/_elements/ticket_list
+++ b/html/m/_elements/ticket_list
@@ -5,6 +5,7 @@ $page => ''
 <%init>
 </%init>
 <&| /m/_elements/wrapper &>
+<&|/Widgets/TitleBox &>
 <& /Elements/CollectionList,
     Query => $query,
     OrderBy => 'id',
@@ -16,3 +17,4 @@ $page => ''
     BaseURL => '/m/list/'
 &>
 </&>
+</&>
diff --git a/html/m/style.css b/html/m/style.css
new file mode 100644
index 0000000..c5fbc34
--- /dev/null
+++ b/html/m/style.css
@@ -0,0 +1,79 @@
+body {
+    font-family: helvetica, arial, sans-serif;
+    background-color: #ccf;
+    text-rendering: optimizeLegibility;
+}
+
+.titlebox-title {
+    font-size: 1.3em;
+    padding-top: 1em;
+    text-decoration: underline;
+}
+
+ul.menu
+{
+    text-align: left;
+    list-style: none;
+    padding: 0;
+    margin: -0.6em;
+    left: 0;
+}
+
+ul.menu li
+{
+    display: block;
+    margin: 0;
+    padding: 0;
+}
+
+ul.menu li a:active, ul.menu li a:hover {
+    background-color: #eee;
+}
+
+
+ul.menu li a
+{
+    display: block;
+    padding: 1em;
+    margin: 0;
+    border:0;
+    border-top-width: 1px;
+    border-top-color: #666;
+    border-style: solid;
+    text-decoration: none;
+}
+
+ul.menu li:first-child a {
+    border: none;
+}
+
+ul.menu li#active a
+{
+    color: #800000;
+}
+
+div.titlebox {
+    padding: 1em;
+    -moz-border-radius: 1em;
+    -webkit-border-radius: 1em;
+    margin: 1em;
+    background-color: #fff;
+
+}
+
+hr.clear {
+    display: none;
+}
+
+
+.label, .labeltop {
+    text-align: right;
+    display: inline-block;
+    width: 6em;
+}
+
+%$m->abort();
+</%init>
+    $HTML::Mason::Commands::r->content_type('text/css');
+
+</%init>
diff --git a/html/m/ticket/create b/html/m/ticket/create
index e69de29..d9d820b 100644
--- a/html/m/ticket/create
+++ b/html/m/ticket/create
@@ -0,0 +1,395 @@
+<%ARGS>
+$QuoteTransaction => undef
+$CloneTicket => undef
+</%ARGS>
+<%init>
+$m->callback( CallbackName => "Init", ARGSRef => \%ARGS );
+my $Queue = $ARGS{Queue};
+
+
+my $showrows = sub {
+    my @pairs = @_;
+
+    while (@pairs) {
+        my $key = shift @pairs;
+        my $val = shift @pairs;
+
+        $m->out("<div><label>$key</label><div class=\"value\">$val</div></div>");
+
+    }
+
+};
+
+
+my $CloneTicketObj;
+if ($CloneTicket) {
+    $CloneTicketObj = RT::Ticket->new( $session{CurrentUser} );
+    $CloneTicketObj->Load($CloneTicket)
+        or Abort( loc("Ticket could not be loaded") );
+
+    my $clone = {
+        Requestors => join( ',', $CloneTicketObj->RequestorAddresses ),
+        Cc         => join( ',', $CloneTicketObj->CcAddresses ),
+        AdminCc    => join( ',', $CloneTicketObj->AdminCcAddresses ),
+        InitialPriority => $CloneTicketObj->Priority,
+    };
+
+    $clone->{$_} = $CloneTicketObj->$_()
+        for qw/Owner Subject FinalPriority TimeEstimated TimeWorked
+        Status TimeLeft/;
+
+    $clone->{$_} = $CloneTicketObj->$_->AsString
+        for grep { $CloneTicketObj->$_->Unix }
+        map      { $_ . "Obj" } qw/Starts Started Due Resolved/;
+
+    my $members = $CloneTicketObj->Members;
+    my ( @members, @members_of, @refers, @refers_by, @depends, @depends_by );
+    my $refers = $CloneTicketObj->RefersTo;
+    while ( my $refer = $refers->Next ) {
+        push @refers, $refer->LocalTarget;
+    }
+    $clone->{'new-RefersTo'} = join ' ', @refers;
+
+    my $refers_by = $CloneTicketObj->ReferredToBy;
+    while ( my $refer_by = $refers_by->Next ) {
+        push @refers_by, $refer_by->LocalBase;
+    }
+    $clone->{'RefersTo-new'} = join ' ', @refers_by;
+    if (0) {    # Temporarily disabled
+        my $depends = $CloneTicketObj->DependsOn;
+        while ( my $depend = $depends->Next ) {
+            push @depends, $depend->LocalTarget;
+        }
+        $clone->{'new-DependsOn'} = join ' ', @depends;
+
+        my $depends_by = $CloneTicketObj->DependedOnBy;
+        while ( my $depend_by = $depends_by->Next ) {
+            push @depends_by, $depend_by->LocalBase;
+        }
+        $clone->{'DependsOn-new'} = join ' ', @depends_by;
+
+        while ( my $member = $members->Next ) {
+            push @members, $member->LocalBase;
+        }
+        $clone->{'MemberOf-new'} = join ' ', @members;
+
+        my $members_of = $CloneTicketObj->MemberOf;
+        while ( my $member_of = $members_of->Next ) {
+            push @members_of, $member_of->LocalTarget;
+        }
+        $clone->{'new-MemberOf'} = join ' ', @members_of;
+
+    }
+
+    my $cfs = $CloneTicketObj->QueueObj->TicketCustomFields();
+    while ( my $cf = $cfs->Next ) {
+        my $cf_id     = $cf->id;
+        my $cf_values = $CloneTicketObj->CustomFieldValues( $cf->id );
+        my @cf_values;
+        while ( my $cf_value = $cf_values->Next ) {
+            push @cf_values, $cf_value->Content;
+        }
+        $clone->{"Object-RT::Ticket--CustomField-$cf_id-Value"} = join "\n",
+            @cf_values;
+    }
+
+    for ( keys %$clone ) {
+        $ARGS{$_} = $clone->{$_} if not defined $ARGS{$_};
+    }
+
+}
+
+my @results;
+
+my $title = loc("Create a new ticket");
+
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+$QueueObj->Load($Queue) || Abort(loc("Queue could not be loaded."));
+
+$m->callback( QueueObj => $QueueObj, title => \$title, results => \@results, ARGSRef => \%ARGS );
+
+$QueueObj->Disabled && Abort(loc("Cannot create tickets in a disabled queue."));
+
+my $CFs = $QueueObj->TicketCustomFields();
+
+my $ValidCFs = $m->comp(
+    '/Elements/ValidateCustomFields',
+    CustomFields => $CFs,
+    ARGSRef => \%ARGS
+);
+
+# {{{ deal with deleting uploaded attachments
+foreach my $key (keys %ARGS) {
+    if ($key =~ m/^DeleteAttach-(.+)$/) {
+	delete $session{'Attachments'}{$1};
+    }
+    $session{'Attachments'} = { %{$session{'Attachments'} || {}} };
+}
+# }}}
+
+# {{{ store the uploaded attachment in session
+if ($ARGS{'Attach'}) {			# attachment?
+    my $attachment = MakeMIMEEntity(
+        AttachmentFieldName => 'Attach'
+    );
+
+    my $file_path = Encode::decode_utf8("$ARGS{'Attach'}");
+    $session{'Attachments'} = {
+        %{$session{'Attachments'} || {}},
+	$file_path => $attachment,
+    };
+}
+# }}}
+
+# delete temporary storage entry to make WebUI clean
+unless (keys %{$session{'Attachments'}} and $ARGS{'id'} eq 'new') {
+    delete $session{'Attachments'};
+}
+
+my $checks_failure = 0;
+
+my $gnupg_widget = $m->comp('/Elements/GnuPG/SignEncryptWidget:new', Arguments => \%ARGS );
+$m->comp( '/Elements/GnuPG/SignEncryptWidget:Process',
+    self      => $gnupg_widget,
+    QueueObj  => $QueueObj,
+);
+
+
+if ( !exists $ARGS{'AddMoreAttach'} && ($ARGS{'id'}||'') eq 'new' ) {
+    my $status = $m->comp('/Elements/GnuPG/SignEncryptWidget:Check',
+        self      => $gnupg_widget,
+        Operation => 'Create',
+        QueueObj  => $QueueObj,
+    );
+    $checks_failure = 1 unless $status;
+}
+
+# check email addresses for RT's
+{
+    foreach my $field ( qw(Requestors Cc AdminCc) ) {
+        my $value = $ARGS{ $field };
+        next unless defined $value && length $value;
+
+        my @emails = Email::Address->parse( $value );
+        foreach my $email ( grep RT::EmailParser->IsRTAddress($_->address), @emails ) {
+            push @results, loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $email->format, loc($field =~ /^(.*?)s?$/) );
+            $checks_failure = 1;
+            $email = undef;
+        }
+        $ARGS{ $field } = join ', ', map $_->format, grep defined, @emails;
+    }
+}
+
+my $skip_create = 0;
+$m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create => \$skip_create, 
+              checks_failure => $checks_failure, results => \@results );
+
+if ((!exists $ARGS{'AddMoreAttach'}) and (defined($ARGS{'id'}) and $ARGS{'id'} eq 'new')) { # new ticket?
+    if ( $ValidCFs && !$checks_failure && !$skip_create ) {
+        $m->comp('show', %ARGS);
+        $RT::Logger->crit("After display call; error is $@");
+        $m->abort();
+    }
+    elsif ( !$ValidCFs ) {
+        # Invalid CFs
+        while (my $CF = $CFs->Next) {
+            my $msg = $m->notes('InvalidField-' . $CF->Id) or next;
+            push @results, $CF->Name . ': ' . $msg;
+        }
+    }
+}
+
+
+
+
+</%init>
+<&| /m/_elements/wrapper &>
+<& /Elements/ListActions, actions => \@results  &>
+<form action="<% RT->Config->Get('WebPath') %>/m/ticket/create" method="post" enctype="multipart/form-data" name="TicketCreate">
+<input type="hidden" class="hidden" name="id" value="new" />
+% $m->callback( CallbackName => 'FormStart', QueueObj => $QueueObj, ARGSRef => \%ARGS );
+% if ($gnupg_widget) {
+<& /Elements/GnuPG/SignEncryptWidget:ShowIssues, self => $gnupg_widget &>
+% }
+<div id="Ticket-Create-basics">
+<&| /Widgets/TitleBox, title => $title &>
+<%perl>
+
+$showrows->(
+
+    loc('Queue') => $m->scomp( '/Ticket/Elements/ShowQueue', QueueObj => $QueueObj )
+        . '<input type="hidden" class="hidden" name="Queue" value="'. $QueueObj->Name .'" />',
+
+    loc('Status') =>
+
+        $m->scomp(
+        "/Elements/SelectStatus",
+        Name         => "Status",
+        Default      => $ARGS{Status} || 'new',
+        DefaultValue => 0,
+        SkipDeleted  => 1
+        ),
+
+    loc("Owner") =>
+
+        $m->scomp(
+        "/Elements/SelectOwner",
+        Name         => "Owner",
+        QueueObj     => $QueueObj,
+        Default      => $ARGS{Owner} || $RT::Nobody->Id,
+        DefaultValue => 0
+        ),
+
+    loc("Requestors") => $m->scomp(
+        "/Elements/EmailInput",
+        Name    => 'Requestors',
+        Size    => '40',
+        Default => $ARGS{Requestors} || $session{CurrentUser}->EmailAddress
+    ),
+
+    loc("Cc") =>
+
+        $m->scomp( "/Elements/EmailInput", Name => 'Cc', Size => '40', Default => $ARGS{Cc} )
+        . '<span class="comment"><i><font size="-2">'
+        . loc(
+        "(Sends a carbon-copy of this update to a comma-delimited list of email addresses. These people <strong>will</strong> receive future updates.)"
+        )
+        . '</font></i></span>',
+
+    loc("Admin Cc") =>
+
+        $m->scomp( "/Elements/EmailInput", Name => 'AdminCc', Size => '40', Default => $ARGS{AdminCc} )
+        . '<span class="comment" colspan="2"><i><font size="-2">'
+        . loc(
+        "(Sends a carbon-copy of this update to a comma-delimited list of administrative email addresses. These people <strong>will</strong> receive future updates.)"
+        )
+        . '</font></i></span>',
+
+    loc("Subject") =>
+
+        '<input name="Subject" size="60" maxsize="200" value="'.($ARGS{Subject} || '').'" />',
+
+);
+
+
+$m->scomp("/Ticket/Elements/EditCustomFields", %ARGS, QueueObj => $QueueObj );
+
+
+$m->scomp("/Ticket/Elements/EditTransactionCustomFields", %ARGS, QueueObj => $QueueObj );
+
+</%perl>
+% if (exists $session{'Attachments'}) {
+
+<%loc("Attached file") %>
+
+<%loc("Check box to delete")%><br />
+% foreach my $attach_name (keys %{$session{'Attachments'}}) {
+<input type="checkbox" class="checkbox" name="DeleteAttach-<%$attach_name%>" value="1" /><%$attach_name%><br />
+% } # end of foreach
+
+
+% } # end of if
+
+<%perl>
+$showrows->(
+    loc("Attach file") =>
+
+        '<div class="value" colspan="5">
+<input type="file" name="Attach" />
+<input type="submit" class="button" name="AddMoreAttach" value="' . loc("Add More Files") . '" />'
+);
+</%perl>
+
+
+% if ( $gnupg_widget ) {
+%$m->scomp("/Elements/GnuPG/SignEncryptWidget", self => $gnupg_widget, QueueObj => $QueueObj )
+% }
+
+<%perl>
+$showrows->(
+    loc("Describe the issue below") =>
+        $m->scomp(
+        "/Elements/MessageBox", exists $ARGS{Content}  ? (Default => $ARGS{Content}, IncludeSignature => 0 ) : 
+( QuoteTransaction => $QuoteTransaction )));
+
+
+$m->scomp("/Elements/Submit", Label => loc("Create"));
+
+</%perl>
+
+    <div class="ticket-info-basics">
+	  <&| /Widgets/TitleBox, title => loc('The Basics'), 
+		title_class=> 'inverse',  
+		color => "#993333" &>
+<%perl>
+$showrows->(
+    loc("Priority") => $m->scomp(
+        "/Elements/SelectPriority",
+        Name    => "InitialPriority",
+        Default => $ARGS{InitialPriority} ? $ARGS{InitialPriority} : $QueueObj->InitialPriority,
+    ),
+    loc("Final Priority") => $m->scomp(
+        "/Elements/SelectPriority",
+        Name    => "FinalPriority",
+        Default => $ARGS{FinalPriority} ? $ARGS{FinalPriority} : $QueueObj->FinalPriority,
+    ),
+
+    loc("Time Estimated") => $m->scomp(
+        "/Elements/EditTimeValue",
+        Name    => 'TimeEstimated',
+        Default => $ARGS{TimeEstimated} || '',
+        InUnits => $ARGS{'TimeEstimated-TimeUnits'}
+        ),
+
+    loc("Time Worked") => $m->scomp(
+        "/Elements/EditTimeValue",
+        Name    => 'TimeWorked',
+        Default => $ARGS{TimeWorked} || '',
+        InUnits => $ARGS{'TimeWorked-TimeUnits'}
+    ),
+
+    loc("Time Left") => $m->scomp(
+        "/Elements/EditTimeValue",
+        Name    => 'TimeLeft',
+        Default => $ARGS{TimeLeft} || '',
+        InUnits => $ARGS{'TimeLeft-TimeUnits'}
+    ),
+);
+
+</%perl>
+</&>
+<&|/Widgets/TitleBox, title => loc("Dates"),
+		title_class=> 'inverse',  
+		 color => "#663366"  &>
+
+<%perl>
+$showrows->(
+    loc("Starts") => $m->scomp( "/Elements/SelectDate", Name => "Starts", Default => ( $ARGS{Starts} || '' )),
+    loc("Due")    => $m->scomp( "/Elements/SelectDate", Name => "Due",    Default => ($ARGS{Due}    || '' ))
+);
+
+</%perl>
+</&>
+
+<&|/Widgets/TitleBox, title => loc('Links'), title_class=> 'inverse' &>
+
+<em><%loc("(Enter ticket ids or URLs, separated with spaces)")%></em>
+
+<%perl>
+$showrows->(
+    loc("Depends on")     => '<input size="10" name="new-DependsOn" value="' . ($ARGS{'new-DependsOn'} || '' ). '" />',
+    loc("Depended on by") => '<input size="10" name="DependsOn-new" value="' . ($ARGS{'DependsOn-new'} || '' ) . '" />',
+    loc("Parents")        => '<input size="10" name="new-MemberOf" value="' . ($ARGS{'new-MemberOf'} || '') . '" />',
+    loc("Children")       => '<input size="10" name="MemberOf-new" value="' . ($ARGS{'MemberOf-new'} || '') . '" />',
+    loc("Refers to")      => '<input size="10" name="new-RefersTo" value="' . ($ARGS{'new-RefersTo'} || '') . '" />',
+    loc("Referred to by") => '<input size="10" name="RefersTo-new" value="' . ($ARGS{'RefersTo-new'} || ''). '" />'
+);
+</%perl>
+
+</&>
+
+
+<& /Elements/Submit, Label => loc("Create") &>
+</form>
+</&>
+</&>
diff --git a/html/m/ticket/show b/html/m/ticket/show
index 701f52c..9909a85 100644
--- a/html/m/ticket/show
+++ b/html/m/ticket/show
@@ -2,8 +2,100 @@
 $id => undef
 </%args>
 <%init>
-my $t = RT::Ticket->new($session{CurrentUser});
-$t->Load($id);
+my $TicketObj;
+my @Actions; 
+
+if ($ARGS{'id'} eq 'new') {
+    # {{{ Create a new ticket
+
+    my $Queue = new RT::Queue( $session{'CurrentUser'} );
+    $Queue->Load($ARGS{'Queue'});
+    unless ( $Queue->id ) {
+        Abort('Queue not found');
+    }
+
+    unless ( $Queue->CurrentUserHasRight('CreateTicket') ) {
+        Abort('You have no permission to create tickets in that queue.');
+    }
+
+    ($TicketObj, @Actions) = CreateTicket(
+        Attachments => delete $session{'Attachments'},
+        %ARGS,
+    );
+    unless ( $TicketObj->CurrentUserHasRight('ShowTicket') ) {
+        Abort("No permission to view newly created ticket #".$TicketObj->id.".");
+    }
+    # }}}
+} else { 
+    $TicketObj ||= LoadTicket($ARGS{'id'});
+
+    $m->callback( CallbackName => 'BeforeProcessArguments',
+        TicketObj => $TicketObj,
+        ActionsRef => \@Actions, ARGSRef => \%ARGS );
+    if ( defined $ARGS{'Action'} ) {
+        if ($ARGS{'Action'} =~ /^(Steal|Kill|Take|SetTold)$/) {
+            my $action = $1;
+            my ($res, $msg) = $TicketObj->$action();
+            push(@Actions, $msg);
+        }
+    }
+
+    $m->callback(CallbackName => 'ProcessArguments', 
+            Ticket => $TicketObj, 
+            ARGSRef => \%ARGS, 
+            Actions => \@Actions);
+    
+    $ARGS{UpdateAttachments} = $session{'Attachments'};
+    push @Actions,
+        ProcessUpdateMessage(
+        ARGSRef   => \%ARGS,
+        Actions   => \@Actions,
+        TicketObj => $TicketObj,
+        );
+    delete $session{'Attachments'};
+
+    #Process status updates
+    push @Actions, ProcessTicketWatchers(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+    push @Actions, ProcessTicketBasics(  ARGSRef => \%ARGS, TicketObj => $TicketObj );
+    push @Actions, ProcessTicketLinks(   ARGSRef => \%ARGS, TicketObj => $TicketObj );
+    push @Actions, ProcessTicketDates(   ARGSRef => \%ARGS, TicketObj => $TicketObj );
+    push @Actions, ProcessObjectCustomFieldUpdates(ARGSRef => \%ARGS, TicketObj => $TicketObj );
+
+    # XXX: we shouldn't block actions here if user has no right to see the ticket,
+    # but we should allow him to see actions he has done
+    unless ($TicketObj->CurrentUserHasRight('ShowTicket')) {
+        Abort("No permission to view ticket");
+    }
+    if ( $ARGS{'MarkAsSeen'} ) {
+        $TicketObj->SetAttribute(
+            Name => 'User-'. $TicketObj->CurrentUser->id .'-SeenUpTo',
+            Content => $TicketObj->LastUpdated,
+        );
+        push @Actions, loc('Marked all messages as seen');
+    }
+}
+
+$m->callback(
+    CallbackName => 'BeforeDisplay',
+    TicketObj => \$TicketObj,
+    Actions => \@Actions,
+    ARGSRef => \%ARGS,
+);
+
+# This code does automatic redirection if any updates happen. 
+
+if (@Actions) {
+
+    # We've done something, so we need to clear the decks to avoid
+    # resubmission on refresh.
+    # But we need to store Actions somewhere too, so we don't lose them.
+    my $key = Digest::MD5::md5_hex( rand(1024) );
+    push @{ $session{"Actions"}->{$key} ||= [] }, @Actions;
+    $session{'i'}++;
+    my $url = RT->Config->Get('WebURL') . "/m/ticket/show?id=" . $TicketObj->id . "&results=" . $key;
+    $url .= '#' . $ARGS{Anchor} if $ARGS{Anchor};
+    RT::Interface::Web::Redirect($url);
+}
 </%init>
 <&| /m/_elements/wrapper &>
 
@@ -11,27 +103,27 @@ $t->Load($id);
     <&| /Widgets/TitleBox, title => loc('The Basics'),
         class => 'ticket-info-basics',
     &>
-        <& /Ticket/Elements/ShowBasics, Ticket => $t &>
+        <& /Ticket/Elements/ShowBasics, Ticket => $TicketObj &>
     </&>
 
-% if ($t->CustomFields->First) {
+% if ($TicketObj->CustomFields->First) {
     <&| /Widgets/TitleBox, title => loc('Custom Fields'),
-        title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$t->Id,
+        title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$TicketObj->Id,
         class => 'ticket-info-cfs',
     &>
-        <& /Ticket/Elements/ShowCustomFields, Ticket => $t &>
+        <& /Ticket/Elements/ShowCustomFields, Ticket => $TicketObj &>
     </&>
 % }
 
     <&| /Widgets/TitleBox, title => loc('People'),
         class => 'ticket-info-people',
     &>
-        <& /Ticket/Elements/ShowPeople, Ticket => $t &>
+        <& /Ticket/Elements/ShowPeople, Ticket => $TicketObj &>
     </&>
 
-    <& /Ticket/Elements/ShowAttachments, Ticket => $t &>
+    <& /Ticket/Elements/ShowAttachments, Ticket => $TicketObj &>
 
-    <& /Ticket/Elements/ShowRequestor, Ticket => $t &>
+    <& /Ticket/Elements/ShowRequestor, Ticket => $TicketObj &>
 
 % if ( RT->Config->Get('EnableReminders') ) {
     <&|/Widgets/TitleBox, title => loc("Reminders"),
@@ -39,7 +131,7 @@ $t->Load($id);
     &>
         <table><tr><td>
             <form action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post">
-                <& /Ticket/Elements/Reminders, Ticket => $t, ShowCompleted => 0 &>
+                <& /Ticket/Elements/Reminders, Ticket => $TicketObj, ShowCompleted => 0 &>
                 <div align="right"><input type="submit" class="button" value="<&|/l&>Save</&>" /></div>
             </form>
         </td></tr></table>
@@ -49,13 +141,13 @@ $t->Load($id);
     <&| /Widgets/TitleBox, title => loc("Dates"),
         class => 'ticket-info-dates',
     &>
-        <& /Ticket/Elements/ShowDates, Ticket => $t &>
+        <& /Ticket/Elements/ShowDates, Ticket => $TicketObj &>
     </&>
 
     <&| /Widgets/TitleBox, title => loc('Links'),
         class => 'ticket-info-links',
     &>
-        <& /Elements/ShowLinks, Ticket => $t &>
+        <& /Elements/ShowLinks, Ticket => $TicketObj &>
     </&>
 
 </&>

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



More information about the Bps-public-commit mailing list