496c043f3e23527f183076e91928bae5e3a26055
[evergreen-equinox.git] / Open-ILS / src / perlmods / lib / OpenILS / WWW / EGCatLoader / Course.pm
1 package OpenILS::WWW::EGCatLoader;
2 use strict; use warnings;
3 use Apache2::Const -compile => qw(OK DECLINED FORBIDDEN HTTP_GONE HTTP_INTERNAL_SERVER_ERROR REDIRECT HTTP_BAD_REQUEST HTTP_NOT_FOUND);
4 use OpenSRF::Utils::Logger qw/$logger/;
5 use OpenILS::Utils::CStoreEditor qw/:funcs/;
6 use OpenILS::Utils::Fieldmapper;
7 use OpenILS::Application::AppUtils;
8 use Net::HTTP::NB;
9 use IO::Select;
10 my $U = 'OpenILS::Application::AppUtils';
11
12 sub load_course {
13     my $self = shift;
14     my $ctx = $self->ctx;
15
16     $ctx->{page} = 'course';
17     $ctx->{readonly} = $self->cgi->param('readonly');
18
19     my $course_id = $ctx->{page_args}->[0];
20
21     return Apache2::Const::HTTP_BAD_REQUEST
22         unless $course_id and $course_id =~ /^\d+$/;
23
24     $ctx->{course} = $U->simplereq(
25         'open-ils.circ',
26         'open-ils.circ.courses.retrieve',
27         [$course_id]
28     )->[0];
29     
30     $ctx->{instructors} = $U->simplereq(
31         'open-ils.circ',
32         'open-ils.circ.course_users.retrieve',
33         $course_id
34     );
35
36     $ctx->{course_materials} = $U->simplereq(
37         'open-ils.circ',
38         'open-ils.circ.course_materials.retrieve.fleshed',
39         {course => $course_id}
40     );
41     return Apache2::Const::OK;
42 }
43
44 sub load_cresults {
45     my $self = shift;
46     my %args = @_;
47     my $internal = $args{internal};
48     my $cgi = $self->cgi;
49     my $ctx = $self->ctx;
50     my $e = $self->editor;
51     my $limit = 10;
52
53     $ctx->{page} = 'cresult' unless $internal;
54     $ctx->{ids} = [];
55     $ctx->{courses} = [];
56     $ctx->{hit_count} = 0;
57     $ctx->{search_ou} = $self->_get_search_lib();
58     my $page = $cgi->param('page') || 0;
59     my $offset = $page * $limit;
60     my $results;
61     $ctx->{page_size} = $limit;
62     $ctx->{search_page} = $page;
63     $ctx->{pagable_limit} = 50;
64
65     # fetch this page plus the first hit from the next page
66     if ($internal) {
67         $limit = $offset + $limit + 1;
68         $offset = 0;
69     }
70
71     my ($user_query, $query, @queries, $modifiers) = _prepare_course_search($cgi, $ctx);
72
73     return Apache2::Const::OK unless $query;
74
75     $ctx->{user_query} = $user_query;
76     $ctx->{processed_search_query} = $query;
77     my $search_args = {};
78     my $course_numbers = ();
79     
80     my $where_clause;
81     my $and_terms = [];
82     my $or_terms = [];
83
84     # Handle is_archived checkbox and Org Selector
85     my $search_orgs = $U->get_org_descendants($ctx->{search_ou});
86     push @$and_terms, {'owning_lib' => $search_orgs};
87     push @$and_terms, {'-not' => {'+acmc' => 'is_archived'}} unless $query =~ qr\#include_archived\;
88
89     # Now let's push the actual queries
90     for my $query_obj (@queries) {
91         my $type = $query_obj->{'qtype'};
92         my $query = $query_obj->{'value'};
93         my $bool = $query_obj->{'bool'};
94         my $contains = $query_obj->{'contains'};
95         my $operator = ($contains eq 'nocontains') ? '!~*' : '~*';
96         my $search_query;
97         if ($type eq 'instructor') {
98             my $in = ($contains eq 'nocontains') ? "not in" : "in";
99             $search_query = {'id' => {$in => {
100                 'from' => 'acmcu',
101                 'select' => {'acmcu' => ['course']},
102                 'where' => {'usr' => {'in' => {
103                     'from' => 'au',
104                     'select' => {'au' => ['id']},
105                     'where' => {
106                         '-or' => [
107                             {'pref_first_given_name' => {'~*' => $query}},
108                             {'first_given_name' => {'~*' => $query}},
109                             {'pref_second_given_name' => {'~*' => $query}},
110                             {'second_given_name' => {'~*' => $query}},
111                             {'pref_family_name' => {'~*' => $query}},
112                             {'family_name' => {'~*' => $query}}
113                         ]
114                     }
115                 }}}
116             }}};
117         } else {
118             $search_query = ($contains eq 'nocontains') ?
119               {'+acmc' => { $type => {$operator => $query}}} :
120               {$type => {$operator => $query}};
121         }
122
123         if ($bool eq 'or') {
124             push @$or_terms, $search_query;
125         }
126
127         if ($bool eq 'and') {
128             push @$and_terms, $search_query;
129         }
130     }
131
132     if ($or_terms and @$or_terms > 0) {
133         if ($and_terms and @$and_terms > 0) {
134             push @$or_terms, $and_terms;
135         }
136         $where_clause = {'-or' => $or_terms};
137     } else {
138         $where_clause = {'-and' => $and_terms};
139     }
140
141     my $hits = $e->json_query({
142         "from" => "acmc",
143         "select" => {"acmc" => ['id']},
144         "where" => $where_clause
145     });
146
147     my $results = $e->json_query({
148         "from" => "acmc",
149         "select" => {"acmc" => [
150             'id',
151             'name',
152             'course_number',
153             'section_number',
154             'is_archived',
155             'owning_lib'
156         ]},
157         "limit" => $limit,
158         "offset" => $offset,
159         "order_by" => {"acmc" => ['id']},
160         "where" => $where_clause
161     });
162     for my $result (@$results) {
163         push @{$ctx->{courses}}, {
164             id => $result->{id},
165             course_number => $result->{course_number},
166             section_number => $result->{section_number},
167             owning_lib => $result->{owning_lib},
168             name => $result->{name},
169             is_archived => $result->{is_archived},
170             instructors => []
171         }
172     }
173
174     #$ctx->{courses} = $@courses;#[{id=>10, name=>"test", course_number=>"LIT"}];
175     $ctx->{hit_count} = @$hits || 0;
176     #$ctx->{hit_count} = 0;
177     return Apache2::Const::OK;
178 }
179
180 sub _prepare_course_search {
181     my ($cgi, $ctx) = @_;
182
183     my ($user_query, @queries) = _prepare_query($cgi);
184     my $modifiers;
185     $user_query //= '';
186
187     my $query = $user_query;
188     $query .= ' ' . $ctx->{global_search_filter} if $ctx->{global_search_filter};
189
190     foreach ($cgi->param('modifier')) {
191         $query = ('#' . $_ . ' ' . $query) unless $query =~ qr/\#\Q$_/;
192
193     }
194     # filters
195     foreach (grep /^fi:/, $cgi->param) {
196         /:(-?\w+)$/ or next;
197         my $term = join(",", $cgi->param($_));
198         $query .= " $1($term)" if length $term;
199     }
200
201     return () unless $query;
202
203     return ($user_query, $query, @queries);
204 }
205
206 sub _prepare_query {
207     my $cgi = shift;
208
209     return $cgi->param('query') unless $cgi->param('qtype');
210
211     my %parts;
212     my @part_names = qw/qtype contains query bool modifier/;
213     $parts{$_} = [ $cgi->param($_) ] for (@part_names);
214
215     my $full_query = '';
216     my @queries;
217     for (my $i = 0; $i < scalar @{$parts{'qtype'}}; $i++) {
218         my ($qtype, $contains, $query, $bool, $modifier) = map { $parts{$_}->[$i] } @part_names;
219         next unless $query =~ /\S/;
220
221         $contains = "" unless defined $contains;
222
223         push @queries, {
224             contains => $contains,
225             bool => $bool,
226             qtype => $qtype,
227             value => $query
228         };
229
230         $bool = ($bool and $bool eq 'or') ? '||' : '&&';
231
232         $query = "$qtype:$query";
233
234         $full_query = $full_query ? "($full_query $bool $query)" : $query;
235     }
236
237     return ($full_query, @queries);
238 }