Skip to content

Commit

Permalink
Add new Description core ticket field
Browse files Browse the repository at this point in the history
  • Loading branch information
cbrandtbuffalo authored and sunnavy committed Nov 22, 2024
1 parent 72c7e2c commit 66d9892
Show file tree
Hide file tree
Showing 33 changed files with 686 additions and 13 deletions.
6 changes: 6 additions & 0 deletions docs/ticket_metadata.pod
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ have or don't have that word or phrase. Try using 'the' in both cases; there
are surely a lot of tickets that both do and do not have 'the' in the subject
of the ticket!

=head2 Description

This optional ticket field is helpful for recording the main purpose of the
ticket. This is especially helpful if you are managing a project and using
tickets for tasks.

=head2 Queue

Queue specification is a great way to narrow your search. If you are a
Expand Down
11 changes: 10 additions & 1 deletion etc/RT_Config.pm.in
Original file line number Diff line number Diff line change
Expand Up @@ -2035,7 +2035,7 @@ ordering of these standard groupings cannot be modified. You may also
only append Custom Fields to the list in these boxes, not reorder or
remove core fields.

For C<RT::Ticket>, these groupings are: C<Basics>, C<Dates>, C<Links>, C<People>, C<QuickCreate>
For C<RT::Ticket>, these groupings are: C<Basics>, C<Dates>, C<Links>, C<People>, C<Description>, C<QuickCreate>

For C<RT::User>: C<Identity>, C<Access control>, C<Location>, C<Phones>

Expand Down Expand Up @@ -3475,6 +3475,15 @@ Set this option to C<0> to disable this feature.

Set($QuoteSelectedText, 1);

=item C<$TicketDescriptionRows>

Set the height of the edit box for the optional Description field
on tickets. One row translates roughly to one line of text.

=cut

Set($TicketDescriptionRows, 20);

=back

