From 400eb419bd9dfdf7b18ba75d2c3c210724a5d914 Mon Sep 17 00:00:00 2001 From: Kyle Huckins Date: Tue, 11 Feb 2020 20:08:57 +0000 Subject: [PATCH] lp1849212 Course Browse - Add Course Browse UI - Allow browsing courses by Course Number and Title - Add YAOUS to allow/disallow browsing by Instructor. - Minor code cleanup Signed-off-by: Kyle Huckins Signed-off-by: Jane Sandberg Signed-off-by: Michele Morgan Signed-off-by: Galen Charlton --- .../perlmods/lib/OpenILS/WWW/EGCatLoader.pm | 1 + .../lib/OpenILS/WWW/EGCatLoader/Course.pm | 159 +++++++++++++++++ .../XXXX.schema.course-materials-module.sql | 15 ++ Open-ILS/src/templates/opac/course_browse.tt2 | 161 ++++++++++++++++++ .../parts/course_search/qtype_selector.tt2 | 15 +- 5 files changed, 348 insertions(+), 3 deletions(-) create mode 100644 Open-ILS/src/templates/opac/course_browse.tt2 diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm index c252552045..8479fabfc9 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader.pm @@ -157,6 +157,7 @@ sub load { return $self->load_record if $path =~ m|opac/record/\d|; return $self->load_cnbrowse if $path =~ m|opac/cnbrowse|; return $self->load_browse if $path =~ m|opac/browse|; + return $self->load_course_browse if $path =~ m|opac/course_browse|; return $self->load_course if $path =~ m|opac/course|; return $self->load_mylist_add if $path =~ m|opac/mylist/add|; diff --git a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm index 496c043f3e..42160c16e9 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Course.pm @@ -41,6 +41,165 @@ sub load_course { return Apache2::Const::OK; } +sub load_course_browse { + my $self = shift; + my $cgi = $self->cgi; + my $ctx = $self->ctx; + my $e = $self->editor; + + my $browse_results = []; + + # Are we searching? Cool, let's generate some links + if ($cgi->param('bterm')) { + my $bterm = $cgi->param('bterm'); + my $qtype = $cgi->param('qtype'); + # Search term is optional. If it's empty, start at the + # beginning. Otherwise, center results on a match. + # Regardless, we're listing everything, so retrieve all. + my $results; + my $instructors; + if ($qtype eq 'instructor') { + $instructors = $e->json_query({ + "from" => "acmcu", + "select" => {"acmcu" => [ + 'id', + 'usr', + 'is_public' + ]}, + # TODO: We need to support the chosen library as well... + "where" => {'+acmcu' => 'is_public'} + }); + $results = $e->json_query({ + "from" => "au", + "select" => {"au" => [ + 'id', + 'pref_first_given_name', + 'first_given_name', + 'pref_second_given_name', + 'second_given_name', + 'pref_family_name', + 'family_name' + ]}, + "order_by" => {'au' => ['pref_family_name', 'family_name']}, + "where" => {'-and' => [{ + "id" => { "in" => { + "from" => "acmcu", + "select" => { + "acmcu" => ['usr'] + }, + "where" => {'-and' => [ + {'+acmcu' => 'is_public'}, + {"course" => { "in" =>{ + "from" => "acmc", + "select" => { + "acmc" => ['id'] + }, + "where" => {'-not' => [{'+acmc' => 'is_archived'}]} + }}} + ]} + }} + }]} + }); + } else { + $results = $e->json_query({ + "from" => "acmc", + "select" => {"acmc" => [ + 'id', + 'name', + 'course_number', + 'is_archived', + 'owning_lib' + ]}, + "order_by" => {"acmc" => [$qtype]}, + # TODO: We need to support the chosen library as well... + "where" => {'-not' => {'+acmc' => 'is_archived'}} + }); + } + my $bterm_match = 0; + for my $result(@$results) { + my $value_exists = 0; + my $rqtype = $qtype; + my $entry = { + 'value' => '', + 'results_count' => 0, + 'match' => 0 + }; + + if ($qtype eq 'instructor') { + # Put together the name + my $name_str = ''; + if ($result->{'pref_family_name'}) { + $name_str = $result->{'pref_family_name'} . ", "; + } elsif ($result->{'family_name'}) { + $name_str = $result->{'family_name'} . ", "; + } + + if ($result->{'pref_first_given_name'}) { + $name_str .= $result->{'pref_first_given_name'}; + } elsif ($result->{'first_given_name'}) { + $name_str .= $result->{'first_given_name'}; + } + + if ($result->{'pref_second_given_name'}) { + $name_str .= " " . $result->{'pref_second_given_name'}; + } elsif ($result->{'second_given_name'}) { + $name_str .= " " . $result->{'second_given_name'}; + } + + $result->{$rqtype} = $name_str; + + # Get an accurate count of matching courses + for my $instructor(@$instructors) { + if ($instructor->{'usr'} eq $result->{'id'}) { + $entry->{'results_count'} += 1; + last; + } + } + } else { + $entry->{'results_count'} += 1; + } + + for my $existing_entry(@$browse_results) { + if ($existing_entry->{'value'} eq $result->{$rqtype} && $value_exists eq 0) { + $value_exists = 1; + $existing_entry->{'results_count'} += 1; + last; + } + } + + if ($value_exists eq 0) { + # For Name/Course Number browse queries... + if ($bterm_match eq 0) { + if ($result->{$qtype} =~ m/^$bterm./ || $result->{$qtype} eq $bterm) { + $bterm_match = 1; + $entry->{'match'} = 1; + } + } + $entry->{'value'} = $result->{$rqtype}; + push @$browse_results, $entry; + } + } + # Feels a bit hacky, but we need the index of the matching entry + my $match_idx = 0; + if ($bterm_match) { + for my $i (0..$#$browse_results) { + if ($browse_results->[$i]->{'match'}) { + $match_idx = $i; + last; + } + } + } + + for my $i(0..$#$browse_results) { + $browse_results->[$i]->{'browse_index'} = $i; + } + $ctx->{match_idx} = $match_idx; + $ctx->{browse_results} = $browse_results; + } + + return Apache2::Const::OK; +} + sub load_cresults { my $self = shift; my %args = @_; diff --git a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.course-materials-module.sql b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.course-materials-module.sql index d4e0d52242..b934d09f8c 100644 --- a/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.course-materials-module.sql +++ b/Open-ILS/src/sql/Pg/upgrade/XXXX.schema.course-materials-module.sql @@ -71,6 +71,21 @@ VALUES ( 'coust', 'description' ) +), ( + 'circ', + 'circ.course_materials_browse_by_instructor', 'bool', + oils_i18n_gettext( + 'circ.course_materials_browse_by_instructor', + 'Allow users to browse Courses by Instructor', + 'coust', + 'label' + ), + oils_i18n_gettext( + 'circ.course_materials_browse_by_instructor', + 'If enabled, the Org Unit will allow OPAC users to browse Courses by instructor name.' + 'coust', + 'description' + ) ); COMMIT; diff --git a/Open-ILS/src/templates/opac/course_browse.tt2 b/Open-ILS/src/templates/opac/course_browse.tt2 new file mode 100644 index 0000000000..5caabdc94c --- /dev/null +++ b/Open-ILS/src/templates/opac/course_browse.tt2 @@ -0,0 +1,161 @@ +[%- + + PROCESS "opac/parts/header.tt2"; + PROCESS "opac/parts/misc_util.tt2"; + PROCESS "opac/parts/org_selector.tt2"; + WRAPPER "opac/parts/base.tt2"; + INCLUDE "opac/parts/topnav.tt2"; + + ctx.page_title = l("Browse Courses"); + blimit = CGI.param('blimit') || ctx.opac_hits_per_page || 10; + display_idx = CGI.param('didx') || ctx.match_idx || 0; + + upper_limit = 0; + lower_limit = 0; + depart_list = ['blimit', 'bterm', 'bpivot']; + ctx.metalinks.push(''); +%] + +

[% l('Course Browse') %]

+
+ +
+ +
+
+
+ + + [% BLOCK browse_pager %] + [% + pivot_lower = CGI.param('didx') - blimit; + pivot_higher = CGI.param('didx') + blimit; + IF pivot_lower < 0; + pivot_lower = 0; + END; + IF CGI.param('didx') <= 0; + lower_limit = 1; + ELSE; + lower_limit = 0; + END; + + IF pivot_higher > ctx.browse_results.size; + pivot_higher = ctx.browse_results.size - (blimit + 1); + upper_limit = 1; + ELSE; + upper_limit = 0; + END; + %] + [% IF ctx.browse_results.size >= blimit %] +
+ [% IF lower_limit == 0 %] + ← [%l ('Back') %] + [% END %] + [% IF upper_limit == 0 %] + [%l ('Next') %] → + [% END %] + +
+ [% END %] + [% END %] + + [% PROCESS browse_pager id=0 %] + +
+ [% IF ctx.browse_error %] + + [% l("An error occurred browsing records. " _ + "Please try again in a moment or report the issue " _ + "to library staff.") %] + + [% ELSE %] + [% IF ctx.browse_leading_article_warning %] +
+ [% l("Your browse term seems to begin with an article (a, an, the). You might get better results by omitting the article.") %] + [% IF ctx.browse_leading_article_alternative %] +

[% alternative_link = BLOCK %] + [% ctx.browse_leading_article_alternative | html %] + [%- END; # alternative_link BLOCK + l("Did you mean [_1]?", alternative_link); + END # IF %] +

+
+ [% END # IF browse leading article warning %] + +
    + [% FOR result IN ctx.browse_results %] + [% IF result.browse_index >= CGI.param('didx') && + result.browse_index <= (CGI.param('didx') + blimit - 1) %] +
  • + + [% IF result.results_count > 0 %] + [% result.value | html %] + ([% + IF result.accurate == 'f'; + l("At least"); " "; + END; #result.accurate IF + result.results_count %]) + [% ELSE %] + [% result.value | html %] + [% END; #result.sources IF %] + +
  • + [% END %] + [% END; #result in browse_results %] +
+ [% END; #browse error ELSE %] +
+ + [% PROCESS browse_pager id=1 %] +
+ +
+
+
+ +[% END %] \ No newline at end of file diff --git a/Open-ILS/src/templates/opac/parts/course_search/qtype_selector.tt2 b/Open-ILS/src/templates/opac/parts/course_search/qtype_selector.tt2 index a9770b1fe0..279b1c84ea 100644 --- a/Open-ILS/src/templates/opac/parts/course_search/qtype_selector.tt2 +++ b/Open-ILS/src/templates/opac/parts/course_search/qtype_selector.tt2 @@ -1,8 +1,17 @@ -[% query_types = [ +[% query_types = [ {value => "name", label => l("Title"), plural_label => l("Titles"), browse => 1}, - {value => "instructor", label => l("Instructor"), plural_label => l('Instructors')}, - {value => "course_number", label => l("Course Number")} + {value => "course_number", label => l("Course Number"), plural_label => l('Course Numbers'), browse => 1} ]; + +IF ctx.get_org_setting( + CGI.param('locg'), 'circ.course_materials_browse_by_instructor'); +query_types.push({ + value => "instructor", + label => l("Instructor"), + plural_label => l('Instructors'), + browse => 1}, +); +END; -%]