[Bps-public-commit] rt-extension-rest2 04/07: Add /searches/ and /search/ endpoits for saved searches
sunnavy
sunnavy at bestpractical.com
Wed Jul 14 10:05:51 EDT 2021
This is an automated email from the git hooks/post-receive script.
sunnavy pushed a commit to branch saved-searches
in repository rt-extension-rest2.
commit 39175cafffaa69d2798ea87cd56be9073b73e3e9
Author: sunnavy <sunnavy at bestpractical.com>
AuthorDate: Thu May 27 04:48:20 2021 +0800
Add /searches/ and /search/ endpoits for saved searches
---
lib/RT/Extension/REST2/Resource/Search.pm | 110 ++++++++++++++++++++++++++++
lib/RT/Extension/REST2/Resource/Searches.pm | 93 +++++++++++++++++++++++
2 files changed, 203 insertions(+)
diff --git a/lib/RT/Extension/REST2/Resource/Search.pm b/lib/RT/Extension/REST2/Resource/Search.pm
new file mode 100644
index 0000000..56545f1
--- /dev/null
+++ b/lib/RT/Extension/REST2/Resource/Search.pm
@@ -0,0 +1,110 @@
+package RT::Extension::REST2::Resource::Search;
+use strict;
+use warnings;
+
+use Moose;
+use namespace::autoclean;
+
+extends 'RT::Extension::REST2::Resource::Record';
+with 'RT::Extension::REST2::Resource::Record::Readable',
+ 'RT::Extension::REST2::Resource::Record::Hypermedia' =>
+ { -alias => { _self_link => '_default_self_link', hypermedia_links => '_default_hypermedia_links' } };
+
+sub dispatch_rules {
+ Path::Dispatcher::Rule::Regex->new(
+ regex => qr{^/search/?$},
+ block => sub { { record_class => 'RT::Attribute' } },
+ ),
+ Path::Dispatcher::Rule::Regex->new(
+ regex => qr{^/search/(.+)/?$},
+ block => sub {
+ my ($match, $req) = @_;
+ my $desc = $match->pos(1);
+ my $record = _load_search($req, $desc);
+
+ return { record_class => 'RT::Attribute', record_id => $record ? $record->Id : 0 };
+ },
+ );
+}
+
+sub _self_link {
+ my $self = shift;
+ my $result = $self->_default_self_link(@_);
+
+ $result->{type} = 'search';
+ $result->{_url} =~ s!/attribute/!/search/!;
+ return $result;
+}
+
+sub hypermedia_links {
+ my $self = shift;
+ my $links = $self->_default_hypermedia_links;
+ my $record = $self->record;
+ if ( my $content = $record->Content ) {
+ if ( ( $content->{SearchType} || 'Ticket' ) eq 'Ticket' ) {
+ my $id = $record->Id;
+ push @$links,
+ { _url => RT::Extension::REST2->base_uri . "/tickets?search=$id",
+ type => 'results',
+ ref => 'tickets',
+ };
+ }
+ }
+ return $links;
+}
+
+sub base_uri { join '/', RT::Extension::REST2->base_uri, 'search' }
+
+sub resource_exists {
+ my $self = shift;
+ my $record = $self->record;
+ return $record->Id && $record->Name =~ /^(?:SavedSearch$|Search -)/;
+}
+
+sub forbidden {
+ my $self = shift;
+ return 0 unless $self->resource_exists;
+ my $search = RT::SavedSearch->new( $self->current_user );
+ return $search->LoadById( $self->record->Id ) ? 0 : 1;
+}
+
+sub _load_search {
+ my $req = shift;
+ my $id = shift;
+
+ if ( $id =~ /\D/ ) {
+
+ my $attrs = RT::Attributes->new( $req->env->{"rt.current_user"} );
+
+ $attrs->Limit( FIELD => 'Name', VALUE => 'SavedSearch' );
+ $attrs->Limit( FIELD => 'Name', VALUE => 'Search -', OPERATOR => 'STARTSWITH' );
+ $attrs->Limit( FIELD => 'Description', VALUE => $id );
+
+ my @searches;
+ while ( my $attr = $attrs->Next ) {
+ my $search = RT::SavedSearch->new( $req->env->{"rt.current_user"} );
+ if ( $search->LoadById( $attr->Id ) ) {
+ push @searches, $search;
+ }
+ }
+
+ my $record_id;
+ if (@searches) {
+ if ( @searches > 1 ) {
+ RT->Logger->warning("Found multiple searches with description $id");
+ }
+ return $searches[0];
+ }
+ }
+ else {
+ my $search = RT::SavedSearch->new( $req->env->{"rt.current_user"} );
+ if ( $search->LoadById($id) ) {
+ return $search;
+ }
+ }
+ return;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
diff --git a/lib/RT/Extension/REST2/Resource/Searches.pm b/lib/RT/Extension/REST2/Resource/Searches.pm
new file mode 100644
index 0000000..3e0b7a1
--- /dev/null
+++ b/lib/RT/Extension/REST2/Resource/Searches.pm
@@ -0,0 +1,93 @@
+package RT::Extension::REST2::Resource::Searches;
+use strict;
+use warnings;
+
+use Moose;
+use namespace::autoclean;
+
+extends 'RT::Extension::REST2::Resource::Collection';
+with 'RT::Extension::REST2::Resource::Collection::ProcessPOSTasGET',
+ 'RT::Extension::REST2::Resource::Collection::QueryByJSON';
+
+sub dispatch_rules {
+ Path::Dispatcher::Rule::Regex->new(
+ regex => qr{^/searches/?$},
+ block => sub { { collection_class => 'RT::Attributes' } },
+ )
+}
+
+use Encode qw( decode_utf8 );
+use RT::Extension::REST2::Util qw( error_as_json );
+use RT::Search::Simple;
+
+sub allowed_methods {
+ [ 'GET', 'HEAD', 'POST' ]
+}
+
+sub limit_collection {
+ my $self = shift;
+ my @objects = RT::SavedSearch->new($self->current_user)->ObjectsForLoading;
+ if ( $self->current_user->HasRight( Object => $RT::System, Right => 'ShowSavedSearches' ) ) {
+ push @objects, RT::System->new( $self->current_user );
+ }
+
+ my $query = $self->query;
+ my @fields = $self->searchable_fields;
+ my %searchable = map {; $_ => 1 } @fields;
+
+ my @ids;
+ my @attrs;
+ for my $object (@objects) {
+ my $attrs = $object->Attributes;
+ $attrs->Limit( FIELD => 'Name', VALUE => 'SavedSearch' );
+ push @attrs, $attrs;
+ }
+
+ # Default system searches
+ my $attrs = RT::System->new( $self->current_user )->Attributes;
+ $attrs->Limit( FIELD => 'Name', VALUE => 'Search -', OPERATOR => 'STARTSWITH' );
+ push @attrs, $attrs;
+
+ for my $attrs (@attrs) {
+ for my $limit (@$query) {
+ next
+ unless $limit->{field}
+ and $searchable{ $limit->{field} }
+ and defined $limit->{value};
+
+ $attrs->Limit(
+ FIELD => $limit->{field},
+ VALUE => $limit->{value},
+ ( $limit->{operator} ? ( OPERATOR => $limit->{operator} )
+ : ()
+ ),
+ CASESENSITIVE => ( $limit->{case_sensitive} || 0 ),
+ ( $limit->{entry_aggregator} ? ( ENTRYAGGREGATOR => $limit->{entry_aggregator} )
+ : ()
+ ),
+ );
+ }
+ push @ids, map { $_->Id } @{ $attrs->ItemsArrayRef };
+ }
+
+ while ( @ids > 1000 ) {
+ my @batch = splice( @ids, 0, 1000 );
+ $self->Limit( FIELD => 'id', VALUE => \@ids, OPERATOR => 'IN' );
+ }
+ $self->collection->Limit( FIELD => 'id', VALUE => \@ids, OPERATOR => 'IN' );
+
+ return 1;
+}
+
+sub serialize_record {
+ my $self = shift;
+ my $record = shift;
+ my $result = $self->SUPER::serialize_record($record);
+ $result->{type} = 'search';
+ $result->{_url} =~ s!/attribute/!/search/!;
+ return $result;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
--
To stop receiving notification emails like this one, please contact
sysadmin at bestpractical.com.
More information about the Bps-public-commit
mailing list