diff options
Diffstat (limited to 'rt/share/html/REST')
27 files changed, 3776 insertions, 0 deletions
diff --git a/rt/share/html/REST/1.0/Forms/attachment/default b/rt/share/html/REST/1.0/Forms/attachment/default new file mode 100644 index 000000000..05ef02c9e --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/attachment/default @@ -0,0 +1,102 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/attachment/default +%# +<%ARGS> +$id +$args => undef +</%ARGS> +<%INIT> +my @data; +my ($c, $o, $k, $e) = ("", [], {}, ""); +my $attachment = new RT::Attachment $session{CurrentUser}; + +$attachment->Load($id); +unless ( $attachment->Id ) { + return [ "# Attachment $id does not exist.", [], {}, 1 ]; +} +unless ( $attachment->Id eq $id ) { + return [ "# Invalid attachment id: $id", [], {}, 1 ]; +} + +my @arglist = split( '/', $args || "" ); +my $content; + +if ( @argslist and $arglist[0] eq 'content' ) { + $c = $attachment->OriginalContent; +} else { + my @data; + push @data, [ id => "attachment/" . $attachment->Id ]; + push @data, [ Subject => $attachment->Subject ]; + push @data, [ Creator => $attachment->Creator ]; + push @data, [ Created => $attachment->Created ]; + push @data, [ Transaction => $attachment->TransactionId ]; + push @data, [ Parent => "attachment/" . $attachment->Parent ]; + push @data, [ MessageId => $attachment->MessageId ]; + push @data, [ Filename => $attachment->Filename ]; + push @data, [ ContentType => $attachment->ContentType ]; + push @data, [ ContentEncoding => $attachment->ContentEncoding ]; + push @data, [ Headers => $attachment->Headers ]; + if ( $attachment->ContentType =~ m|^text/| ) { + push @data, [ Content => $attachment->Content ]; + } else { + push @data, + [ Content => + "Content is not text and will not be displayed!\n" + . "Use \"rt show attachment/<id>/content [> file.ext]\" to get the content." + ]; + } + + my %k = map {@$_} @data; + $o = [ map { $_->[0] } @data ]; + $k = \%k; +} + +return [ $c, $o, $k, $e ]; + +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/group/customfields b/rt/share/html/REST/1.0/Forms/group/customfields new file mode 100644 index 000000000..7341bac33 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/group/customfields @@ -0,0 +1,96 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/group/customfields +%# +<%ARGS> +$id +$format => 's' +$changes => {} +</%ARGS> +<%perl> +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my $group = new RT::Group $session{CurrentUser}; + +$group->Load($id); +if (!$group->Id) { + return [ "# Group $id does not exist.", [], {}, 1 ]; +} + +if (%$changes) { + $e = 1; + $c = "Cannot modify Group CF definitions via REST"; + goto DONE; +} + +my @data; + +push @data, [ id => "group/" . $group->Id ]; +my $gcfs = $group->CustomFields; +while ( my $gcf = $gcfs->Next() ) { + if ( $format eq "l" ) { + my $cfadmin + = ( $gcf->SingleValue ? 'SingleValue' : 'MultiValue' ) + . $gcf->Type + . ( $gcf->Pattern ? ( ' ' . $gcf->FriendlyPattern ) : '' ); + + push @data, + [ $gcf->Name . ' (' . $gcf->Description . ')' => $cfadmin ]; + } else { + push @data, [ $gcf->Name => "" ]; + } +} + +my %k = map {@$_} @data; +$o = [ map { $_->[0] } @data ]; +$k = \%k; + +DONE: +$c ||= join("\n", @comments) if @comments; +return [ $c, $o, $k, $e ]; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/group/default b/rt/share/html/REST/1.0/Forms/group/default new file mode 100644 index 000000000..b286c85fa --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/group/default @@ -0,0 +1,203 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/group/default +%# +<%ARGS> +$id +$format => 's' +$fields => undef # these are the fields passed to the rt "-f" flag. +$changes => {} +</%ARGS> +<%perl> +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my %data = %$changes; +my $group = new RT::Group $session{CurrentUser}; +my @fields = qw(Name Description); +my %fields = map { lc $_ => $_ } @fields; + +if ($id ne 'new') { + $group->Load($id); + if (!$group->Id) { + return [ "# Group $id does not exist.", [], {}, 1 ]; + } +} +else { + if (%data == 0) { + return [ + "# Required: Name", + [ qw(id Name Description) ], + { + id => "group/new", + Name => "", + Description => "" + }, + 0 + ]; + } + else { + my %v; + my %create = %fields; + $create{name} = "Name"; + $create{description} = "Description"; + # Do any fields need to be excluded here? + + foreach my $k (keys %data) { + if (exists $create{lc $k}) { + $v{$create{lc $k}} = delete $data{$k}; + } + } + + $group->CreateUserDefinedGroup(%v); + unless ($group->Id) { + return [ "# Could not create group.", [], {}, 1 ]; + } + + $id = $group->Id; + delete $data{id}; + push(@comments, "# Group $id created."); + goto DONE if %data == 0; + } +} + +if (%data == 0) { + my @data; + + push @data, [ id => "group/".$group->Id ]; + push @data, [ Name => $group->Name ]; + push @data, [ Description => $group->Description ]; + + + # Members + my $gms = []; + my $GroupMembers = $group->MembersObj(); + while ( my $mo = $GroupMembers->Next() ) { + if ( $mo->MemberObj->IsGroup ) { + my $us = $mo->MemberObj->Object->UserMembersObj(); + my @users; + while ( my $u = $us->Next() ) { + push @users, $u->RealName . ' <' . $u->EmailAddress . '>'; + } + push @$gms, + 'GROUP [' + . $mo->MemberObj->Object->Name . ']' . ' (' + . join( ';', @users ) . ')'; + } elsif ( $mo->MemberObj->IsUser ) { + push @$gms, + $mo->MemberObj->Object->RealName . ' <' + . $mo->MemberObj->Object->EmailAddress . '>'; + } + } + push @data, [ Members => $gms ]; + + # Custom fields + my $CustomFields = $group->CustomFields; + while ( my $CustomField = $CustomFields->Next() ) { + next + unless ( !%$fields + || exists $fields->{ lc "CF-" . $CustomField->Name } ); + next unless $CustomField->CurrentUserHasRight('SeeCustomField'); + my $CFvalues = $group->CustomFieldValues( $CustomField->Id ); + my @CFvalues; + while ( my $CFvalue = $CFvalues->Next() ) { + push @CFvalues, $CFvalue->Content; + } + push @data, [ "CF-" . $CustomField->Name => \@CFvalues ]; + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; +} +else { + my ($get, $set, $key, $val, $n, $s); + + foreach $key (keys %data) { + $val = $data{$key}; + $key = lc $key; + $n = 1; + + if ($key eq 'name' || $key eq 'description' || exists $fields{$key}) + { + if (exists $fields{$key}) { + $key = $fields{$key}; + } + else { + $key = "Description" if $key eq 'description'; + $key = "Name" if $key eq 'name'; + } + $set = "Set$key"; + + next if $val eq $group->$key; + ($n, $s) = $group->$set($val); + } + elsif ($key ne 'id') { + $n = 0; + $s = "Unknown field."; + } + + SET: + if ($n == 0) { + $e = 1; + push @comments, "# $key: $s"; + unless (@$o) { + my %o = keys %$changes; + delete @o{"id", @fields}; + @$o = ("id", @fields, keys %o); + $k = $changes; + } + } + } + + push(@comments, "# Group $id updated.") unless $n == 0; +} + +DONE: +$c ||= join("\n", @comments) if @comments; +return [ $c, $o, $k, $e ]; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/group/ns b/rt/share/html/REST/1.0/Forms/group/ns new file mode 100644 index 000000000..c2359b231 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/group/ns @@ -0,0 +1,62 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/group/ns +%# +<%ARGS> +$id +</%ARGS> +<%perl> +use RT::Groups; + +my $groups = new RT::Groups $session{CurrentUser}; +$groups->Limit(FIELD => 'Name', OPERATOR => '=', VALUE => $id); +if ($groups->Count == 0) { + return (0, "No group named $id exists."); +} +return $groups->Next->Id; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/queue/customfields b/rt/share/html/REST/1.0/Forms/queue/customfields new file mode 100644 index 000000000..a4f05fccd --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/queue/customfields @@ -0,0 +1,96 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/queue/customfields +%# +<%ARGS> +$id +$format => 's' +$changes => {} +</%ARGS> +<%perl> +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my $queue = new RT::Queue $session{CurrentUser}; + +$queue->Load($id); +if (!$queue->Id) { + return [ "# Queue $id does not exist.", [], {}, 1 ]; +} + +if (%$changes) { + $e = 1; + $c = "Cannot modify Queue CF definitions via REST"; + goto DONE; +} + +my @data; + +push @data, [ id => "queue/" . $queue->Id ]; +my $qcfs = $queue->CustomFields; +while ( my $qcf = $qcfs->Next() ) { + if ( $format eq "l" ) { + my $cfadmin + = ( $qcf->SingleValue ? 'SingleValue' : 'MultiValue' ) + . $qcf->Type + . ( $qcf->Pattern ? ( ' ' . $qcf->FriendlyPattern ) : '' ); + + push @data, + [ $qcf->Name . ' (' . $qcf->Description . ')' => $cfadmin ]; + } else { + push @data, [ $qcf->Name => "" ]; + } +} + +my %k = map {@$_} @data; +$o = [ map { $_->[0] } @data ]; +$k = \%k; + +DONE: +$c ||= join("\n", @comments) if @comments; +return [ $c, $o, $k, $e ]; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/queue/default b/rt/share/html/REST/1.0/Forms/queue/default new file mode 100755 index 000000000..58691dd45 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/queue/default @@ -0,0 +1,186 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/queue/default +%# +<%ARGS> +$id +$format => 's' +$fields => undef # these are the fields passed to the rt "-f" flag. +$changes => {} +</%ARGS> +<%perl> +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my %data = %$changes; +my $queue = new RT::Queue $session{CurrentUser}; +my @fields = qw(Name Description CorrespondAddress CommentAddress + InitialPriority FinalPriority DefaultDueIn); +my %fields = map { lc $_ => $_ } @fields; + +if ($id ne 'new') { + $queue->Load($id); + if (!$queue->Id) { + return [ "# Queue $id does not exist.", [], {}, 1 ]; + } +} +else { + if (keys %data == 0) { + return [ + "# Required: Name", + [ "id", @fields ], + { + id => 'queue/new', + Name => '<queue name>', + Description => "", + CommentAddress => "", + CorrespondAddress => "", + InitialPriority => "", + FinalPriority => "", + DefaultDueIn => "", + }, + 0 + ]; + } + else { + my %v; + my %create = %fields; + + foreach my $k (keys %data) { + if (exists $create{lc $k}) { + $v{$create{lc $k}} = delete $data{$k}; + } + } + + if ($v{Name} eq '<queue name>') { + my %o = keys %$changes; + delete @o{"id", @fields}; + return [ + "# Please set the queue name.", + [ "id", @fields, keys %o ], $changes, 1 + ]; + } + + $queue->Create(%v); + unless ($queue->Id) { + return [ "# Could not create queue.", [], {}, 1 ]; + } + + delete $data{id}; + $id = $queue->Id; + push(@comments, "# Queue $id created."); + goto DONE if keys %data == 0; + } +} + +if ( keys %data == 0) { + my @data; + + push @data, [ id => "queue/".$queue->Id ]; + foreach my $key (@fields) { + push @data, [ $key => $queue->$key ]; + } + + # Custom fields + my $CustomFields = $queue->CustomFields; + while ( my $CustomField = $CustomFields->Next() ) { + next + unless ( !%$fields + || exists $fields->{ lc "CF-" . $CustomField->Name } ); + next unless $CustomField->CurrentUserHasRight('SeeCustomField'); + my $CFvalues = $queue->CustomFieldValues( $CustomField->Id ); + my @CFvalues; + while ( my $CFvalue = $CFvalues->Next() ) { + push @CFvalues, $CFvalue->Content; + } + push @data, [ "CF-" . $CustomField->Name => \@CFvalues ]; + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; +} +else { + my ($get, $set, $key, $val, $n, $s); + + foreach $key (keys %data) { + $val = $data{$key}; + $key = lc $key; + $n = 1; + + if (exists $fields{$key}) { + $key = $fields{$key}; + $set = "Set$key"; + + next if $val eq $queue->$key; + ($n, $s) = $queue->$set($val); + } + elsif ($key ne 'id') { + $n = 0; + $s = "Unknown field."; + } + + SET: + if ($n == 0) { + $e = 1; + push @comments, "# $key: $s"; + unless (@$o) { + my %o = keys %$changes; + delete @o{"id", @fields}; + @$o = ("id", @fields, keys %o); + $k = $changes; + } + } + } + + push(@comments, "# Queue $id updated.") unless $n == 0; +} + +DONE: +$c ||= join("\n", @comments) if @comments; +return [ $c, $o, $k, $e ]; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/queue/ns b/rt/share/html/REST/1.0/Forms/queue/ns new file mode 100755 index 000000000..dea51f69f --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/queue/ns @@ -0,0 +1,62 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/queue/ns +%# +<%ARGS> +$id +</%ARGS> +<%perl> +use RT::Queues; + +my $queues = new RT::Queues $session{CurrentUser}; +$queues->Limit(FIELD => 'Name', OPERATOR => '=', VALUE => $id); +if ($queues->Count == 0) { + return (0, "No queue named $id exists."); +} +return $queues->Next->Id; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields b/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields new file mode 100644 index 000000000..27db9345b --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/queue/ticketcustomfields @@ -0,0 +1,97 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/queue/ticketcustomfields +%# +<%ARGS> +$id +$format => 's' +$changes => {} +</%ARGS> +<%perl> +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my $queue = new RT::Queue $session{CurrentUser}; + +$queue->Load($id); +if (!$queue->Id) { + return [ "# Queue $id does not exist.", [], {}, 1 ]; +} + +if (%$changes) { + $e = 1; + $c = "Cannot modify Queue CF definitions via REST"; + goto DONE; +} + +my @data; + +push @data, [ id => "queue/" . $queue->Id ]; +my $qcfs = RT::CustomFields->new($session{CurrentUser}); +$qcfs->LimitToGlobalOrQueue($id); +while ( my $qcf = $qcfs->Next() ) { + if ( $format eq "l" ) { + my $cfadmin + = ( $qcf->SingleValue ? 'SingleValue' : 'MultiValue' ) + . $qcf->Type + . ( $qcf->Pattern ? ( ' ' . $qcf->FriendlyPattern ) : '' ); + + push @data, + [ $qcf->Name . ' (' . $qcf->Description . ')' => $cfadmin ]; + } else { + push @data, [ $qcf->Name => "" ]; + } +} + +my %k = map {@$_} @data; +$o = [ map {$_->[0]} @data ]; +$k = \%k; + +DONE: +$c ||= join("\n", @comments) if @comments; +return [ $c, $o, $k, $e ]; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/ticket/attachments b/rt/share/html/REST/1.0/Forms/ticket/attachments new file mode 100755 index 000000000..33dd888fc --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/attachments @@ -0,0 +1,135 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/attachments +%# +<%ARGS> +$id +$args => undef +</%ARGS> +<%INIT> +my @data; +my ($c, $o, $k, $e) = ("", [], {}, ""); +my $ticket = new RT::Ticket $session{CurrentUser}; + +$ticket->Load($id); +unless ($ticket->Id) { + return [ "# Ticket $id does not exist.", [], {}, 1 ]; +} + +my @arglist = split('/', $args || ''); +my ($aid, $content); + +if ( defined $arglist[1] && $arglist[1] eq 'content') { + $aid = $arglist[0]; + $content = 1; +} else { + $aid = $args; + $content = 0; +} + +if ($aid) { + unless ($aid =~ /^\d+$/) { + return [ "# Invalid attachment id: $aid", [], {}, 1 ]; + } + my $attachment = new RT::Attachment $session{CurrentUser}; + $attachment->Load($aid); + unless ($attachment->Id eq $aid) { + return [ "# Invalid attachment id: $aid", [], {}, 1 ]; + } + if ($content) { + $c = $attachment->OriginalContent; + # if we're sending a binary attachment (and only the attachment) + # flag it so bin/rt knows to special case it + if ($attachment->ContentType !~ /^text\//) { + $r->content_type($attachment->ContentType); + } + } else { + my @data; + push @data, [ id => $attachment->Id ]; + push @data, [ Subject => $attachment->Subject ]; + push @data, [ Creator => $attachment->Creator ]; + push @data, [ Created => $attachment->Created ]; + push @data, [ Transaction => $attachment->TransactionId ]; + push @data, [ Parent => $attachment->Parent ]; + push @data, [ MessageId => $attachment->MessageId ]; + push @data, [ Filename => $attachment->Filename ]; + push @data, [ ContentType => $attachment->ContentType ]; + push @data, [ ContentEncoding => $attachment->ContentEncoding ]; + push @data, [ Headers => $attachment->Headers ]; + push @data, [ Content => $attachment->Content ]; + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; + } + +} +else { + my @attachments; + my $transactions = $ticket->Transactions; + while (my $t = $transactions->Next) { + my $attachments = $t->Attachments; + while (my $a = $attachments->Next) { + my $size = length($a->Content || ''); + if ($size > 1024) { $size = int($size/102.4)/10 . "k" } + else { $size .= "b" } + push @attachments, $a->Id.": ".($a->Filename || '(Unnamed)')." (".$a->ContentType . " / ".$size.")"; + } + } + + if (@attachments) { + $o = [ "id", "Attachments" ]; + $k = { + id => "ticket/".$ticket->Id."/attachments", + Attachments => \@attachments + }; + } +} + +return [ $c, $o, $k, $e ]; +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/comment b/rt/share/html/REST/1.0/Forms/ticket/comment new file mode 100755 index 000000000..a7d59edc0 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/comment @@ -0,0 +1,152 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/comment +%# +<%ARGS> +$id +%changes +</%ARGS> +<%INIT> +use MIME::Entity; +use LWP::MediaTypes; +use RT::Interface::REST; +use File::Temp qw(tempfile); + +$RT::Logger->debug("Got ticket id=$id for comment"); +$RT::Logger->debug("Got args @{[keys(%changes)]}."); + +my $ticket = new RT::Ticket $session{CurrentUser}; +my ($c, $o, $k, $e) = ("", [], {}, 0); + +# http://.../REST/1.0/ticket/1/comment +$ticket->Load($id); +if (!$ticket->Id) { + $e = 1; + $c = "# Ticket $id does not exist."; + goto OUTPUT; +} + +my $action; +($action = $changes{Action}) =~ s/^(.)(.*)$/\U$1\L$2\E/; +unless ($action =~ /^(?:Comment|Correspond)$/) { + $e = 1; + $c = "# Invalid action: `$action'."; + goto OUTPUT; +} + +my $text = $changes{Text}; +my @atts = @{ vsplit($changes{Attachment}) }; + +if (!$changes{Text} && @atts == 0) { + $e = 1; + $c = "# Empty comment with no attachments submitted."; + goto OUTPUT; +} + +my $cgi = $m->cgi_object; +my $ent = MIME::Entity->build(Type => "multipart/mixed"); +$ent->attach(Data => $changes{Text}) if $changes{Text}; + +my $i = 1; +foreach my $att (@atts) { + local $/=undef; + my $file = $att; + $file =~ s#^.*[\\/]##; + + my $fh = $cgi->upload("attachment_$i"); + if ($fh) { + my $buf; + my ($w, $tmp) = tempfile(); + my $info = $cgi->uploadInfo($fh); + + while (sysread($fh, $buf, 8192)) { + syswrite($w, $buf); + } + + $ent->attach( + Path => $tmp, + Type => $info->{'Content-Type'} || guess_media_type($tmp), + Filename => $file, + Disposition => "attachment" + ); + } + else { + $e = 1; + $c = "# No attachment for $att."; + goto OUTPUT; + } + + $i++; +} + +unless ($ticket->CurrentUserHasRight('ModifyTicket') || + ($action eq "Comment" && + $ticket->CurrentUserHasRight("CommentOnTicket")) || + ($action eq "Correspond" && + $ticket->CurrentUserHasRight("ReplyToTicket"))) +{ + $e = 1; + $c = "# You are not allowed to $action on ticket $id."; + goto OUTPUT; +} + +my $cc = join ", ", @{ vsplit($changes{Cc}) }; +my $bcc = join ", ", @{ vsplit($changes{Bcc}) }; +my ($n, $s) = $ticket->$action(MIMEObj => $ent, + CcMessageTo => $cc, + BccMessageTo => $bcc, + TimeTaken => $changes{TimeWorked} || 0); +$c = "# ".$s; +if ($changes{Status}) { + my ($status_n, $status_s) = $ticket->SetStatus($changes{'Status'} ); + $c .= "\n# ".$status_s; +} + +OUTPUT: +return [ $c, $o, $k, $e ]; +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/default b/rt/share/html/REST/1.0/Forms/ticket/default new file mode 100755 index 000000000..b82cb5ed6 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/default @@ -0,0 +1,447 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/default +%# +<%ARGS> +$id +$changes => {} +$fields => undef +$args => undef +</%ARGS> +<%INIT> +use MIME::Entity; +use RT::Interface::REST; + +my $cf_spec = RT::Interface::REST->custom_field_spec(1); + +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my %data = %$changes; +my $ticket = new RT::Ticket $session{CurrentUser}; +my @dates = qw(Created Starts Started Due Resolved Told LastUpdated); +my @people = qw(Requestors Cc AdminCc); +my @create = qw(Queue Requestor Subject Cc AdminCc Owner Status Priority + InitialPriority FinalPriority TimeEstimated TimeWorked + TimeLeft Starts Started Due Resolved); +my @simple = qw(Subject Status Priority Disabled TimeEstimated TimeWorked + TimeLeft InitialPriority FinalPriority); +my %dates = map {lc $_ => $_} @dates; +my %people = map {lc $_ => $_} @people; +my %create = map {lc $_ => $_} @create; +my %simple = map {lc $_ => $_} @simple; + +# Are we dealing with an existing ticket? +if ($id ne 'new') { + $ticket->Load($id); + if (!$ticket->Id) { + return [ "# Ticket $id does not exist.", [], {}, 1 ]; + } + elsif (!$ticket->CurrentUserHasRight('ShowTicket') || + (%data && !$ticket->CurrentUserHasRight('ModifyTicket'))) + { + my $act = %data ? "modify" : "display"; + return [ "# You are not allowed to $act ticket $id.", [], {}, 1 ]; + } +} +else { + if (!keys(%data)) { + # GET ticket/new: Return a suitable default form. + # We get defaults from queue/1 (XXX: What if it isn't there?). + my $due = new RT::Date $session{CurrentUser}; + my $queue = new RT::Queue $session{CurrentUser}; + my $starts = new RT::Date $session{CurrentUser}; + $queue->Load(1); + $due->SetToNow; + $due->AddDays($queue->DefaultDueIn) if $queue->DefaultDueIn; + $starts->SetToNow; + + return [ + "# Required: id, Queue", + [ qw(id Queue Requestor Subject Cc AdminCc Owner Status Priority + InitialPriority FinalPriority TimeEstimated Starts Due Text) ], + { + id => "ticket/new", + Queue => $queue->Name, + Requestor => $session{CurrentUser}->Name, + Subject => "", + Cc => [], + AdminCc => [], + Owner => "", + Status => "new", + Priority => $queue->InitialPriority, + InitialPriority => $queue->InitialPriority, + FinalPriority => $queue->FinalPriority, + TimeEstimated => 0, + Starts => $starts->ISO, + Due => $due->ISO, + Text => "", + }, + 0 + ]; + } + else { + # We'll create a new ticket, and fall through to set fields that + # can't be set in the call to Create(). + my (%v, $text); + + foreach my $k (keys %data) { + # flexibly parse any dates + if ($dates{lc $k}) { + my $time = new RT::Date $session{CurrentUser}; + $time->Set(Format => 'unknown', Value => $data{$k}); + $data{$k} = $time->ISO; + } + + if (exists $create{lc $k}) { + $v{$create{lc $k}} = delete $data{$k}; + } + # Set custom field + elsif ($k =~ /^$cf_spec/) { + my $cf = RT::CustomField->new( $RT::SystemUser ); + my $cfk = $1 || $2; + unless($cf->LoadByName( Name => $cfk )) { + push @comments, "# Invalid custom field name ($cfk)"; + delete $data{$k}; + next; + } + $v{"CustomField-".$cf->Id()} = delete $data{$k}; + } + elsif (lc $k eq 'text') { + $text = delete $data{$k}; + } + } + + # people fields allow multiple values + $v{$_} = vsplit($v{$_}) foreach ( grep $create{lc $_}, @people ); + + if ($text) { + $v{MIMEObj} = + MIME::Entity->build( + From => $session{CurrentUser}->EmailAddress, + Subject => $v{Subject}, + Data => $text + ); + } + + my($tid,$trid,$terr) = $ticket->Create(%v); + unless ($tid) { + push(@comments, "# Could not create ticket."); + push(@comments, "# " . $terr); + goto DONE; + } + + delete $data{id}; + $id = $ticket->Id; + push(@comments, "# Ticket $id created."); + # see if the hash is empty + goto DONE if ! keys(%data); + } +} + +# Now we know we're dealing with an existing ticket. +if (!keys(%data)) { + my ($time, $key, $val, @data); + + push @data, [ id => "ticket/".$ticket->Id ]; + push @data, [ Queue => $ticket->QueueObj->Name ] + if (!%$fields || exists $fields->{lc 'Queue'}); + push @data, [ Owner => $ticket->OwnerObj->Name ] + if (!%$fields || exists $fields->{lc 'Owner'}); + push @data, [ Creator => $ticket->CreatorObj->Name ] + if (!%$fields || exists $fields->{lc 'Creator'}); + + foreach (qw(Subject Status Priority InitialPriority FinalPriority)) { + next unless (!%$fields || (exists $fields->{lc $_})); + push @data, [$_ => $ticket->$_ ]; + } + + foreach $key (@people) { + next unless (!%$fields || (exists $fields->{lc $key})); + push @data, [ $key => [ $ticket->$key->MemberEmailAddresses ] ]; + } + + $time = new RT::Date ($session{CurrentUser}); + foreach $key (@dates) { + next unless (!%$fields || (exists $fields->{lc $key})); + $time->Set(Format => 'sql', Value => $ticket->$key); + push @data, [ $key => $time->AsString ]; + } + + $time = new RT::Date ($session{CurrentUser}); + foreach $key (qw(TimeEstimated TimeWorked TimeLeft)) { + next unless (!%$fields || (exists $fields->{lc $key})); + $val = $ticket->$key || 0; + $val = "$val minutes" if $val; + push @data, [ $key => $val ]; + } + + # Display custom fields + my $CustomFields = $ticket->CustomFields; + while (my $cf = $CustomFields->Next()) { + next unless !%$fields + || exists $fields->{"cf.{".lc($cf->Name)."}"} + || exists $fields->{"cf-".lc $cf->Name}; + + my $vals = $ticket->CustomFieldValues($cf->Id()); + my @out = (); + if ( $cf->SingleValue ) { + my $v = $vals->Next; + push @out, $v->Content if $v; + } + else { + while (my $v = $vals->Next()) { + my $content = $v->Content; + $content =~ s/'/\\'/g; + if ( $v->Content =~ /,/ ) { + push @out, q{'} . $content . q{'}; + } + else { + push @out, $content; + } + } + } + push @data, [ ('CF.{' . $cf->Name . '}') => join ',', @out ]; + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; +} +else { + my ($get, $set, $key, $val, $n, $s); + + foreach $key (keys %data) { + $val = $data{$key}; + $key = lc $key; + $n = 1; + + if (ref $val eq 'ARRAY') { + unless ($key =~ /^(?:Requestors|Cc|AdminCc)$/i) { + $n = 0; + $s = "$key may have only one value."; + goto SET; + } + } + + if ($key =~ /^queue$/i) { + next if $val eq $ticket->QueueObj->Name; + ($n, $s) = $ticket->SetQueue($val); + } + elsif ($key =~ /^owner$/i) { + next if $val eq $ticket->OwnerObj->Name; + ($n, $s) = $ticket->SetOwner($val); + } + elsif (exists $simple{$key}) { + $key = $simple{$key}; + $set = "Set$key"; + + next if (($val eq $ticket->$key)|| ($ticket->$key =~ /^\d+$/ && $val == $ticket->$key)); + ($n, $s) = $ticket->$set("$val"); + } + elsif (exists $dates{$key}) { + $key = $dates{$key}; + + # We try to detect whether it should update a field by checking + # whether its current value equals the entered value. Since the + # LastUpdated field is automatically updated as other columns are + # changed, it is not properly skipped. Users cannot update this + # field anyway. + next if $key eq 'LastUpdated'; + + $set = "Set$key"; + + my $time = new RT::Date $session{CurrentUser}; + $time->Set(Format => 'sql', Value => $ticket->$key); + next if ($val =~ /^not set$/i || $val eq $time->AsString); + + $time->Set(Format => 'unknown', Value => $val); + ($n, $s) = $ticket->$set($time->ISO); + } + elsif (exists $people{$key}) { + $key = $people{$key}; + my ($p, @msgs); + + my %new = map {$_=>1} @{ vsplit($val) }; + my %old = map {$_=>1} $ticket->$key->MemberEmailAddresses; + my $type = $key eq 'Requestors' ? 'Requestor' : $key; + + foreach $p (keys %old) { + unless (exists $new{$p}) { + ($s, $n) = $ticket->DeleteWatcher(Type => $type, + Email => $p); + push @msgs, [ $s, $n ]; + } + } + foreach $p (keys %new) { + # XXX: This is a stupid test. + unless ($p =~ /^[\w.+-]+\@([\w.-]+\.)*\w+.?$/) { + $s = 0; + $n = "$p is not a valid email address."; + push @msgs, [ $s, $n ]; + next; + } + unless ($ticket->IsWatcher(Type => $type, Email => $p)) { + ($s, $n) = $ticket->AddWatcher(Type => $type, + Email => $p); + push @msgs, [ $s, $n ]; + } + } + + $n = 1; + if (@msgs = grep {$_->[0] == 0} @msgs) { + $n = 0; + $s = join "\n", map {"# ".$_->[1]} @msgs; + $s =~ s/^# //; + } + } + # Set custom field + elsif ($key =~ /^$cf_spec/) { + my $cf = RT::CustomField->new( $RT::SystemUser ); + $key = $1 || $2; + if (not $cf->LoadByName( Name => $key )) { + $n = 0; + $s = "Unknown custom field."; + } + else { + my $vals = $ticket->CustomFieldValues($cf->id); + + if ( $cf->SingleValue ) { + my $old = $vals->Next; + if ( $old ) { + if ( $val ne $old->Content ) { + $old->Delete; + ($n, $s) = $ticket->AddCustomFieldValue( + Field => $cf, Value => $val ); + $s =~ s/^# // if defined $s; + } + } + else { + ($n, $s) = $ticket->AddCustomFieldValue( + Field => $cf, Value => $val ); + $s =~ s/^# // if defined $s; + } + } + else { + my @new; + my ( $a, $b ) = split /,/, $val, 2; + while ($a) { + no warnings 'uninitialized'; + if ( $a =~ /^'/ ) { + my $s = $a; + while ( $a !~ /'$/ || ( $a !~ /(\\\\)+'$/ + && $a =~ /(\\)+'$/ ) ) { + ( $a, $b ) = split /,/, $b, 2; + $s .= ',' . $a; + } + $s =~ s/^'//; + $s =~ s/'$//; + $s =~ s/\\'/'/g; + push @new, $s; + } + elsif ( $a =~ /^q{/ ) { + my $s = $a; + while ( $a !~ /}$/ ) { + ( $a, $b ) = split /,/, $b, 2; + $s .= ',' . $a; + } + $s =~ s/^q{//; + $s =~ s/}//; + push @new, $s; + } + else { + push @new, $a; + } + ( $a, $b ) = split /,/, $b, 2; + } + + my %new; + $new{$_}++ for @new; + + while (my $v = $vals->Next()) { + my $c = $v->Content; + if ( $new{$c} ) { + $new{$c}--; + } + else { + $v->Delete(); + } + } + for ( @new ) { + while ( $new{$_} && $new{$_}-- ) { + ($n, $s) = $ticket->AddCustomFieldValue( + Field => $cf, Value => $_ ); + $s =~ s/^# // if defined $s; + } + } + } + } + } + elsif ($key ne 'id' && $key ne 'type' && $key ne 'creator') { + $n = 0; + $s = "Unknown field."; + } + + SET: + if ($n == 0) { + $e = 1; + push @comments, "# $key: $s"; + unless (@$o) { + # move id forward + @$o = ("id", grep { $_ ne 'id' } keys %$changes); + $k = $changes; + } + } + } + push(@comments, "# Ticket ".$ticket->id." updated.") unless $n == 0; +} + +DONE: +$c ||= join("\n", @comments) if @comments; +return [$c, $o, $k, $e]; + +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/history b/rt/share/html/REST/1.0/Forms/ticket/history new file mode 100755 index 000000000..4f14f4299 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/history @@ -0,0 +1,205 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/history +%# +<%ARGS> +$id +$args => undef +$format => undef +$fields => undef +</%ARGS> +<%INIT> +my $ticket = new RT::Ticket $session{CurrentUser}; +my ($c, $o, $k, $e) = ("", [], {}, ""); + +$ticket->Load($id); +unless ($ticket->Id) { + return [ "# Ticket $id does not exist.", [], {}, 1 ]; +} + +my $trans = $ticket->Transactions(); +my $total = $trans->Count(); + +if ( $args ) { + chomp $args; +} +else { + $args = ''; +} + +my @arglist = split('/', $args ); +my ($type, $tid); +if (defined $arglist[0] && $arglist[0] eq 'type') { + $type = $arglist[1]; +} elsif ( defined $arglist[0] && $arglist[0] eq 'id') { + $tid = $arglist[1]; +} else { + $type = $args; +} + +if ($type) { + # Create, Set, Status, Correspond, Comment, Give, Steal, Take, Told + # CustomField, AddLink, DeleteLink, AddWatcher, DelWatcher + if ($args =~ /^links?$/) { + $trans->Limit(FIELD => 'Type', OPERATOR => 'LIKE', VALUE => '%Link'); + } + elsif ($args =~ /^watchers?$/) { + $trans->Limit(FIELD => 'Type', OPERATOR => 'LIKE', VALUE => '%Watcher'); + } + else { + $trans->Limit(FIELD => 'Type', OPERATOR => '=', VALUE => $type); + } +} elsif ($tid) { + $trans->Limit(FIELD => 'Id', OPERATOR => '=', VALUE => $tid); +} + +if ($tid) { + my @data; + my $t = new RT::Transaction $session{CurrentUser}; + + # this paragraph limits the transaction ID query to transactions on this ticket. + # Otherwise you can query any transaction from any ticket, which makes no sense. + my $Transactions = $ticket->Transactions; + my $tok=0; + while (my $T = $Transactions->Next()) { + $tok=1 if ($T->Id == $tid) + } + if ($tok) { + $t->Load($tid); + } else { + return [ "# Transaction $tid is not related to Ticket $id", [], {}, 1 ]; + } + + push @data, [ id => $t->Id ]; + push @data, [ Ticket => $t->Ticket ] + if (!%$fields || exists $fields->{lc 'Ticket'}); + push @data, [ TimeTaken => $t->TimeTaken ] + if (!%$fields || exists $fields->{lc 'TimeTaken'}); + push @data, [ Type => $t->Type ] + if (!%$fields || exists $fields->{lc 'Type'}); + push @data, [ Field => $t->Field ] + if (!%$fields || exists $fields->{lc 'Field'}); + push @data, [ OldValue => $t->OldValue ] + if (!%$fields || exists $fields->{lc 'OldValue'}); + push @data, [ NewValue => $t->NewValue ] + if (!%$fields || exists $fields->{lc 'NewValue'}); + push @data, [ Data => $t->Data ] + if (!%$fields || exists $fields->{lc 'Data'}); + push @data, [ Description => $t->Description ] + if (!%$fields || exists $fields->{lc 'Description'}); + push @data, [ Content => $t->Content ] + if (!%$fields || exists $fields->{lc 'Content'}); + + + if (!%$fields || exists $fields->{lc 'Content'}) { + my $creator = new RT::User $session{CurrentUser}; + $creator->Load($t->Creator); + push @data, [ Creator => $creator->Name ]; + } + push @data, [ Created => $t->Created ] + if (!%$fields || exists $fields->{lc 'Created'}); + + if (!%$fields || exists $fields->{lc 'Attachments'}) { + my $attachlist; + my $attachments = $t->Attachments; + while (my $a = $attachments->Next) { + my $size = length($a->Content||''); + if ($size > 1024) { $size = int($size/102.4)/10 . "k" } + else { $size .= "b" } + $attachlist .= "\n" . $a->Id.": ".($a->Filename || "untitled")." (".$size.")"; + } + + push @data, [Attachments => $attachlist]; + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; + +} else { + my (@data, $tids); + $format ||= "s"; + $format = "l" if (%$fields); + + while (my $t = $trans->Next) { + my $tid = $t->Id; + + if ($format eq "l") { + $tids .= "," if $tids; + $tids .= $tid; + } else { + push @$o, $tid; + $k->{$tid} = $t->Description; + } + } + + if ($format eq "l") { + my @tid; + push @tid, "ticket/$id/history/id/$tids"; + my $fieldstring; + foreach my $key (keys %$fields) { + $fieldstring .= "," if $fieldstring; + $fieldstring .= $key; + } + my ($content, $forms); + $m->subexec("/REST/1.0/show", + id => \@tid, + format => $format, + fields => $fieldstring); + return [ $c, $o, $k, $e ]; + } +} + +if (!$c) { + my $sub = $trans->Count(); + $c = "# $sub/$total ($args/total)"; +} + +return [ $c, $o, $k, $e ]; + +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/links b/rt/share/html/REST/1.0/Forms/ticket/links new file mode 100755 index 000000000..783ac7339 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/links @@ -0,0 +1,172 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/links +%# +<%ARGS> +$id +$format => 's' +$changes => undef +</%ARGS> +<%INIT> +my @data; +my $ticket = new RT::Ticket $session{CurrentUser}; + +$ticket->Load($id); +if (!$ticket->Id) { + return [ "# Ticket $id does not exist.", [], {}, 1 ]; +} + +my ($c, $o, $k, $e) = ("", [], {}, 0); +my @fields = qw(DependsOn DependedOnBy RefersTo ReferredToBy Members MemberOf); +my %fields = map { lc $_ => $_ } @fields; + +my %lfields = ( + Members => { Type => 'MemberOf', Mode => 'Base' }, + ReferredToBy => { Type => 'RefersTo', Mode => 'Base' }, + DependedOnBy => { Type => 'DependsOn', Mode => 'Base' }, + MemberOf => { Type => 'MemberOf', Mode => 'Target' }, + RefersTo => { Type => 'RefersTo', Mode => 'Target' }, + DependsOn => { Type => 'DependsOn', Mode => 'Target' }, +); + +if ($changes) { + my ($get, $set, $key, $val, $n, $s); + my %data = %$changes; + my @comments; + + foreach $key (keys %data) { + $val = $data{$key}; + $key = lc $key; + $n = 1; + + if (exists $fields{$key}) { + $key = $fields{$key}; + + my %old; + my $field = $lfields{$key}->{Mode}; + while (my $link = $ticket->$key->Next) { + $old{$link->$field} = 1; + } + + my %new; + foreach my $nkey (@{vsplit($val)}) { + if ($nkey =~ /^\d+$/) { + my $uri = new RT::URI $session{CurrentUser}; + my $tick = new RT::Ticket $session{CurrentUser}; + $tick->Load($nkey); + if ($tick->Id) { + $nkey = $uri->FromObject($tick); + } + else { + $n = 0; + $s = "Ticket $nkey does not exist."; + goto SET; + } + } + $new{$nkey} = 1; + } + + foreach my $u (keys %old) { + if (exists $new{$u}) { + delete $new{$u}; + } + else { + my $type = $lfields{$key}->{Type}; + my $mode = $lfields{$key}->{Mode}; + ($n, $s) = $ticket->DeleteLink(Type => $type, $mode => $u); + goto SET; + } + } + foreach my $u (keys %new) { + my $type = $lfields{$key}->{Type}; + my $mode = $lfields{$key}->{Mode}; + ($n, $s) = $ticket->AddLink(Type => $type, $mode => $u); + goto SET; + } + } + elsif ($key ne 'id' && $key ne 'type') { + $n = 0; + $s = "Unknown field: $key"; + } + + SET: + if ($n == 0) { + $e = 1; + push @comments, "# $key: $s"; + unless (@$o) { + @$o = ("id", @fields); + %$k = %data; + } + } + } + + push(@comments, "# Links for ticket $id updated.") unless @comments; + $c = join("\n", @comments) if @comments; +} +else { + my @data; + + push @data, [ id => "ticket/".$ticket->Id."/links" ]; + foreach my $key (@fields) { + my @val; + + my $field = $lfields{$key}->{Mode}; + while (my $link = $ticket->$key->Next) { + push @val, $link->$field; + } + push(@val, "") if (@val == 0 && defined $format && $format eq 'l'); + push @data, [ $key => [ @val ] ] if @val; + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; +} + +return [ $c, $o, $k, $e ]; +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/merge b/rt/share/html/REST/1.0/Forms/ticket/merge new file mode 100755 index 000000000..3d9181921 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/merge @@ -0,0 +1,96 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/merge +%# +<%ARGS> +$id +$args +</%ARGS> +<%INIT> +use RT::Interface::REST; + +my $into = $args; + +my $ticket = new RT::Ticket $session{CurrentUser}; +my $ticket_into = new RT::Ticket $session{CurrentUser}; +my ($c, $o, $k, $e) = ("", [], {}, 0); + +# http://.../REST/1.0/ticket/1/merge/6 (merges ticket 1 into ticket 6) + +$ticket->Load($id); +if (!$ticket->Id) { + $e = 1; + $c = "# Ticket $id does not exist."; + goto OUTPUT; +} +$ticket_into->Load($into); +if (!$ticket_into->Id) { + $e = 1; + $c = "# Ticket $into does not exist."; + goto OUTPUT; +} + +if (!$ticket->CurrentUserHasRight('ModifyTicket')) { + $e = 1; + $c = "# You are not allowed to modify ticket $id."; + goto OUTPUT; +} + +my ($n, $s) = $ticket->MergeInto($into); + +if ($n == 0) { + $e = 1; + $c = "# Could not complete the merge."; +} +else { + $c = "# Merge completed."; +} + +OUTPUT: +return [ $c, $o, $k, $e ]; +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/ticket/take b/rt/share/html/REST/1.0/Forms/ticket/take new file mode 100755 index 000000000..0b886b010 --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/ticket/take @@ -0,0 +1,135 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/ticket/take +%# +<%ARGS> +$id +%changes +</%ARGS> +<%INIT> +use RT::Interface::REST; + +my $ticket = new RT::Ticket $session{CurrentUser}; +my ($c, $o, $k, $e) = ("", [], {}, 0); + +# http://.../REST/1.0/ticket/1/take +$ticket->Load( $id ); +unless ( $ticket->Id ) { + $e = 1; + $c = "# Ticket $id does not exist."; + goto OUTPUT; +} + +my $action; + +my @comments; + +($action = $changes{Action}) =~ s/^(.)(.*)$/\U$1\L$2\E/; +unless ($action =~ /^(?:Take|Steal|Untake)$/) { + $e = 1; + $c = "# Invalid action: `$action'."; + goto OUTPUT; +} + +my ($status, $msg) = $ticket->$action(); +$c = "# $msg"; +$e = 1 unless $status; +goto OUTPUT; + +#unless ($ticket->CurrentUserHasRight('ModifyTicket') || +# ( ($action eq "Take" || $action eq 'Untake') && +# $ticket->CurrentUserHasRight("TakeTicket")) || +# ($action eq "Steal" && +# $ticket->CurrentUserHasRight("StealTicket"))) +#{ +# $e = 1; +# $c = "# You are not allowed to $action ticket $id."; +# goto OUTPUT; +#} + +#if ( keys %changes ) { +#} +#else { +# # process the form data structure +# my ($key, $val); +# +# foreach $key (keys %data) { +# $val = $data{$key}; +# +# if ($key =~ /^force$/i) { +# if ($val !~ /^(?:0|1)$/) { +# push(@comments, "# invalid value for 'force': $val"); +# goto DONE; +# } +# my ($ret_id, $msg); +# +# ### take +# if ($val == 0) { +# ($ret_id, $msg) = $ticket->Take; +# if (!$ret_id) { +# push(@comments, "# Couldn't take ticket $id: $msg"); +# goto DONE; +# } +# push(@comments, "# Ticket $id taken."); +# } +# ### steal +# else { +# ($ret_id, $msg) = $ticket->Steal; +# if (!$ret_id) { +# push(@comments, "# Couldn't steal ticket $id: $msg"); +# goto DONE; +# } +# push(@comments, "# Ticket $id stolen."); +# } +# } +# } +#} + +OUTPUT: +return [ $c, $o, $k, $e ]; +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/transaction/default b/rt/share/html/REST/1.0/Forms/transaction/default new file mode 100644 index 000000000..387dcef2c --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/transaction/default @@ -0,0 +1,143 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/transaction +%# +<%ARGS> +$id +$args => undef +$format => undef +$fields => undef +</%ARGS> +<%INIT> +my $trans = new RT::Transactions $session{CurrentUser}; +my ($c, $o, $k, $e) = ("", [], {} , ""); + +chomp $args; +my @arglist = split('/', $args); +my $tid = $id; + +$trans->Limit(FIELD => 'Id', OPERATOR => '=', VALUE => $tid); + +if ($tid) { + my @data; + my $t = new RT::Transaction $session{CurrentUser}; + $t->Load($tid); + if ($format eq "l") { + push @data, [ id => $t->Id ]; + push @data, [ Ticket => $t->Ticket ] + if (!%$fields || exists $fields->{lc 'Ticket'}); + push @data, [ TimeTaken => $t->TimeTaken ] + if (!%$fields || exists $fields->{lc 'TimeTaken'}); + push @data, [ Type => $t->Type ] + if (!%$fields || exists $fields->{lc 'Type'}); + push @data, [ Field => $t->Field ] + if (!%$fields || exists $fields->{lc 'Field'}); + push @data, [ OldValue => $t->OldValue ] + if (!%$fields || exists $fields->{lc 'OldValue'}); + push @data, [ NewValue => $t->NewValue ] + if (!%$fields || exists $fields->{lc 'NewValue'}); + push @data, [ Data => $t->Data ] + if (!%$fields || exists $fields->{lc 'Data'}); + push @data, [ Description => $t->Description ] + if (!%$fields || exists $fields->{lc 'Description'}); + push @data, [ Content => $t->Content ] + if (!%$fields || exists $fields->{lc 'Content'}); + + if (!%$fields || exists $fields->{lc 'Content'}) { + my $creator = new RT::User $session{CurrentUser}; + $creator->Load($t->Creator); + push @data, [ Creator => $creator->Name ]; + } + push @data, [ Created => $t->Created ] + if (!%$fields || exists $fields->{lc 'Created'}); + + if (!%$fields || exists $fields->{lc 'Attachments'}) { + my $attachlist; + my $attachments = $t->Attachments; + while (my $a = $attachments->Next) { + my $size = length($a->Content); + if ($size > 1024) { + $size = int($size/102.4)/10 . "k"; + } + else { + $size .= "b"; + } + $attachlist .= "\n" . $a->Id.": ".($a->Filename || "untitled")." (".$size.")"; + } + push @data, [Attachments => $attachlist]; + } + + } else { + push @data, [ id => $t->Id ]; + push @data, [ Description => $t->Description ]; + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; +} +#else { +# my (@data, $tids); +# $format ||= "s"; +# $format = "l" if (%$fields); +# +# while (my $t = $trans->Next) { +# my $tid = $t->Id; +# if ($format eq "l") { +# $tids .= "," if $tids; +# $tids .= $tid; +# } else { +# push @$o, $tid; +# $k->{$tid} = $t->Description; +# } +# } +#} + +return [ $c, $o, $k, $e ]; + +</%INIT> diff --git a/rt/share/html/REST/1.0/Forms/user/default b/rt/share/html/REST/1.0/Forms/user/default new file mode 100755 index 000000000..036a862bc --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/user/default @@ -0,0 +1,188 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/user/default +%# +<%ARGS> +$id +$format => 's' +$changes => {} +</%ARGS> +<%perl> +my @comments; +my ($c, $o, $k, $e) = ("", [], {}, 0); +my %data = %$changes; +my $user = new RT::User $session{CurrentUser}; +my @fields = qw(RealName NickName Gecos Organization Address1 Address2 City + State Zip Country HomePhone WorkPhone MobilePhone PagerPhone + FreeformContactInfo Comments Signature Lang EmailEncoding + WebEncoding ExternalContactInfoId ContactInfoSystem + ExternalAuthId AuthSystem Privileged Disabled); +my %fields = map { lc $_ => $_ } @fields; + +if ($id ne 'new') { + $user->Load($id); + if (!$user->Id) { + return [ "# User $id does not exist.", [], {}, 1 ]; + } +} +else { + if (keys %data == 0) { + return [ + "# Required: Name, EmailAddress", + [ qw(id Name EmailAddress Organization Password Comments) ], + { + id => "user/new", + Name => "", + EmailAddress => "", + Organization => "", + Password => "", + Comments => "" + }, + 0 + ]; + } + else { + my %v; + my %create = %fields; + $create{name} = "Name"; + $create{password} = "Password"; + $create{emailaddress} = "EmailAddress"; + $create{contactinfo} = "FreeformContactInfo"; + # Do any fields need to be excluded here? + + foreach my $k (keys %data) { + if (exists $create{lc $k}) { + $v{$create{lc $k}} = delete $data{$k}; + } + } + + $user->Create(%v); + unless ($user->Id) { + return [ "# Could not create user.", [], {}, 1 ]; + } + + $id = $user->Id; + delete $data{id}; + push(@comments, "# User $id created."); + goto DONE if keys %data == 0; + } +} + +if (keys %data == 0) { + my @data; + + push @data, [ id => "user/".$user->Id ]; + push @data, [ Name => $user->Name ]; + push @data, [ Password => '********' ]; + push @data, [ EmailAddress => $user->EmailAddress ]; + + foreach my $key (@fields) { + my $val = $user->$key; + + if ( (defined ($format) && $format eq 'l') || (defined $val && $val ne '')) { + $key = "ContactInfo" if $key eq 'FreeformContactInfo'; + push @data, [ $key => $val ]; + } + } + + my %k = map {@$_} @data; + $o = [ map {$_->[0]} @data ]; + $k = \%k; +} +else { + my ($get, $set, $key, $val, $n, $s); + + foreach $key (keys %data) { + $val = $data{$key}; + $key = lc $key; + $n = 1; + + if ($key eq 'name' || $key eq 'emailaddress' || + $key eq 'contactinfo' || exists $fields{$key}) + { + if (exists $fields{$key}) { + $key = $fields{$key}; + } + else { + $key = "FreeformContactInfo" if $key eq 'contactinfo'; + $key = "EmailAddress" if $key eq 'emailaddress'; + $key = "Name" if $key eq 'name'; + } + $set = "Set$key"; + + next if $val eq $user->$key; + ($n, $s) = $user->$set($val); + } + elsif ($key eq 'password') { + ($n, $s) = $user->SetPassword($val) unless $val =~ /^\**$/; + } + elsif ($key ne 'id') { + $n = 0; + $s = "Unknown field."; + } + + SET: + if ($n == 0) { + $e = 1; + push @comments, "# $key: $s"; + unless (@$o) { + my %o = keys %$changes; + delete @o{"id", @fields}; + @$o = ("id", @fields, keys %o); + $k = $changes; + } + } + } + + push(@comments, "# User $id updated.") unless $n == 0; +} + +DONE: +$c ||= join("\n", @comments) if @comments; +return [ $c, $o, $k, $e ]; +</%perl> diff --git a/rt/share/html/REST/1.0/Forms/user/ns b/rt/share/html/REST/1.0/Forms/user/ns new file mode 100755 index 000000000..8f4678d0e --- /dev/null +++ b/rt/share/html/REST/1.0/Forms/user/ns @@ -0,0 +1,65 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/Forms/user/ns +%# +<%ARGS> +$id +</%ARGS> +<%perl> +use RT::Users; + +my $field = "Name"; +$field = "EmailAddress" if $id =~ /\@/; + +my $users = new RT::Users $session{CurrentUser}; +$users->Limit(FIELD => $field, OPERATOR => '=', VALUE => $id); +if ($users->Count == 0) { + return (0, "No user named $id exists."); +} +return $users->Next->Id; +</%perl> diff --git a/rt/share/html/REST/1.0/NoAuth/mail-gateway b/rt/share/html/REST/1.0/NoAuth/mail-gateway new file mode 100755 index 000000000..20d28ec84 --- /dev/null +++ b/rt/share/html/REST/1.0/NoAuth/mail-gateway @@ -0,0 +1,84 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +<%flags> +inherit => undef # inhibit UTF8 conversion done in /autohandler +</%flags> +<%ARGS> +$queue => 1 +$action => "correspond" +$ticket => undef +</%ARGS> +<%init> +$m->callback( %ARGS, CallbackName => 'Pre' ); +use RT::Interface::Email (); # It's an exporter, but we don't care +$r->content_type('text/plain; charset=utf-8'); +$m->error_format('text'); +my ( $status, $error, $Ticket ) = RT::Interface::Email::Gateway( \%ARGS ); +if ( $status == 1 ) { + $m->out('ok'); + if ( $Ticket && $Ticket->Id ) { + $m->out( 'Ticket: ' . ($Ticket->Id || '') ); + $m->out( 'Queue: ' . ($Ticket->QueueObj->Name || '') ); + $m->out( 'Owner: ' . ($Ticket->OwnerObj->Name || '') ); + $m->out( 'Status: ' . ($Ticket->Status || '') ); + $m->out( 'Subject: ' . ($Ticket->Subject || '') ); + $m->out( + 'Requestor: ' . ($Ticket->Requestors->MemberEmailAddressesAsString || '') ); + } +} +else { + $RT::Logger->error( "Could not record email: " . $error ); + if ( $status == -75 ) { + $m->out( "temporary failure - " . $error ); + } + else { + $m->out( 'not ok - ' . $error ); + } +} +$m->abort(); +</%init> diff --git a/rt/share/html/REST/1.0/autohandler b/rt/share/html/REST/1.0/autohandler new file mode 100755 index 000000000..8354e56ca --- /dev/null +++ b/rt/share/html/REST/1.0/autohandler @@ -0,0 +1,56 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/autohandler +%# +<%INIT> +use RT::Interface::REST; +$r->content_type('text/plain; charset=utf-8'); +$m->error_format('text'); +$m->call_next(); +$m->abort(); +</%INIT> diff --git a/rt/share/html/REST/1.0/dhandler b/rt/share/html/REST/1.0/dhandler new file mode 100755 index 000000000..085bbb304 --- /dev/null +++ b/rt/share/html/REST/1.0/dhandler @@ -0,0 +1,326 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/dhandler +%# +<%ARGS> +@id => () +$fields => undef +$format => undef +$content => undef +</%ARGS> +<%INIT> +use RT::Interface::REST; + +my $output = ""; +my $status = "200 Ok"; +my $object = $m->dhandler_arg; + +my $name = qr{[\w.-]+}; +my $list = '(?:(?:\d+-)?\d+,)*(?:\d+-)?\d+'; +my $label = '[a-zA-Z0-9@_.+-]+'; +my $field = RT::Interface::REST->field_spec; +my $labels = "(?:$label,)*$label"; + +# We must handle requests such as the following: +# +# 1. http://.../REST/1.0/show (with a list of object specifications). +# 2. http://.../REST/1.0/edit (with a self-contained list of forms). +# 3. http://.../REST/1.0/ticket/show (implicit type specification). +# http://.../REST/1.0/ticket/edit +# 4. http://.../REST/1.0/ticket/nn (all possibly with a single form). +# http://.../REST/1.0/ticket/nn/history +# http://.../REST/1.0/ticket/nn/comment +# http://.../REST/1.0/ticket/nn/attachment/1 +# +# Objects are specified by their type, and either a unique numeric ID, +# or a unique name (e.g. ticket/1, queue/foo). Multiple objects of the +# same type may be specified by a comma-separated list of identifiers +# (e.g., user/ams,rai or ticket/1-3,5-7). +# +# Ultimately, we want a list of object specifications to operate upon. +# The URLs in (4) provide enough information to identify an object. We +# will assemble submitted information into that format in other cases. +# +my (@objects, $forms); +my $utype; + +if ($object eq 'show' || # $REST/show + (($utype) = ($object =~ m{^($name)/show$}))) # $REST/ticket/show +{ + # We'll convert type/range specifications ("ticket/1-3,7-9/history") + # into a list of singular object specifications ("ticket/1/history"). + # If the URL specifies a type, we'll accept only that one. + foreach my $id (@id) { + $id =~ s|^(?:$utype/)?|$utype/| if $utype; + if (my ($type, $oids, $extra) = + ($id =~ m#^($name)/($list|$labels)(?:(/.*))?$#o)) + { + $extra ||= ''; + my ($attr, $args) = $extra =~ m{^(?:/($name)(?:/(.*))?)?$}o; + my $tids; + if ($attr and $attr eq 'history' and $args) { + ($tids) = $args =~ m#id/(\d.*)#o; + } + # expand transaction and attachment range specifications + # (if applicable) + foreach my $oid (expand_list($oids)) { + if ($tids) { + push(@objects, "$type/$oid/$attr/id/$_") for expand_list($tids); + } else { + push(@objects, "$type/$oid$extra"); + } + } + } + else { + $status = "400 Bad Request"; + $output = "Invalid object ID specified: '$id'"; + goto OUTPUT; + } + } +} +elsif ($object eq 'edit' || # $REST/edit + (($utype) = ($object =~ m{^($name)/edit$}))) # $REST/ticket/edit +{ + # We'll make sure each of the submitted forms is syntactically valid + # and sufficiently identifies an object to operate upon, then add to + # the object list as above. + my @output; + + $forms = form_parse($content); + foreach my $form (@$forms) { + my ($c, $o, $k, $e) = @$form; + + if ($e) { + push @output, [ "# Syntax error.", $o, $k, $e ]; + } + else { + my ($type, $id); + + # Look for matching types in the ID, form, and URL. + $type = $utype || $k->{id}; + $type =~ s|^([^/]+)/\d+$|$1| if !$utype; + $type =~ s|^(?:$utype)?|$utype/| if $utype; + $type =~ s|/$|| if $type; + + if (exists $k->{id}) { + $id = $k->{id}; + $id =~ s|^(?:$type/)?|$type/| if $type; + + if ($id =~ m#^$name/(?:$label|\d+)(?:/.*)?#o) { + push @objects, $id; + } + else { + push @output, [ "# Invalid object ID: '$id'", $o, $k, $e ]; + } + } + else { + push @output, [ "# No object ID specified.", $o, $k, $e ]; + } + } + } + # If we saw any errors at this stage, we won't process any part of + # the submitted data. + if (@output) { + unshift @output, [ "# Please resubmit with errors corrected." ]; + $status = "409 Syntax Error"; + $output = form_compose(\@output); + goto OUTPUT; + } +} +else { + # We'll assume that this is in the correct format already. Otherwise + # it will be caught by the loop below. + push @objects, $object; + + if ($content) { + $forms = form_parse($content); + + if (@$forms > 1) { + $status = "400 Bad Request"; + $output = "You may submit only one form to this object."; + goto OUTPUT; + } + + my ($c, $o, $k, $e) = @{ $forms->[0] }; + if ($e) { + $status = "409 Syntax Error"; + $output = form_compose([ ["# Syntax error.", $o, $k, $e] ]); + goto OUTPUT; + } + } +} + +# Make sure we have something to do. +unless (@objects) { + $status = "400 Bad Request"; + $output = "No objects specified."; + goto OUTPUT; +} + +# Parse and validate any field specifications. +my (%fields, @fields); +if ($fields) { + unless ($fields =~ /^(?:$field,)*$field$/) { + $status = "400 Bad Request"; + $output = "Invalid field specification: $fields"; + goto OUTPUT; + } + @fields = map lc, split /,/, $fields; + @fields{@fields} = (); + unless (exists $fields{id}) { + unshift @fields, "id"; + $fields{id} = (); + } + + # canonicalize cf-foo to cf.{foo} + for my $field (@fields) { + if ($field =~ /^(c(?:ustom)?f(?:ield)?)-(.+)/) { + $fields{"cf.{$2}"} = delete $fields{"$1-$2"}; + + # overwrite the element in @fields + $field = "cf.{$2}"; + } + } +} + +my (@comments, @output); + +foreach $object (@objects) { + my ($handler, $type, $id, $attr, $args); + my ($c, $o, $k, $e) = ("", ["id"], {id => $object}, 0); + + my $i = 0; + if ($object =~ m{^($name)/(\d+|$label)(?:/($name)(?:/(.*))?)?$}o || + $object =~ m{^($name)/(new)$}o) + { + ($type, $id, $attr, $args) = ($1, $2, ($3 || 'default'), $4); + $handler = "Forms/$type/$attr"; + + unless ($m->comp_exists($handler)) { + $args = "$attr/$args"; + $handler = "Forms/$type/default"; + + unless ($m->comp_exists($handler)) { + $i = 2; + $c = "# Unknown object type: $type"; + } + } + elsif ($id ne 'new' && $id !~ /^\d+$/) { + my $ns = "Forms/$type/ns"; + + # Can we resolve named objects? + unless ($m->comp_exists($ns)) { + $i = 3; + $c = "# Objects of type $type must be specified by numeric id."; + } + else { + my ($n, $s) = $m->comp("Forms/$type/ns", id => $id); + if ($n <= 0) { $i = 4; $c = "# $s"; } + else { $i = 0; $id = $n; } + } + } + else { + $i = 0; + } + } + else { + $i = 1; + $c = "# Invalid object specification: '$object'"; + } + + if ($i != 0) { + if ($content) { + (undef, $o, $k, $e) = @{ shift @$forms }; + } + push @output, [ $c, $o, $k ]; + next; + } + + unless ($content) { + my $d = $m->comp($handler, id => $id, args => $args, format => $format, fields => \%fields); + my ($c, $o, $k, $e) = @$d; + + if (!$e && @$o && keys %fields) { + my %lk = map { lc $_ => $_ } keys %$k; + @$o = map { $lk{$_} } @fields; + foreach my $key (keys %$k) { + delete $k->{$key} unless exists $fields{lc $key}; + } + } + push(@output, [ $c, $o, $k ]) if ($c || @$o || keys %$k); + } + else { + my ($c, $o, $k, $e) = @{ shift @$forms }; + my $d = $m->comp($handler, id => $id, args => $args, format => $format, + changes => $k); + ($c, $o, $k, $e) = @$d; + + # We won't pass $e through to compose, trusting instead that the + # handler added suitable comments for the user. + if ($e) { + if (@$o) { + $status = "409 Syntax Error"; + } + else { + $status = "400 Bad Request"; + } + push @output, [ $c, $o, $k ]; + } + else { + push @comments, $c; + } + } +} + +unshift(@output, [ join "\n", @comments ]) if @comments; +$output = form_compose(\@output); + +OUTPUT: +$m->out("RT/".$RT::VERSION ." ".$status ."\n\n$output\n") if ($output || $status !~ /^200/); +return; +</%INIT> diff --git a/rt/share/html/REST/1.0/logout b/rt/share/html/REST/1.0/logout new file mode 100755 index 000000000..f800ce362 --- /dev/null +++ b/rt/share/html/REST/1.0/logout @@ -0,0 +1,51 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +<%PERL> +tied(%session)->delete if (defined %session); +</%PERL> +RT/<% $RT::VERSION %> 200 Ok diff --git a/rt/share/html/REST/1.0/search/dhandler b/rt/share/html/REST/1.0/search/dhandler new file mode 100755 index 000000000..86d33b37f --- /dev/null +++ b/rt/share/html/REST/1.0/search/dhandler @@ -0,0 +1,56 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/search/dhandler +%# +<%INIT> +my $status = "500 Server Error"; +my $output = "Unsupported object type."; +</%INIT> +RT/<% $RT::VERSION %> <% $status %> + +<% $output |n %> diff --git a/rt/share/html/REST/1.0/search/ticket b/rt/share/html/REST/1.0/search/ticket new file mode 100755 index 000000000..46eb5ffcf --- /dev/null +++ b/rt/share/html/REST/1.0/search/ticket @@ -0,0 +1,159 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/search/ticket +%# +<%ARGS> +$query +$format => undef +$orderby => undef +$fields => undef +</%ARGS> +<%INIT> +use RT::Interface::REST; +my $output = ""; +my $status = "200 Ok"; +my $tickets = new RT::Tickets $session{CurrentUser}; + +# Parse and validate any field specifications. +my $field = RT::Interface::REST->field_spec; +my (%fields, @fields); +if ($fields) { + $format ||= "l"; + unless ($fields =~ /^(?:$field,)*$field$/) { + $status = "400 Bad Request"; + $output = "Invalid field specification: $fields"; + goto OUTPUT; + } + @fields = map lc, split /,/, $fields; + @fields{@fields} = (); + unless (exists $fields{id}) { + unshift @fields, "id"; + $fields{id} = (); + } +} + +$format ||= "s"; +if ($format !~ /^[isl]$/) { + $status = "400 Bad request"; + $output = "Unknown listing format: $format. (Use i, s, or l.)\n"; + goto OUTPUT; +} + +my ($n, $s); +eval { + ($n, $s) = $tickets->FromSQL($query); +}; +my $sortstring = ""; +if ($orderby) { + $sortstring = 'FIELD => '; + my $order = substr($orderby, 0, 1); + if ($order eq '+' || $order eq '-') { + $sortstring .= 'substr($orderby, 1)'; + if ($order eq '+') { + $sortstring .= ", ORDER => 'ASC'"; + } elsif ($order eq '-') { + $sortstring .= ", ORDER => 'DESC'"; + } + } else { + $sortstring .= '$orderby'; + } + my $foo = 'FIELD => '; + $foo .= '$orderby'; + $tickets->OrderBy(eval $sortstring); +} +if ($@ || $n == 0) { + $s ||= $@; + $status = "400 Bad request"; + $output = "Invalid query: '$s'.\n"; + goto OUTPUT; +} + +$n = 0; +my @output; +while (my $ticket = $tickets->Next) { + $n++; + + my $id = $ticket->Id; + if ($format eq "i") { + $output .= "ticket/" . $id . "\n"; + } + elsif ($format eq "s") { + if ($fields) { + my $result = $m->comp("/REST/1.0/Forms/ticket/default", id => $id, format => $format, fields => \%fields); + my ($notes, $order, $key_values, $errors) = @$result; + # If it's the first time through, add our header + if ($n == 1) { + $output .= join("\t",@$order)."\n"; + } + # Cut off the annoying ticket/ before the id; + $key_values->{'id'} = $id; + $output .= join("\t", map {$key_values->{$_}} @$order)."\n"; + + + } else { + $output .= $ticket->Id . ": ". $ticket->Subject . "\n"; + } + } + else { + my $d = $m->comp("/REST/1.0/Forms/ticket/default", id => $id, format => $format, fields => \%fields); + my ($c, $o, $k, $e) = @$d; + push @output, [ $c, $o, $k ]; + } +} +if ($n == 0 && $format ne "i") { + $output = "No matching results.\n"; +} + +$output = form_compose(\@output) if @output; + +OUTPUT: +$m->out("RT/". $RT::VERSION . " " . $status ."\n\n"); + +$m->out($output ); +return(); +</%INIT> diff --git a/rt/share/html/REST/1.0/ticket/comment b/rt/share/html/REST/1.0/ticket/comment new file mode 100755 index 000000000..000f35288 --- /dev/null +++ b/rt/share/html/REST/1.0/ticket/comment @@ -0,0 +1,177 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/ticket/comment +%# +<%ARGS> +$content +</%ARGS> +<%INIT> +use MIME::Entity; +use LWP::MediaTypes; +use RT::Interface::REST; +use File::Temp qw(tempfile); + +my $ticket = new RT::Ticket $session{CurrentUser}; +my $object = $r->path_info; +my $status = "200 Ok"; +my $output; +my $action; + +# http://.../REST/1.0/ticket/1/comment +my ($c, $o, $k, $e) = @{ form_parse($content)->[0] }; +if ($e || !$o) { + if (!$o) { + $output = "Empty form submitted.\n"; + } + else { + $c = "# Syntax error."; + $output = form_compose([[$c, $o, $k, $e]]); + } + $status = "400 Bad Request"; + goto OUTPUT; +} + +$object =~ s#^/##; +$object ||= $k->{Ticket}; +unless ($object =~ /^\d+/) { + $output = "Invalid ticket id: `$object'.\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} +if ($k->{Ticket} && $object ne $k->{Ticket}) { + $output = "The submitted form and URL specify different tickets.\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} + +($action = $k->{Action}) =~ s/^(.)(.*)$/\U$1\L$2\E/; +unless ($action =~ /^(?:Comment|Correspond)$/) { + $output = "Invalid action: `$action'.\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} + +my $text = $k->{Text}; +my @atts = @{ vsplit($k->{Attachment}) }; + +if (!$k->{Text} && @atts == 0) { + $status = "400 Bad Request"; + $output = "Empty comment with no attachments submitted.\n"; + goto OUTPUT; +} + +my $cgi = $m->cgi_object; +my $ent = MIME::Entity->build(Type => "multipart/mixed"); +$ent->attach(Data => $k->{Text}) if $k->{Text}; + +my $i = 1; +foreach my $att (@atts) { + local $/=undef; + my $file = $att; + $file =~ s#^.*[\\/]##; + + my $fh = $cgi->upload("attachment_$i"); + if ($fh) { + my $buf; + my ($w, $tmp) = tempfile(); + my $info = $cgi->uploadInfo(); + + while (sysread($fh, $buf, 8192)) { + syswrite($w, $buf); + } + + $ent->attach( + Path => $tmp, + Type => $info->{'Content-Type'} || guess_media_type($tmp), + Filename => $file, + Disposition => "attachment" + ); + } + else { + $status = "400 Bad Request"; + $output = "No attachment for $att.\n"; + goto OUTPUT; + } + + $i++; +} + +$ticket->Load($object); +unless ($ticket->Id) { + $output = "Couldn't load ticket id: `$object'.\n"; + $status = "404 Ticket not found"; + goto OUTPUT; +} +unless ($ticket->CurrentUserHasRight('ModifyTicket') || + ($action eq "Comment" && + $ticket->CurrentUserHasRight("CommentOnTicket")) || + ($action eq "Correspond" && + $ticket->CurrentUserHasRight("ReplyToTicket"))) +{ + $output = "You are not allowed to $action on ticket $object.\n"; + $status = "403 Permission denied"; + goto OUTPUT; +} + +my $cc = join ", ", @{ vsplit($k->{Cc}) }; +my $bcc = join ", ", @{ vsplit($k->{Bcc}) }; +my ($n, $s) = $ticket->$action(MIMEObj => $ent, + CcMessageTo => $cc, + BccMessageTo => $bcc, + TimeTaken => $k->{TimeWorked} || 0); +$output = $s; +if ($k->{Status}) { + my ($status_n, $status_s) = $ticket->SetStatus($k->{'Status'} ); + $output .= "\n".$status_s; +} + +OUTPUT: +</%INIT> +RT/<% $RT::VERSION %> <% $status %> + +<% $output |n %> diff --git a/rt/share/html/REST/1.0/ticket/link b/rt/share/html/REST/1.0/ticket/link new file mode 100755 index 000000000..a5e8ae201 --- /dev/null +++ b/rt/share/html/REST/1.0/ticket/link @@ -0,0 +1,123 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/ticket/link +%# +<%ARGS> +$id => undef +$del => 0 +$rel +$to +</%ARGS> +<%INIT> +use RT::Interface::REST; + +my $output; +my $status = "200 Ok"; +my $ticket = new RT::Ticket $session{CurrentUser}; +my $object = $r->path_info; + +my @fields = qw(DependsOn DependedOnBy RefersTo ReferredToBy HasMember MemberOf); +my %fields = map { lc $_ => $_ } @fields; +my %lfields = ( + HasMember => { Type => 'MemberOf', Mode => 'Base' }, + ReferredToBy => { Type => 'RefersTo', Mode => 'Base' }, + DependedOnBy => { Type => 'DependsOn', Mode => 'Base' }, + MemberOf => { Type => 'MemberOf', Mode => 'Target' }, + RefersTo => { Type => 'RefersTo', Mode => 'Target' }, + DependsOn => { Type => 'DependsOn', Mode => 'Target' }, +); + +# http://.../REST/1.0/ticket/link/1 + +$object =~ s#^/REST/1.0/ticket/link##; +if ($id && $object && $id != $object) { + $output = "Different ids in URL (`$object') and submitted form (`$id').\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} +$id ||= $object; +unless ($id =~ /^\d+$/ && $to =~ /^\d+$/) { + my $bad = ($id !~ /^\d+$/) ? $id : $to; + $output = $r->path_info. "\n"; + $output .= "Invalid ticket id: '$bad'.\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} +unless (exists $fields{lc $rel}) { + $output = "Invalid link: '$rel'.\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} +$rel = $fields{lc $rel}; + +$ticket->Load($id); +unless ($ticket->Id) { + $output = "Couldn't load ticket id: '$id'.\n"; + $status = "404 Ticket not found"; + goto OUTPUT; +} + +my $type = $lfields{$rel}->{Type}; +my $mode = $lfields{$rel}->{Mode}; + +my $n = 1; +my $op = $del ? "DeleteLink" : "AddLink"; + +($n, $output) = $ticket->$op(Type => $type, $mode => $to); +if ($n == 0) { + $status = "500 Error"; +} else { + my $action = $del ? "Deleted" : "Created"; + $output .= " $action link " . $ticket->Id . " $rel $to"; +} + +OUTPUT: +</%INIT> +RT/<% $RT::VERSION %> <% $status %> + +<% $output |n %> diff --git a/rt/share/html/REST/1.0/ticket/merge b/rt/share/html/REST/1.0/ticket/merge new file mode 100755 index 000000000..24c9829e9 --- /dev/null +++ b/rt/share/html/REST/1.0/ticket/merge @@ -0,0 +1,102 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2009 Best Practical Solutions, LLC +%# <jesse@bestpractical.com> +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} +%# REST/1.0/ticket/merge +%# +<%ARGS> +$id => undef +$into +</%ARGS> +<%INIT> +use RT::Interface::REST; + +my $output; +my $status = "200 Ok"; +my $ticket = new RT::Ticket $session{CurrentUser}; +my $object = $r->path_info; + +# http://.../REST/1.0/ticket/merge/1 + +$object =~ s#^/##; +if ($id && $object && $id != $object) { + $output = "Different ids in URL (`$object') and submitted form (`$id').\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} +$id ||= $object; +unless ($id =~ /^\d+$/ && $into =~ /^\d+$/) { + my $bad = ($id !~ /^\d+$/) ? $id : $into; + $output = $r->path_info. "\n"; + $output .= "Invalid ticket id: `$bad'.\n"; + $status = "400 Bad Request"; + goto OUTPUT; +} + +$ticket->Load($id); +unless ($ticket->Id) { + $output = "Couldn't load ticket id: `$id'.\n"; + $status = "404 Ticket not found"; + goto OUTPUT; +} +unless ($ticket->CurrentUserHasRight('ModifyTicket')) { + $output = "You are not allowed to modify ticket $id.\n"; + $status = "403 Permission denied"; + goto OUTPUT; +} + +my ($n, $s) = $ticket->MergeInto($into); + +if ($n == 0) { + $status = "500 Error"; +} +$output = $s; + +OUTPUT: +</%INIT> +RT/<% $RT::VERSION %> <% $status %> + +<% $output |n %> |