=head2 Group Summary Configuration
Expand Down
2 changes: 2 additions & 0 deletions etc/schema.Oracle
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ CREATE TABLE Tickets (
Type VARCHAR2(16),
Owner NUMBER(11,0) DEFAULT 0 NOT NULL,
Subject VARCHAR2(200) DEFAULT '[no subject]',
Description CLOB,
InitialPriority NUMBER(11,0) DEFAULT 0 NOT NULL,
FinalPriority NUMBER(11,0) DEFAULT 0 NOT NULL,
Priority NUMBER(11,0) DEFAULT 0 NOT NULL,
Expand All @@ -278,6 +279,7 @@ CREATE TABLE Tickets (
CREATE INDEX Tickets1 ON Tickets (Queue, Status);
CREATE INDEX Tickets2 ON Tickets (Owner);
CREATE INDEX Tickets6 ON Tickets (EffectiveId, Type);
CREATE INDEX Tickets7 ON Tickets (Description) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('SYNC (ON COMMIT)');


CREATE SEQUENCE SCRIPACTIONS_seq;
Expand Down
2 changes: 2 additions & 0 deletions etc/schema.Pg
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ CREATE TABLE Tickets (
Type varchar(16) NULL ,
Owner integer NOT NULL DEFAULT 0 ,
Subject varchar(200) NULL DEFAULT '[no subject]' ,
Description text NULL ,
InitialPriority integer NOT NULL DEFAULT 0 ,
FinalPriority integer NOT NULL DEFAULT 0 ,
Priority integer NOT NULL DEFAULT 0 ,
Expand All @@ -433,6 +434,7 @@ CREATE TABLE Tickets (
CREATE INDEX Tickets1 ON Tickets (Queue, Status) ;
CREATE INDEX Tickets2 ON Tickets (Owner) ;
CREATE INDEX Tickets3 ON Tickets (EffectiveId) ;
CREATE INDEX Tickets7 ON Tickets USING GIN(to_tsvector('simple', Description));


--
Expand Down
1 change: 1 addition & 0 deletions etc/schema.SQLite
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ CREATE TABLE Tickets (
Type varchar(16) collate NOCASE NULL ,
Owner integer NULL DEFAULT 0 ,
Subject varchar(200) collate NOCASE NULL DEFAULT '[no subject]' ,
Description text collate NOCASE NULL ,
InitialPriority integer NULL DEFAULT 0 ,
FinalPriority integer NULL DEFAULt 0 ,
Priority integer NULL DEFAULT 0 ,
Expand Down
2 changes: 2 additions & 0 deletions etc/schema.mysql
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ CREATE TABLE Tickets (
Type varchar(16) CHARACTER SET ascii NULL ,
Owner integer NOT NULL DEFAULT 0 ,
Subject varchar(200) NULL DEFAULT '[no subject]' ,
Description TEXT NULL ,
InitialPriority integer NOT NULL DEFAULT 0 ,
FinalPriority integer NOT NULL DEFAULT 0 ,
Priority integer NOT NULL DEFAULT 0 ,
Expand All @@ -292,6 +293,7 @@ CREATE TABLE Tickets (
CREATE INDEX Tickets1 ON Tickets (Queue, Status) ;
CREATE INDEX Tickets2 ON Tickets (Owner) ;
CREATE INDEX Tickets6 ON Tickets (EffectiveId, Type) ;
CREATE FULLTEXT INDEX Tickets7 ON Tickets (Description) ;



Expand Down
2 changes: 2 additions & 0 deletions etc/upgrade/5.9.5/schema.Oracle
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE Tickets ADD Description CLOB;
CREATE INDEX Tickets7 ON Tickets (Description) INDEXTYPE IS CTXSYS.CONTEXT PARAMETERS ('SYNC (ON COMMIT)');
2 changes: 2 additions & 0 deletions etc/upgrade/5.9.5/schema.Pg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE Tickets ADD COLUMN Description Text NULL;
CREATE INDEX Tickets7 ON Tickets USING GIN(to_tsvector('simple', Description));
2 changes: 2 additions & 0 deletions etc/upgrade/5.9.5/schema.mysql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE Tickets ADD COLUMN Description TEXT NULL;
CREATE FULLTEXT INDEX Tickets7 ON Tickets (Description);
10 changes: 10 additions & 0 deletions lib/RT/Config.pm
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,16 @@ our %META;
Description => 'Quote selected text on ticket update', # loc
}
},
TicketDescriptionRows => {
Section => 'Ticket display',
Overridable => 1,
SortOrder => 15,
Widget => '/Widgets/Form/Integer',
WidgetArguments => {
Description => 'Ticket Description Rows', # loc
Hints => 'Rows for the Description edit box on tickets', # loc
}
},

# User overridable locale options
DateTimeFormat => {
Expand Down
5 changes: 5 additions & 0 deletions lib/RT/Handle.pm
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ sub Connect {
# statement_timeout is defined in milliseconds
$self->dbh->do( "SET statement_timeout = " . int( $timeout * 1000 ) )
if defined $timeout && length $timeout;

my $text_search_config = $self->dbh->selectrow_hashref('show default_text_search_config');
# Looks like "pg_catalog.english", we just want the "english" part
my ($pg_prefix, $search_language) = split /\./, $text_search_config->{'default_text_search_config'};
RT->Config->Set('DefaultTextSearchConfig', $search_language);
}
elsif ( $db_type eq 'SQLite' ) {
$self->dbh->{sqlite_see_if_its_a_number} = 1;
Expand Down
30 changes: 30 additions & 0 deletions lib/RT/Interface/Web.pm
Original file line number Diff line number Diff line change
Expand Up @@ -2736,6 +2736,7 @@ sub CreateTicket {
TimeEstimated => $ARGS{'TimeEstimated'},
TimeWorked => $ARGS{'TimeWorked'},
Subject => $ARGS{'Subject'},
Description => $ARGS{'Description'},
Status => $ARGS{'Status'},
Due => $due ? $due->ISO : undef,
Starts => $starts ? $starts->ISO : undef,
Expand Down Expand Up @@ -3622,6 +3623,35 @@ sub ProcessTicketBasics {
return (@results);
}

=head2 ProcessTicketDescription ( TicketObj => $Ticket, ARGSRef => \%ARGS );
Returns an array of results messages.
=cut

sub ProcessTicketDescription {

my %args = (
TicketObj => undef,
ARGSRef => undef,
@_
);

my $TicketObj = $args{'TicketObj'};
my $ARGSRef = $args{'ARGSRef'};

# Set basic fields
my @attribs = qw( Description );

my @results = UpdateRecordObject(
AttributesRef => \@attribs,
Object => $TicketObj,
ARGSRef => $ARGSRef,
);

return (@results);
}

sub ProcessTicketReminders {
my %args = (
TicketObj => undef,
Expand Down
14 changes: 11 additions & 3 deletions lib/RT/Record/Role/ObjectContent.pm
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ Returns corresponding L<RT::ObjectContent> object's content, undef if it doesn't

sub Content {
my $self = shift;
if ( my $object_content = $self->ContentObj ) {
# Call ContentObj($self) in case ContentObj is used for other purposes in target modules like RT::Transaction
if ( my $object_content = ContentObj($self) ) {
return $object_content->DecodedContent;
}
return undef;
Expand All @@ -99,11 +100,18 @@ sub SetContent {
my $content = shift;
my %args = ( RecordTransaction => 1, @_ );

return ( 0, $self->loc('Permission Denied') ) unless $self->CurrentUserCanModify;
my $object_content = ContentObj($self);

if ( $self->isa('RT::Transaction') ) {
# Not allow to update Content
return ( 0, $self->loc('Permission Denied') ) if $object_content;
}
else {
return ( 0, $self->loc('Permission Denied') ) unless $self->CurrentUserCanModify;
}

( my $encoding, $content ) = RT::ObjectContent->_EncodeContent($content);

my $object_content = $self->ContentObj;
my $old_content_id;

if ($object_content) {
Expand Down
5 changes: 5 additions & 0 deletions lib/RT/Ticket.pm
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ Arguments: ARGS is a hash of named parameters. Valid parameters are:
Type -- The ticket's type. ignore this for now
Owner -- This ticket's owner. either an RT::User object or this user's id
Subject -- A string describing the subject of the ticket
Description -- More detailed information about the purpose of this ticket
Priority -- an integer from 0 to 99
InitialPriority -- an integer from 0 to 99
FinalPriority -- an integer from 0 to 99
Expand Down Expand Up @@ -274,6 +275,7 @@ sub Create {
Type => 'ticket',
Owner => undef,
Subject => '',
Description => undef,
InitialPriority => undef,
FinalPriority => undef,
Priority => undef,
Expand Down Expand Up @@ -434,6 +436,7 @@ sub Create {
my %params = (
Queue => $QueueObj->Id,
Subject => $args{'Subject'},
Description => $args{'Description'},
InitialPriority => $args{'InitialPriority'},
FinalPriority => $args{'FinalPriority'},
Priority => $args{'Priority'},
Expand Down Expand Up @@ -3725,6 +3728,8 @@ sub _CoreAccessible {
{read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
Subject =>
{read => 1, write => 1, sql_type => 12, length => 200, is_blob => 0, is_numeric => 0, type => 'varchar(200)', default => '[no subject]'},
Description =>
{read => 1, write => 1, sql_type => -4, length => 0, is_blob => 1, is_numeric => 0, type => 'text', default => ''},
InitialPriority =>
{read => 1, write => 1, sql_type => 4, length => 11, is_blob => 0, is_numeric => 1, type => 'int(11)', default => '0'},
FinalPriority =>
Expand Down
91 changes: 91 additions & 0 deletions lib/RT/Tickets.pm
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ our %FIELD_METADATA = (
LastUpdated => [ 'DATE' => 'LastUpdated', ], #loc_left_pair
Created => [ 'DATE' => 'Created', ], #loc_left_pair
Subject => [ 'STRING', ], #loc_left_pair
Description => [ 'FULLTEXTSTRING', ], #loc_left_pair
Content => [ 'TRANSCONTENT', ], #loc_left_pair
ContentType => [ 'TRANSFIELD', ], #loc_left_pair
Filename => [ 'TRANSFIELD', ], #loc_left_pair
Expand Down Expand Up @@ -189,6 +190,7 @@ our %dispatch = (
LINK => \&_LinkLimit,
DATE => \&_DateLimit,
STRING => \&_StringLimit,
FULLTEXTSTRING => \&_FullTextStringLimit,
QUEUE => \&_QueueLimit,
TRANSFIELD => \&_TransLimit,
TRANSCONTENT => \&_TransContentLimit,
Expand Down Expand Up @@ -746,6 +748,95 @@ sub _StringLimit {
);
}

=head2 _FullTextStringLimit
Handle strings with a full text index like Description
Meta Data:
None
=cut

sub _FullTextStringLimit {
my ( $self, $field, $op, $value, %rest ) = @_;

my $db_type = RT->Config->Get('DatabaseType');

if ( $db_type eq 'Oracle'
&& (!defined $value || !length $value)
&& lc($op) ne 'is' && lc($op) ne 'is not'
) {
if ($op eq '!=' || $op =~ /^NOT\s/i) {
$op = 'IS NOT';
} else {
$op = 'IS';
}
$value = 'NULL';
}

if ( $db_type eq 'Oracle' ) {
my $dbh = $RT::Handle->dbh;
$self->Limit(
%rest,
FUNCTION => "CONTAINS( main.$field, ".$dbh->quote('%'.$value.'%') .")",
OPERATOR => '>',
VALUE => 0,
QUOTEVALUE => 0,
CASESENSITIVE => 1,
);
# this is required to trick DBIx::SB's LEFT JOINS optimizer
# into deciding that join is redundant as it is
$self->Limit(
ENTRYAGGREGATOR => 'AND',
FIELD => 'Description',
OPERATOR => 'IS NOT',
VALUE => 'NULL',
);
}
elsif ( $db_type eq 'Pg' ) {
my $dbh = $RT::Handle->dbh;

$self->Limit(
%rest,
FIELD => $field,
OPERATOR => '@@',
VALUE => 'plainto_tsquery(\'' . RT->Config->Get('DefaultTextSearchConfig') . '\', '. $dbh->quote($value) .')',
QUOTEVALUE => 0,
);
}
elsif ( $db_type eq 'mysql' ) {
my $dbh = $RT::Handle->dbh;
$self->Limit(
%rest,
FUNCTION => "MATCH(Description)",
OPERATOR => 'AGAINST',
VALUE => "(". $dbh->quote($value) ." IN BOOLEAN MODE)",
QUOTEVALUE => 0,
);
# As with Oracle, above, this forces the LEFT JOINs into
# JOINS, which allows the FULLTEXT index to be used.
# Orthogonally, the IS NOT NULL clause also helps the
# optimizer decide to use the index.
$self->Limit(
ENTRYAGGREGATOR => 'AND',
FIELD => "Description",
OPERATOR => 'IS NOT',
VALUE => 'NULL',
QUOTEVALUE => 0,
);
}
else {
# SQLite
$self->Limit(
FIELD => $field,
OPERATOR => $op,
VALUE => $value,
CASESENSITIVE => 0,
%rest,
);
}
}

=head2 _QueueLimit
Handle Queue field supporting both "is" and "match".
Expand Down
Loading

0 comments on commit 66d9892

Please sign in to comment.